Continue work on buffer managements
This commit is contained in:
@@ -35,6 +35,10 @@ public class Pos2D {
|
||||
public Pos2D subtract(Pos2D other) {
|
||||
return new Pos2D(x - other.x, y - other.y);
|
||||
}
|
||||
public Pos2D subtract(int v) {
|
||||
return new Pos2D(x - v, y - v);
|
||||
}
|
||||
|
||||
public double dist(Pos2D other) {
|
||||
return Math.sqrt(Math.pow(x - other.x, 2) + Math.pow(y - other.y, 2));
|
||||
}
|
||||
|
||||
@@ -18,27 +18,30 @@ import com.seibel.lod.core.util.gridList.MovableGridRingList;
|
||||
* -by adding data with the lodBuilder
|
||||
*/
|
||||
public abstract class LodQuadTree {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TODO add static configs here
|
||||
* These configs are updated someway
|
||||
* //TODO add static configs here
|
||||
* //These configs are updated someway
|
||||
* Comment: all config value should be via the class that extends this class, and
|
||||
* by implementing different abstract methods - LeeTom
|
||||
*/
|
||||
|
||||
|
||||
public final int maxPossibleDetailLevel;
|
||||
public final int numbersOfDetailLevels;
|
||||
private final MovableGridRingList<LodSection>[] ringLists;
|
||||
|
||||
/**
|
||||
* Constructor of the quadTree
|
||||
* @param viewDistance
|
||||
* @param initialPlayerX
|
||||
* @param initialPlayerZ
|
||||
* @param viewDistance View distance in blocks
|
||||
* @param initialPlayerX player x coordinate
|
||||
* @param initialPlayerZ player z coordinate
|
||||
*/
|
||||
public LodQuadTree(int viewDistance, int initialPlayerX, int initialPlayerZ) {
|
||||
maxPossibleDetailLevel = DetailDistanceUtil.getDetailLevelFromDistance(viewDistance*Math.sqrt(2));
|
||||
ringLists = new MovableGridRingList[maxPossibleDetailLevel];
|
||||
numbersOfDetailLevels = DetailDistanceUtil.getDetailLevelFromDistance(viewDistance*Math.sqrt(2));
|
||||
ringLists = new MovableGridRingList[numbersOfDetailLevels];
|
||||
int size;
|
||||
for (byte detailLevel = 0; detailLevel < maxPossibleDetailLevel; detailLevel++) {
|
||||
for (byte detailLevel = 0; detailLevel < numbersOfDetailLevels; detailLevel++) {
|
||||
double distance = DetailDistanceUtil.getDrawDistanceFromDetail(detailLevel);
|
||||
int sectionCount = LodUtil.ceilDiv((int) Math.ceil(distance),
|
||||
DhSectionPos.getWidth(detailLevel).toBlock()) + 1; // +1 for the border during move
|
||||
@@ -49,19 +52,37 @@ public abstract class LodQuadTree {
|
||||
|
||||
/**
|
||||
* This method return the LodSection given the Section Pos
|
||||
* @param pos
|
||||
* @return
|
||||
* @param pos the section positon
|
||||
* @return the LodSection
|
||||
*/
|
||||
public LodSection getSection(DhSectionPos pos) {
|
||||
return getSection(pos.detail, pos.x, pos.z);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method returns the RingList of a given detail level
|
||||
* @apiNote The returned ringList should not be modified!
|
||||
* @param detailLevel the detail level
|
||||
* @return the RingList
|
||||
*/
|
||||
public MovableGridRingList<LodSection> getRingList(byte detailLevel) {
|
||||
return ringLists[detailLevel];
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the number of detail levels in the quadTree
|
||||
* @return the number of detail levels
|
||||
*/
|
||||
public int getNumbersOfDetailLevels() {
|
||||
return numbersOfDetailLevels;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method return the LodSection at the given detail level and level coordinate x and z
|
||||
* @param detailLevel
|
||||
* @param x
|
||||
* @param z
|
||||
* @return
|
||||
* @param detailLevel detail level of the section
|
||||
* @param x x coordinate of the section
|
||||
* @param z z coordinate of the section
|
||||
* @return the LodSection
|
||||
*/
|
||||
public LodSection getSection(byte detailLevel, int x, int z) {
|
||||
return ringLists[detailLevel].get(x, z);
|
||||
@@ -71,8 +92,8 @@ public abstract class LodQuadTree {
|
||||
|
||||
/**
|
||||
* This method will compute the detail level based on player position and section pos
|
||||
* @param playerPos
|
||||
* @param sectionPos
|
||||
* @param playerPos player position as a reference for calculating the detail level
|
||||
* @param sectionPos section position
|
||||
* @return detail level of this section pos
|
||||
*/
|
||||
public byte calculateExpectedDetailLevel(DhBlockPos2D playerPos, DhSectionPos sectionPos) {
|
||||
@@ -84,7 +105,7 @@ public abstract class LodQuadTree {
|
||||
|
||||
/**
|
||||
* Given a section pos at level n this method returns the parent section at level n+1
|
||||
* @param pos
|
||||
* @param pos the section positon
|
||||
* @return the parent LodSection
|
||||
*/
|
||||
public LodSection getParentSection(DhSectionPos pos) {
|
||||
@@ -106,12 +127,12 @@ public abstract class LodQuadTree {
|
||||
|
||||
/**
|
||||
* This function update the quadTree based on the playerPos and the current game configs (static and global)
|
||||
* @param playerPos
|
||||
* @param playerPos the reference position for the player
|
||||
*/
|
||||
public void tick(DhBlockPos2D playerPos) {
|
||||
for (int detailLevel = 0; detailLevel < maxPossibleDetailLevel; detailLevel++) {
|
||||
for (int detailLevel = 0; detailLevel < numbersOfDetailLevels; detailLevel++) {
|
||||
ringLists[detailLevel].move(playerPos.x >> detailLevel, playerPos.z >> detailLevel,
|
||||
LodSection::immediateDispose);
|
||||
LodSection::dispose);
|
||||
}
|
||||
|
||||
// First tick pass: update all sections' childCount from bottom level to top level. Step:
|
||||
@@ -133,12 +154,12 @@ public abstract class LodQuadTree {
|
||||
// - set childCount to -1 (Signal that this section will be freed if not rescued)
|
||||
// - If targetLevel <= detail && section == null:
|
||||
// - Parent's childCount++ (Create parent if needed)
|
||||
for (byte detailLevel = 0; detailLevel < maxPossibleDetailLevel; detailLevel++) {
|
||||
for (byte detailLevel = 0; detailLevel < numbersOfDetailLevels; detailLevel++) {
|
||||
final MovableGridRingList<LodSection> ringList = ringLists[detailLevel];
|
||||
final MovableGridRingList<LodSection> childRingList =
|
||||
detailLevel == 0 ? null : ringLists[detailLevel - 1];
|
||||
final MovableGridRingList<LodSection> parentRingList =
|
||||
detailLevel == maxPossibleDetailLevel - 1 ? null : ringLists[detailLevel + 1];
|
||||
detailLevel == numbersOfDetailLevels - 1 ? null : ringLists[detailLevel + 1];
|
||||
final byte detail = detailLevel;
|
||||
ringList.forEachPosOrdered((section, pos) -> {
|
||||
if (detail == 0 && section != null) {
|
||||
@@ -150,7 +171,7 @@ public abstract class LodQuadTree {
|
||||
LodSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
if (parent == null) {
|
||||
parent = parentRingList.setChained(pos.x >> 1, pos.y >> 1,
|
||||
new LodSection(section.pos.getParent()));
|
||||
new LodSection(section.pos.getParent(), getRenderDataSource()));
|
||||
parent.childCount++;
|
||||
}
|
||||
LodUtil.assertTrue(parent.childCount <= 4 && parent.childCount > 0);
|
||||
@@ -159,7 +180,7 @@ public abstract class LodQuadTree {
|
||||
LodSection child = ringList.get(childPos.x, childPos.z);
|
||||
if (child == null) {
|
||||
child = ringList.setChained(childPos.x, childPos.z,
|
||||
new LodSection(childPos));
|
||||
new LodSection(childPos, getRenderDataSource()));
|
||||
child.childCount = 0;
|
||||
} else if (child.childCount == -1) {
|
||||
child.childCount = 0;
|
||||
@@ -181,7 +202,7 @@ public abstract class LodQuadTree {
|
||||
LodSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1);
|
||||
if (parent == null) {
|
||||
parent = parentRingList.setChained(pos.x >> 1, pos.y >> 1,
|
||||
new LodSection(sectPos.getParent()));
|
||||
new LodSection(sectPos.getParent(), getRenderDataSource()));
|
||||
}
|
||||
parent.childCount++;
|
||||
}
|
||||
@@ -209,12 +230,12 @@ public abstract class LodQuadTree {
|
||||
// if childCount == -1: // (section can be loaded or unloaded, due to fast movement)
|
||||
// - set this section to null (TODO: Is this needed to be first or last or don't matter for concurrency?)
|
||||
// - If loaded unload section
|
||||
for (byte detailLevel = 0; detailLevel < maxPossibleDetailLevel; detailLevel++) {
|
||||
for (byte detailLevel = 0; detailLevel < numbersOfDetailLevels; detailLevel++) {
|
||||
final MovableGridRingList<LodSection> ringList = ringLists[detailLevel];
|
||||
final MovableGridRingList<LodSection> childRingList =
|
||||
detailLevel == 0 ? null : ringLists[detailLevel - 1];
|
||||
final MovableGridRingList<LodSection> parentRingList =
|
||||
detailLevel == maxPossibleDetailLevel - 1 ? null : ringLists[detailLevel + 1];
|
||||
detailLevel == numbersOfDetailLevels - 1 ? null : ringLists[detailLevel + 1];
|
||||
ringList.forEachPosOrdered((section, pos) -> {
|
||||
LodUtil.assertTrue(section.childCount == 4 || section.childCount == 0 || section.childCount == -1);
|
||||
if (section.childCount == 4) LodUtil.assertTrue(
|
||||
@@ -229,16 +250,12 @@ public abstract class LodQuadTree {
|
||||
getChildSection(section.pos, 3) == null);
|
||||
if (section.childCount == -1) LodUtil.assertTrue(
|
||||
getParentSection(section.pos).childCount == 0);
|
||||
|
||||
if (section.childCount == 4 && section.isLoaded()) {
|
||||
section.load(getRenderDataSource());
|
||||
} else if (section.childCount == 0 && !section.isLoaded()) {
|
||||
section.unload();
|
||||
} else if (section.childCount == 0 && !section.isLoaded()) {
|
||||
section.load();
|
||||
} else if (section.childCount == -1) {
|
||||
ringList.set(pos.x, pos.y, null);
|
||||
if (section.isLoaded()) {
|
||||
section.unload();
|
||||
}
|
||||
section.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -14,43 +14,34 @@ public class LodSection {
|
||||
// (Should always be 4 after tick() is done, or 0 only if this is an unloaded node)
|
||||
public byte childCount = 0;
|
||||
|
||||
|
||||
private RenderDataContainer levelContainer;
|
||||
public RenderContainer renderContainer = null;
|
||||
// TODO: Should I provide a way to change the render source?
|
||||
private RenderContainer renderContainer;
|
||||
|
||||
// Create sub region
|
||||
public LodSection(DhSectionPos pos) {
|
||||
public LodSection(DhSectionPos pos, RenderDataSource renderSource) {
|
||||
this.pos = pos;
|
||||
levelContainer = null;
|
||||
}
|
||||
LodSection(DhSectionPos pos, RenderDataContainer levelContainer) {
|
||||
this.pos = pos;
|
||||
this.levelContainer = levelContainer;
|
||||
this.renderContainer = renderSource.createRenderData(pos);
|
||||
}
|
||||
|
||||
// Return null if data does not exist
|
||||
public boolean load(RenderDataSource renderDataSource) {
|
||||
if (isLoaded()) throw new IllegalStateException("LodSection is already loaded");
|
||||
levelContainer = renderDataSource.createRenderData(pos);
|
||||
return levelContainer != null;
|
||||
public void load() {
|
||||
LodUtil.assertTrue(!isLoaded());
|
||||
renderContainer.load();
|
||||
}
|
||||
public void unload() {
|
||||
if (!isLoaded()) throw new IllegalStateException("LodSection is not loaded");
|
||||
if (renderContainer != null) renderContainer.notifyUnload();
|
||||
levelContainer = null;
|
||||
}
|
||||
public void dispose() {
|
||||
LodUtil.assertTrue(!isLoaded());
|
||||
if (renderContainer != null) renderContainer.notifyDispose();
|
||||
LodUtil.assertTrue(isLoaded());
|
||||
renderContainer.unload();
|
||||
}
|
||||
|
||||
public void immediateDispose() {
|
||||
if (isLoaded()) unload();
|
||||
if (renderContainer != null) renderContainer.notifyDispose();
|
||||
public void dispose() {
|
||||
if (renderContainer != null) renderContainer.dispose();
|
||||
}
|
||||
|
||||
public boolean isLoaded() {
|
||||
return levelContainer != null;
|
||||
return renderContainer != null && renderContainer.isLoaded();
|
||||
}
|
||||
|
||||
public RenderContainer getRenderContainer() {
|
||||
return renderContainer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
package com.seibel.lod.core.objects.a7;
|
||||
|
||||
import com.seibel.lod.core.objects.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.objects.a7.render.RenderContainer;
|
||||
|
||||
public interface RenderDataSource {
|
||||
RenderDataContainer createRenderData(DhSectionPos pos);
|
||||
/**
|
||||
* Returns the render container for the given section.
|
||||
* @param pos The section position.
|
||||
* @return The render container. If there are no data, returns EmptyRenderContainer.
|
||||
*/
|
||||
RenderContainer createRenderData(DhSectionPos pos);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package com.seibel.lod.core.objects.a7.data;
|
||||
|
||||
import com.seibel.lod.core.objects.a7.RenderDataContainer;
|
||||
import com.seibel.lod.core.objects.a7.RenderDataSource;
|
||||
import com.seibel.lod.core.objects.a7.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.objects.a7.render.EmptyRenderContainer;
|
||||
import com.seibel.lod.core.objects.a7.render.RenderContainer;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@@ -14,10 +15,8 @@ public class DataHandler implements RenderDataSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderDataContainer createRenderData(DhSectionPos pos) {
|
||||
|
||||
|
||||
public RenderContainer createRenderData(DhSectionPos pos) {
|
||||
//TODO
|
||||
return null;
|
||||
return EmptyRenderContainer.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import com.seibel.lod.core.objects.opengl.RenderBuffer;
|
||||
import com.seibel.lod.core.objects.opengl.RenderRegion;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class ColumnRenderContainer extends RenderContainer {
|
||||
public static final int columnWidth = DhSectionPos.DATA_WIDTH_PER_SECTION;
|
||||
public static final int columnCount = LodUtil.pow2(DhSectionPos.DATA_WIDTH_PER_SECTION);
|
||||
@@ -21,6 +23,26 @@ public class ColumnRenderContainer extends RenderContainer {
|
||||
renderRegion = new RenderRegion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyRenderable() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyUnrenderable() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRenderable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyLoad() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyUnload() {
|
||||
|
||||
@@ -32,8 +54,7 @@ public class ColumnRenderContainer extends RenderContainer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderRegion getRenderRegion() {
|
||||
return null;
|
||||
public boolean trySwapRenderBuffer(AtomicReference<RenderBuffer> referenceSlot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,32 @@
|
||||
package com.seibel.lod.core.objects.a7.render;
|
||||
|
||||
import com.seibel.lod.core.objects.opengl.RenderBuffer;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class EmptyRenderContainer extends RenderContainer {
|
||||
public static final EmptyRenderContainer INSTANCE = new EmptyRenderContainer();
|
||||
|
||||
@Override
|
||||
public void notifyRenderable() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyUnrenderable() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRenderable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyLoad() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyUnload() {
|
||||
|
||||
@@ -12,7 +38,7 @@ public class EmptyRenderContainer extends RenderContainer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean render() {
|
||||
return true; //Always render successfully since there is nothing to render
|
||||
public boolean trySwapRenderBuffer(AtomicReference<RenderBuffer> referenceSlot) {
|
||||
return false; // no swap
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
package com.seibel.lod.core.objects.a7.render;
|
||||
|
||||
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.render.LodRenderProgram;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.util.gridList.MovableGridRingList;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class RenderBufferHandler {
|
||||
public final LodQuadTree target;
|
||||
private final MovableGridRingList<RenderBufferNode> renderBufferNodes;
|
||||
|
||||
class RenderBufferNode implements AutoCloseable {
|
||||
public final DhSectionPos pos;
|
||||
public volatile RenderBufferNode[] children = null;
|
||||
public AtomicReference<RenderBuffer> renderBufferSlot = null;
|
||||
|
||||
public RenderBufferNode(DhSectionPos pos) {
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
public void render(LodRenderProgram renderContext) {
|
||||
RenderBuffer buff = renderBufferSlot.get();
|
||||
if (buff != null) {
|
||||
buff.render(renderContext);
|
||||
} else {
|
||||
RenderBufferNode[] childs = children;
|
||||
if (childs != null) {
|
||||
for (RenderBufferNode child : childs) {
|
||||
child.render(renderContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: In the future make this logic a bit more complex so that when children are just created,
|
||||
// the buffer is only unloaded if all children's buffers are ready. This will make the
|
||||
// transition between buffers no longer causing any flicker.
|
||||
public void update() {
|
||||
LodSection section = target.getSection(pos);
|
||||
// If this fails, there may be concurrent modification of the quad tree
|
||||
// (as this update() should be called from the same thread that calls update() on the quad tree)
|
||||
LodUtil.assertTrue(section != null);
|
||||
RenderContainer container = section.getRenderContainer();
|
||||
|
||||
// Update self's render buffer state
|
||||
boolean shouldRender = section.isLoaded();
|
||||
if (!shouldRender) {
|
||||
RenderBuffer buff = renderBufferSlot.getAndSet(null);
|
||||
if (buff != null) {
|
||||
buff.close();
|
||||
}
|
||||
} else {
|
||||
container.trySwapRenderBuffer(renderBufferSlot);
|
||||
}
|
||||
|
||||
// Update children's render buffer state
|
||||
boolean shouldHaveChildren = !container.isLoaded();
|
||||
if (shouldHaveChildren) {
|
||||
if (children == null) {
|
||||
RenderBufferNode[] childs = new RenderBufferNode[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
childs[i] = new RenderBufferNode(pos.getChild(i));
|
||||
}
|
||||
children = childs;
|
||||
}
|
||||
for (RenderBufferNode child : children) {
|
||||
child.update();
|
||||
}
|
||||
} else {
|
||||
if (children != null) {
|
||||
RenderBufferNode[] childs = children;
|
||||
children = null;
|
||||
for (RenderBufferNode child : childs) {
|
||||
child.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (children != null) {
|
||||
for (RenderBufferNode child : children) {
|
||||
child.close();
|
||||
}
|
||||
}
|
||||
RenderBuffer buff = renderBufferSlot.getAndSet(null);
|
||||
if (buff != null) {
|
||||
buff.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RenderBufferHandler(LodQuadTree target) {
|
||||
this.target = target;
|
||||
MovableGridRingList<LodSection> referenceList = target.getRingList((byte) (target.getNumbersOfDetailLevels() - 1));
|
||||
Pos2D center = referenceList.getCenter();
|
||||
renderBufferNodes = new MovableGridRingList<>(referenceList.getHalfSize(), center);
|
||||
}
|
||||
|
||||
public void render(LodRenderProgram 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?
|
||||
renderBufferNodes.forEachOrdered(n -> n.render(renderContext));
|
||||
}
|
||||
|
||||
public void update() {
|
||||
byte topDetail = (byte) (target.getNumbersOfDetailLevels() - 1);
|
||||
MovableGridRingList<LodSection> referenceList = target.getRingList(topDetail);
|
||||
Pos2D center = referenceList.getCenter();
|
||||
renderBufferNodes.move(center.x, center.y, RenderBufferNode::close); // Note: may lock the list
|
||||
renderBufferNodes.forEachPosOrdered((node, pos) -> {
|
||||
DhSectionPos sectPos = new DhSectionPos(topDetail, pos.x, pos.y);
|
||||
LodSection section = target.getSection(sectPos);
|
||||
|
||||
if (section == null) {
|
||||
// If section is null, but node exists, remove node
|
||||
if (node != null) {
|
||||
renderBufferNodes.remove(pos).close();
|
||||
}
|
||||
// If section is null, continue
|
||||
return;
|
||||
}
|
||||
|
||||
// If section is not null, but node does not exist, create node
|
||||
if (node == null) {
|
||||
node = renderBufferNodes.setChained(pos, new RenderBufferNode(sectPos));
|
||||
}
|
||||
// Node should be not null here
|
||||
// Update node
|
||||
node.update();
|
||||
});
|
||||
}
|
||||
|
||||
public void close() {
|
||||
renderBufferNodes.clear(RenderBufferNode::close);
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,39 @@ package com.seibel.lod.core.objects.a7.render;
|
||||
import com.seibel.lod.core.objects.opengl.RenderBuffer;
|
||||
import com.seibel.lod.core.objects.opengl.RenderRegion;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public abstract class RenderContainer {
|
||||
|
||||
public abstract void notifyUnload();
|
||||
public abstract void notifyDispose();
|
||||
private boolean isLoaded = false;
|
||||
public final void load() {
|
||||
isLoaded = true;
|
||||
notifyLoad();
|
||||
}
|
||||
public final void unload() {
|
||||
isLoaded = false;
|
||||
notifyUnload();
|
||||
}
|
||||
public final void dispose() {
|
||||
if (isLoaded) {
|
||||
unload();
|
||||
}
|
||||
notifyDispose();
|
||||
}
|
||||
|
||||
public abstract RenderRegion getRenderRegion();
|
||||
public final boolean isLoaded() {
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
protected abstract void notifyLoad(); // notify the container that it is now loaded and therefore may be rendered
|
||||
protected abstract void notifyUnload(); // notify the container that it is now unloaded and therefore will not be rendered
|
||||
protected abstract void notifyDispose(); // notify the container that the parent lodSection is now disposed
|
||||
|
||||
/**
|
||||
* 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 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.
|
||||
*/
|
||||
public abstract boolean trySwapRenderBuffer(AtomicReference<RenderBuffer> referenceSlot);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,8 @@ public class RenderRegion implements AutoCloseable
|
||||
/** stores if the region at the given x and z index needs to be regenerated */
|
||||
// Use int because I need Tri state:
|
||||
private final AtomicInteger needRegen = new AtomicInteger(2);
|
||||
|
||||
|
||||
|
||||
private enum BackState {
|
||||
Unused,
|
||||
Building,
|
||||
|
||||
@@ -41,6 +41,7 @@ public class MovableGridRingList<T> extends ArrayList<T> implements List<T> {
|
||||
private Pos2D[] ringIteratorList = null;
|
||||
|
||||
//TODO: Check if this needs to be synchronized
|
||||
//FIXME: Make all usage of this class do stuff relative to the minPos instead of the center
|
||||
private void buildRingIteratorList() {
|
||||
ringIteratorList = null;
|
||||
Pos2D[] list = new Pos2D[size*size];
|
||||
@@ -67,6 +68,9 @@ public class MovableGridRingList<T> extends ArrayList<T> implements List<T> {
|
||||
pos.set(new Pos2D(centerX-halfSize, centerY-halfSize));
|
||||
clear();
|
||||
}
|
||||
public MovableGridRingList(int halfSize, Pos2D center) {
|
||||
this(halfSize, center.x, center.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
@@ -173,6 +177,23 @@ public class MovableGridRingList<T> extends ArrayList<T> implements List<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public T remove(int x, int y) {
|
||||
return swap(x, y, null);
|
||||
}
|
||||
|
||||
public T get(Pos2D p) {
|
||||
return get(p.x, p.y);
|
||||
}
|
||||
public boolean set(Pos2D p, T t) {
|
||||
return set(p.x, p.y, t);
|
||||
}
|
||||
public T swap(Pos2D p, T t) {
|
||||
return swap(p.x, p.y, t);
|
||||
}
|
||||
public T remove(Pos2D p) {
|
||||
return remove(p.x, p.y);
|
||||
}
|
||||
|
||||
// TODO: Impl this
|
||||
/*
|
||||
// do a compare and set
|
||||
@@ -196,6 +217,9 @@ public class MovableGridRingList<T> extends ArrayList<T> implements List<T> {
|
||||
public T setChained(int x, int y, T t) {
|
||||
return set(x,y,t) ? t : null;
|
||||
}
|
||||
public T setChained(Pos2D p, T t) {
|
||||
return setChained(p.x, p.y, t);
|
||||
}
|
||||
|
||||
// Return false if haven't changed. Return true if it did
|
||||
public boolean move(int newCenterX, int newCenterY) {
|
||||
|
||||
Reference in New Issue
Block a user