Continue work
This commit is contained in:
@@ -3,7 +3,7 @@ package me.cortex.voxy.client.core.rendering;
|
|||||||
import me.cortex.voxy.client.core.model.ModelBakerySubsystem;
|
import me.cortex.voxy.client.core.model.ModelBakerySubsystem;
|
||||||
import me.cortex.voxy.client.core.model.ModelStore;
|
import me.cortex.voxy.client.core.model.ModelStore;
|
||||||
import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
|
import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
|
||||||
import me.cortex.voxy.client.core.rendering.building.SectionPositionUpdateFilterer;
|
import me.cortex.voxy.client.core.rendering.building.SectionUpdateRouter;
|
||||||
import me.cortex.voxy.client.core.rendering.building.SectionUpdate;
|
import me.cortex.voxy.client.core.rendering.building.SectionUpdate;
|
||||||
import me.cortex.voxy.client.core.rendering.hierachical2.HierarchicalNodeManager;
|
import me.cortex.voxy.client.core.rendering.hierachical2.HierarchicalNodeManager;
|
||||||
import me.cortex.voxy.client.core.rendering.hierachical2.HierarchicalOcclusionTraverser;
|
import me.cortex.voxy.client.core.rendering.hierachical2.HierarchicalOcclusionTraverser;
|
||||||
@@ -47,7 +47,7 @@ public class RenderService<T extends AbstractSectionRenderer<J, ?>, J extends Vi
|
|||||||
this.sectionRenderer = (T) createSectionRenderer(this.modelService.getStore(),1<<19, (1L<<30)-1024);
|
this.sectionRenderer = (T) createSectionRenderer(this.modelService.getStore(),1<<19, (1L<<30)-1024);
|
||||||
|
|
||||||
//Do something incredibly hacky, we dont need to keep the reference to this around, so just connect and discard
|
//Do something incredibly hacky, we dont need to keep the reference to this around, so just connect and discard
|
||||||
var positionFilterForwarder = new SectionPositionUpdateFilterer();
|
var positionFilterForwarder = new SectionUpdateRouter();
|
||||||
|
|
||||||
this.nodeManager = new HierarchicalNodeManager(1<<21, this.sectionRenderer.getGeometryManager(), positionFilterForwarder);
|
this.nodeManager = new HierarchicalNodeManager(1<<21, this.sectionRenderer.getGeometryManager(), positionFilterForwarder);
|
||||||
|
|
||||||
|
|||||||
@@ -105,9 +105,11 @@ public class RenderGenerationService {
|
|||||||
|
|
||||||
byte childMask = section.getNonEmptyChildren();
|
byte childMask = section.getNonEmptyChildren();
|
||||||
section.release();
|
section.release();
|
||||||
|
if (mesh != null) {
|
||||||
//Time is the time at the start of the update
|
//Time is the time at the start of the update
|
||||||
this.resultConsumer.accept(new SectionUpdate(section.key, time, mesh, childMask));
|
this.resultConsumer.accept(new SectionUpdate(section.key, time, mesh, childMask));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void enqueueTask(int lvl, int x, int y, int z) {
|
public void enqueueTask(int lvl, int x, int y, int z) {
|
||||||
this.enqueueTask(lvl, x, y, z, (l,x1,y1,z1)->true);
|
this.enqueueTask(lvl, x, y, z, (l,x1,y1,z1)->true);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import me.cortex.voxy.common.world.WorldSection;
|
|||||||
|
|
||||||
import java.util.function.LongConsumer;
|
import java.util.function.LongConsumer;
|
||||||
|
|
||||||
public class SectionPositionUpdateFilterer {
|
public class SectionUpdateRouter {
|
||||||
private static final int SLICES = 1<<2;
|
private static final int SLICES = 1<<2;
|
||||||
public interface IChildUpdate {void accept(WorldSection section);}
|
public interface IChildUpdate {void accept(WorldSection section);}
|
||||||
|
|
||||||
@@ -4,7 +4,7 @@ package me.cortex.voxy.client.core.rendering.hierachical2;
|
|||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||||
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
|
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
|
||||||
import me.cortex.voxy.client.core.rendering.building.SectionPositionUpdateFilterer;
|
import me.cortex.voxy.client.core.rendering.building.SectionUpdateRouter;
|
||||||
import me.cortex.voxy.client.core.rendering.building.SectionUpdate;
|
import me.cortex.voxy.client.core.rendering.building.SectionUpdate;
|
||||||
import me.cortex.voxy.client.core.rendering.section.AbstractSectionGeometryManager;
|
import me.cortex.voxy.client.core.rendering.section.AbstractSectionGeometryManager;
|
||||||
import me.cortex.voxy.client.core.util.ExpandingObjectAllocationList;
|
import me.cortex.voxy.client.core.util.ExpandingObjectAllocationList;
|
||||||
@@ -12,15 +12,17 @@ import me.cortex.voxy.common.world.WorldEngine;
|
|||||||
import me.jellysquid.mods.sodium.client.util.MathUtil;
|
import me.jellysquid.mods.sodium.client.util.MathUtil;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import static me.cortex.voxy.client.core.rendering.hierachical2.NodeStore.EMPTY_GEOMETRY_ID;
|
||||||
|
import static me.cortex.voxy.client.core.rendering.hierachical2.NodeStore.NODE_ID_MSK;
|
||||||
|
|
||||||
//Contains no logic to interface with the gpu, nor does it contain any gpu buffers
|
//Contains no logic to interface with the gpu, nor does it contain any gpu buffers
|
||||||
public class HierarchicalNodeManager {
|
public class HierarchicalNodeManager {
|
||||||
public static final int NODE_MSK = ((1<<24)-1);
|
|
||||||
private static final int NO_NODE = -1;
|
private static final int NO_NODE = -1;
|
||||||
private static final int SENTINAL_TOP_NODE_INFLIGHT = -2;
|
private static final int SENTINAL_TOP_NODE_INFLIGHT = -2;
|
||||||
|
|
||||||
private static final int ID_TYPE_MSK = (3<<30);
|
private static final int ID_TYPE_MSK = (3<<30);
|
||||||
private static final int ID_TYPE_NONE = 0;
|
private static final int ID_TYPE_NONE = 0;
|
||||||
private static final int ID_TYPE_LEAF = (2<<30);
|
private static final int ID_TYPE_REQUEST = (2<<30);
|
||||||
private static final int ID_TYPE_TOP = (1<<30);
|
private static final int ID_TYPE_TOP = (1<<30);
|
||||||
|
|
||||||
public final int maxNodeCount;
|
public final int maxNodeCount;
|
||||||
@@ -33,9 +35,9 @@ public class HierarchicalNodeManager {
|
|||||||
private final ExpandingObjectAllocationList<NodeChildRequest> requests = new ExpandingObjectAllocationList<>(NodeChildRequest[]::new);
|
private final ExpandingObjectAllocationList<NodeChildRequest> requests = new ExpandingObjectAllocationList<>(NodeChildRequest[]::new);
|
||||||
|
|
||||||
private final AbstractSectionGeometryManager geometryManager;
|
private final AbstractSectionGeometryManager geometryManager;
|
||||||
private final SectionPositionUpdateFilterer updateFilterer;
|
private final SectionUpdateRouter updateRouter;
|
||||||
|
|
||||||
public HierarchicalNodeManager(int maxNodeCount, AbstractSectionGeometryManager geometryManager, SectionPositionUpdateFilterer updateFilterer) {
|
public HierarchicalNodeManager(int maxNodeCount, AbstractSectionGeometryManager geometryManager, SectionUpdateRouter updateRouter) {
|
||||||
if (!MathUtil.isPowerOfTwo(maxNodeCount)) {
|
if (!MathUtil.isPowerOfTwo(maxNodeCount)) {
|
||||||
throw new IllegalArgumentException("Max node count must be a power of 2");
|
throw new IllegalArgumentException("Max node count must be a power of 2");
|
||||||
}
|
}
|
||||||
@@ -43,7 +45,7 @@ public class HierarchicalNodeManager {
|
|||||||
throw new IllegalArgumentException("Max node count cannot exceed 2^24");
|
throw new IllegalArgumentException("Max node count cannot exceed 2^24");
|
||||||
}
|
}
|
||||||
this.activeSectionMap.defaultReturnValue(NO_NODE);
|
this.activeSectionMap.defaultReturnValue(NO_NODE);
|
||||||
this.updateFilterer = updateFilterer;
|
this.updateRouter = updateRouter;
|
||||||
this.maxNodeCount = maxNodeCount;
|
this.maxNodeCount = maxNodeCount;
|
||||||
this.nodeData = new NodeStore(maxNodeCount);
|
this.nodeData = new NodeStore(maxNodeCount);
|
||||||
this.geometryManager = geometryManager;
|
this.geometryManager = geometryManager;
|
||||||
@@ -54,15 +56,13 @@ public class HierarchicalNodeManager {
|
|||||||
throw new IllegalArgumentException("Position already in node set: " + WorldEngine.pprintPos(position));
|
throw new IllegalArgumentException("Position already in node set: " + WorldEngine.pprintPos(position));
|
||||||
}
|
}
|
||||||
this.activeSectionMap.put(position, SENTINAL_TOP_NODE_INFLIGHT);
|
this.activeSectionMap.put(position, SENTINAL_TOP_NODE_INFLIGHT);
|
||||||
this.updateFilterer.watch(position);
|
this.updateRouter.watch(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeTopLevelNode(long position) {
|
public void removeTopLevelNode(long position) {
|
||||||
if (!this.activeSectionMap.containsKey(position)) {
|
if (!this.activeSectionMap.containsKey(position)) {
|
||||||
throw new IllegalArgumentException("Position not in node set: " + WorldEngine.pprintPos(position));
|
throw new IllegalArgumentException("Position not in node set: " + WorldEngine.pprintPos(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processRequestQueue(int count, long ptr) {
|
public void processRequestQueue(int count, long ptr) {
|
||||||
@@ -73,7 +73,7 @@ public class HierarchicalNodeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processRequest(int op) {
|
private void processRequest(int op) {
|
||||||
int node = op&NODE_MSK;
|
int node = op& NODE_ID_MSK;
|
||||||
if (!this.nodeData.nodeExists(node)) {
|
if (!this.nodeData.nodeExists(node)) {
|
||||||
throw new IllegalStateException("Tried processing a node that doesnt exist: " + node);
|
throw new IllegalStateException("Tried processing a node that doesnt exist: " + node);
|
||||||
}
|
}
|
||||||
@@ -109,12 +109,12 @@ public class HierarchicalNodeManager {
|
|||||||
long childPos = makeChildPos(pos, i);
|
long childPos = makeChildPos(pos, i);
|
||||||
request.addChildRequirement(i);
|
request.addChildRequirement(i);
|
||||||
//Insert all the children into the tracking map with the node id
|
//Insert all the children into the tracking map with the node id
|
||||||
if (this.activeSectionMap.put(childPos, requestId|ID_TYPE_LEAF) != NO_NODE) {
|
if (this.activeSectionMap.put(childPos, requestId|ID_TYPE_REQUEST) != NO_NODE) {
|
||||||
throw new IllegalStateException("Leaf request creation failed to insert child into map as a mapping already existed for the node!");
|
throw new IllegalStateException("Leaf request creation failed to insert child into map as a mapping already existed for the node!");
|
||||||
}
|
}
|
||||||
|
|
||||||
//Watch and request the child node at the given position
|
//Watch and request the child node at the given position
|
||||||
if (!this.updateFilterer.watch(childPos)) {
|
if (!this.updateRouter.watch(childPos)) {
|
||||||
throw new IllegalStateException("Failed to watch childPos");
|
throw new IllegalStateException("Failed to watch childPos");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,6 +123,64 @@ public class HierarchicalNodeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void removeSectionInternal(long position) {
|
||||||
|
int node = this.activeSectionMap.remove(position);
|
||||||
|
if (node == NO_NODE) {
|
||||||
|
throw new IllegalArgumentException("Tried removing node but it didnt exist: " + WorldEngine.pprintPos(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node == SENTINAL_TOP_NODE_INFLIGHT) {
|
||||||
|
System.err.println("WARN: Removing inflight top level node: " + WorldEngine.pprintPos(position));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
int type = (node & ID_TYPE_MSK);
|
||||||
|
node &= ~ID_TYPE_MSK;
|
||||||
|
if (type == ID_TYPE_REQUEST) {
|
||||||
|
//TODO: THIS
|
||||||
|
|
||||||
|
} else if (type == ID_TYPE_NONE || type == ID_TYPE_TOP) {
|
||||||
|
if (!this.nodeData.nodeExists(node)) {
|
||||||
|
throw new IllegalStateException("Section in active map but not in node data");
|
||||||
|
}
|
||||||
|
if (this.nodeData.isNodeRequestInFlight(node)) {
|
||||||
|
int requestId = this.nodeData.getNodeRequest(node);
|
||||||
|
var request = this.requests.get(requestId);
|
||||||
|
if (request.getPosition() != position) {
|
||||||
|
throw new IllegalStateException("Position != request.position");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Recurse into all child requests and remove them, free any geometry along the way
|
||||||
|
//this.removeSectionInternal(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
//Recurse into all allocated, children and remove
|
||||||
|
int children = this.nodeData.getChildPtr(node);
|
||||||
|
if (children != NO_NODE) {
|
||||||
|
int count = Integer.bitCount(Byte.toUnsignedInt(this.nodeData.getNodeChildExistence(node)));
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
int cid = children + i;
|
||||||
|
if (!this.nodeData.nodeExists(cid)) {
|
||||||
|
throw new IllegalStateException("Child node doesnt exist!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int geometry = this.nodeData.getNodeGeometry(node);
|
||||||
|
if (geometry != EMPTY_GEOMETRY_ID) {
|
||||||
|
this.geometryManager.removeSection(geometry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//After its been removed, if its _not_ a top level node or inflight request but just a normal node,
|
||||||
|
// go up to parent and remove node from the parent allocation and free node id
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: need to add a flag that says should do geometry uploads or something I.E. need to watch geometry
|
||||||
|
// and existance updates seperatly, since cull geometry
|
||||||
public void processResult(SectionUpdate update) {
|
public void processResult(SectionUpdate update) {
|
||||||
//Need to handle cases
|
//Need to handle cases
|
||||||
// geometry update, leaf node, leaf request node, internal node
|
// geometry update, leaf node, leaf request node, internal node
|
||||||
@@ -132,6 +190,9 @@ public class HierarchicalNodeManager {
|
|||||||
// when mesh result, need to remove the old child allocation block and make a new block to fit the
|
// when mesh result, need to remove the old child allocation block and make a new block to fit the
|
||||||
// new count of children
|
// new count of children
|
||||||
|
|
||||||
|
//If the sections child existance bits fully empty, then the section should be removed
|
||||||
|
|
||||||
|
|
||||||
final long position = update.position();
|
final long position = update.position();
|
||||||
final var geometryData = update.geometry();
|
final var geometryData = update.geometry();
|
||||||
int nodeId = this.activeSectionMap.get(position);
|
int nodeId = this.activeSectionMap.get(position);
|
||||||
@@ -164,10 +225,13 @@ public class HierarchicalNodeManager {
|
|||||||
} else {
|
} else {
|
||||||
int type = (nodeId & ID_TYPE_MSK);
|
int type = (nodeId & ID_TYPE_MSK);
|
||||||
nodeId &= ~ID_TYPE_MSK;
|
nodeId &= ~ID_TYPE_MSK;
|
||||||
if (type == ID_TYPE_LEAF) {
|
if (type == ID_TYPE_REQUEST) {
|
||||||
this.leafDataUpdate(nodeId, update);
|
this.requestDataUpdate(nodeId, update);
|
||||||
} else if (type == ID_TYPE_NONE || type == ID_TYPE_TOP) {
|
} else if (type == ID_TYPE_NONE || type == ID_TYPE_TOP) {
|
||||||
//Not part of a request, just a node update
|
//Not part of a request, just a node update,
|
||||||
|
|
||||||
|
//NOTE! be aware that if its an existance update and there is a request attached, need to check if the updated
|
||||||
|
// request becomes finished!!
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Should not reach here");
|
throw new IllegalStateException("Should not reach here");
|
||||||
}
|
}
|
||||||
@@ -181,17 +245,33 @@ public class HierarchicalNodeManager {
|
|||||||
this.nodeData.setNodeChildExistence(node, childExistence);
|
this.nodeData.setNodeChildExistence(node, childExistence);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void leafDataUpdate(int nodeId, SectionUpdate update) {
|
private void requestDataUpdate(int nodeId, SectionUpdate update) {
|
||||||
var request = this.requests.get(nodeId);
|
var request = this.requests.get(nodeId);
|
||||||
|
//Update for section part of a request, the request may be a leaf request update or an inner node update
|
||||||
|
|
||||||
|
|
||||||
|
if (request.isSatisfied()) {
|
||||||
|
this.processFinishedNodeChildRequest(nodeId, request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Process NodeChildRequest results
|
||||||
|
private void processFinishedNodeChildRequest(int parent, NodeChildRequest request) {
|
||||||
|
int children = this.nodeData.getChildPtr(parent);
|
||||||
|
if (children != NO_NODE) {
|
||||||
|
//There are children already part of this node, so need to reallocate all the children
|
||||||
|
int count = Integer.bitCount(Byte.toUnsignedInt(this.nodeData.getNodeChildExistence(parent)));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int updateNodeGeometry(int node, BuiltSection geometry) {
|
private int updateNodeGeometry(int node, BuiltSection geometry) {
|
||||||
int previousGeometry = this.nodeData.getNodeGeometry(node);
|
int previousGeometry = this.nodeData.getNodeGeometry(node);
|
||||||
int newGeometry = -1;
|
int newGeometry = EMPTY_GEOMETRY_ID;
|
||||||
if (previousGeometry != -1) {
|
if (previousGeometry != EMPTY_GEOMETRY_ID) {
|
||||||
if (!geometry.isEmpty()) {
|
if (!geometry.isEmpty()) {
|
||||||
newGeometry = this.geometryManager.uploadReplaceSection(previousGeometry, geometry);
|
newGeometry = this.geometryManager.uploadReplaceSection(previousGeometry, geometry);
|
||||||
} else {
|
} else {
|
||||||
@@ -209,17 +289,13 @@ public class HierarchicalNodeManager {
|
|||||||
}
|
}
|
||||||
if (previousGeometry == newGeometry) {
|
if (previousGeometry == newGeometry) {
|
||||||
return 0;//No change
|
return 0;//No change
|
||||||
} else if (previousGeometry == -1) {
|
} else if (previousGeometry == EMPTY_GEOMETRY_ID) {
|
||||||
return 1;//Became non-empty
|
return 1;//Became non-empty
|
||||||
} else {
|
} else {
|
||||||
return 2;//Became empty
|
return 2;//Became empty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createSingleNode() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getChildIdx(long pos) {
|
private static int getChildIdx(long pos) {
|
||||||
int x = WorldEngine.getX(pos);
|
int x = WorldEngine.getX(pos);
|
||||||
int y = WorldEngine.getY(pos);
|
int y = WorldEngine.getY(pos);
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ public class HierarchicalOcclusionTraverser {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int HACKY_SECTION_COUNT = 0;
|
||||||
public void doTraversal(Viewport<?> viewport, int depthBuffer) {
|
public void doTraversal(Viewport<?> viewport, int depthBuffer) {
|
||||||
//Compute the mip chain
|
//Compute the mip chain
|
||||||
this.hiZBuffer.buildMipChain(depthBuffer, viewport.width, viewport.height);
|
this.hiZBuffer.buildMipChain(depthBuffer, viewport.width, viewport.height);
|
||||||
@@ -50,7 +51,6 @@ public class HierarchicalOcclusionTraverser {
|
|||||||
//Use a chain of glDispatchComputeIndirect (5 times) with alternating read/write buffers
|
//Use a chain of glDispatchComputeIndirect (5 times) with alternating read/write buffers
|
||||||
// TODO: swap to persistent gpu thread instead
|
// TODO: swap to persistent gpu thread instead
|
||||||
|
|
||||||
/*
|
|
||||||
if (HACKY_SECTION_COUNT != 0) {
|
if (HACKY_SECTION_COUNT != 0) {
|
||||||
long uploadPtr = UploadStream.INSTANCE.upload(this.renderList, 0, HACKY_SECTION_COUNT*4L+4);
|
long uploadPtr = UploadStream.INSTANCE.upload(this.renderList, 0, HACKY_SECTION_COUNT*4L+4);
|
||||||
|
|
||||||
@@ -61,7 +61,6 @@ public class HierarchicalOcclusionTraverser {
|
|||||||
|
|
||||||
UploadStream.INSTANCE.commit();
|
UploadStream.INSTANCE.commit();
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
this.downloadResetRequestQueue();
|
this.downloadResetRequestQueue();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,4 +66,8 @@ class NodeChildRequest {
|
|||||||
public boolean isSatisfied() {
|
public boolean isSatisfied() {
|
||||||
return (this.results&this.mask)==this.mask;
|
return (this.results&this.mask)==this.mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getPosition() {
|
||||||
|
return this.nodePos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,22 @@ package me.cortex.voxy.client.core.rendering.hierachical2;
|
|||||||
import me.cortex.voxy.common.util.HierarchicalBitSet;
|
import me.cortex.voxy.common.util.HierarchicalBitSet;
|
||||||
|
|
||||||
public final class NodeStore {
|
public final class NodeStore {
|
||||||
|
public static final int EMPTY_GEOMETRY_ID = -1;
|
||||||
|
public static final int NODE_ID_MSK = ((1<<24)-1);
|
||||||
|
public static final int REQUEST_ID_MSK = ((1<<16)-1);
|
||||||
|
public static final int GEOMETRY_ID_MSK = (1<<24)-1;
|
||||||
|
public static final int MAX_GEOMETRY_ID = GEOMETRY_ID_MSK-1;
|
||||||
|
private static final int SENTINEL_EMPTY_GEOMETRY_ID = GEOMETRY_ID_MSK;
|
||||||
|
private static final int SENTINEL_NULL_NODE_ID = NODE_ID_MSK -1;
|
||||||
|
private static final int SENTINEL_REQUEST_ID = REQUEST_ID_MSK -1;
|
||||||
private static final int LONGS_PER_NODE = 4;
|
private static final int LONGS_PER_NODE = 4;
|
||||||
private static final int INCREMENT_SIZE = 1<<16;
|
private static final int INCREMENT_SIZE = 1<<16;
|
||||||
private final HierarchicalBitSet allocationSet;
|
private final HierarchicalBitSet allocationSet;
|
||||||
private long[] localNodeData;
|
private long[] localNodeData;
|
||||||
public NodeStore(int maxNodeCount) {
|
public NodeStore(int maxNodeCount) {
|
||||||
|
if (maxNodeCount>=SENTINEL_NULL_NODE_ID) {
|
||||||
|
throw new IllegalArgumentException("Max count too large");
|
||||||
|
}
|
||||||
//Initial count is 1024
|
//Initial count is 1024
|
||||||
this.localNodeData = new long[INCREMENT_SIZE*LONGS_PER_NODE];
|
this.localNodeData = new long[INCREMENT_SIZE*LONGS_PER_NODE];
|
||||||
this.allocationSet = new HierarchicalBitSet(maxNodeCount);
|
this.allocationSet = new HierarchicalBitSet(maxNodeCount);
|
||||||
@@ -54,20 +65,28 @@ public final class NodeStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void free(int nodeId) {
|
private void free(int nodeId) {
|
||||||
|
this.free(nodeId, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void free(int baseNodeId, int count) {
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
int nodeId = baseNodeId + i;
|
||||||
if (!this.allocationSet.free(nodeId)) {
|
if (!this.allocationSet.free(nodeId)) {
|
||||||
throw new IllegalStateException("Node " + nodeId + " was not allocated!");
|
throw new IllegalStateException("Node " + nodeId + " was not allocated!");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void clear(int nodeId) {
|
private void clear(int nodeId) {
|
||||||
|
int idx = id2idx(nodeId);
|
||||||
|
this.localNodeData[idx] = -1;//Position
|
||||||
|
this.localNodeData[idx+1] = 0;
|
||||||
|
this.localNodeData[idx+2] = 0;
|
||||||
|
this.localNodeData[idx+3] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void setNodePosition(int node, long position) {
|
public void setNodePosition(int node, long position) {
|
||||||
this.localNodeData[id2idx(node)] = position;
|
this.localNodeData[id2idx(node)] = position;
|
||||||
}
|
}
|
||||||
@@ -81,40 +100,88 @@ public final class NodeStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getNodeGeometry(int node) {
|
public int getNodeGeometry(int node) {
|
||||||
|
long data = this.localNodeData[id2idx(node)+1];
|
||||||
|
int geometryPtr = (int) (data&GEOMETRY_ID_MSK);
|
||||||
|
if (geometryPtr == SENTINEL_EMPTY_GEOMETRY_ID) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
return geometryPtr;
|
||||||
|
}
|
||||||
|
|
||||||
public void setNodeGeometry(int node, int geometryId) {
|
public void setNodeGeometry(int node, int geometryId) {
|
||||||
|
if (geometryId>MAX_GEOMETRY_ID || geometryId<-1) {
|
||||||
|
throw new IllegalArgumentException("Geometry ptr greater than MAX_GEOMETRY_ID or less than -1 : " + geometryId);
|
||||||
|
}
|
||||||
|
if (geometryId == -1) {
|
||||||
|
geometryId = SENTINEL_EMPTY_GEOMETRY_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNodeRequest(int node, int requestId) {
|
int idx = id2idx(node)+1;
|
||||||
|
long data = this.localNodeData[idx];
|
||||||
}
|
data &= ~GEOMETRY_ID_MSK;
|
||||||
|
data |= geometryId;
|
||||||
public void markRequestInFlight(int nodeId) {
|
this.localNodeData[idx] = data;
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNodeRequestInFlight(int nodeId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isLeafNode(int nodeId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getNodeChildExistence(int nodeId) {return 0;}
|
|
||||||
|
|
||||||
public void setNodeChildExistence(int node, byte existence) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getChildPtr(int nodeId) {
|
public int getChildPtr(int nodeId) {
|
||||||
|
long data = this.localNodeData[id2idx(nodeId)+1];
|
||||||
|
int nodePtr = (int) ((data>>24)&NODE_ID_MSK);
|
||||||
|
if (nodePtr == SENTINEL_NULL_NODE_ID) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
return nodePtr;
|
||||||
|
}
|
||||||
|
|
||||||
public void setChildPtr(int nodeId, int ptr) {
|
public void setChildPtr(int nodeId, int ptr) {
|
||||||
|
if (ptr>=NODE_ID_MSK || ptr<-1) {
|
||||||
|
throw new IllegalArgumentException("Node child ptr greater GEQ NODE_ID_MSK or less than -1 : " + ptr);
|
||||||
|
}
|
||||||
|
if (ptr == -1) {
|
||||||
|
ptr = SENTINEL_NULL_NODE_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = id2idx(nodeId)+1;
|
||||||
|
long data = this.localNodeData[idx];
|
||||||
|
data &= ~(((long)NODE_ID_MSK)<<24);
|
||||||
|
data |= ((long)ptr)<<24;
|
||||||
|
this.localNodeData[idx] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNodeRequest(int node, int requestId) {
|
||||||
|
int id = id2idx(node)+2;
|
||||||
|
long data = this.localNodeData[id];
|
||||||
|
data &= ~REQUEST_ID_MSK;
|
||||||
|
data |= requestId;
|
||||||
|
this.localNodeData[id] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNodeRequest(int node) {
|
||||||
|
return (int) (this.localNodeData[id2idx(node)+2]&REQUEST_ID_MSK);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markRequestInFlight(int nodeId) {
|
||||||
|
this.localNodeData[id2idx(nodeId)+1] |= 1L<<63;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNodeRequestInFlight(int nodeId) {
|
||||||
|
return ((this.localNodeData[id2idx(nodeId)+1]>>63)&1)!=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLeafNode(int nodeId) {
|
||||||
|
return ((this.localNodeData[id2idx(nodeId)+1]>>62)&1)!=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getNodeChildExistence(int nodeId) {
|
||||||
|
long data = this.localNodeData[id2idx(nodeId)+1];
|
||||||
|
return (byte) ((data>>48)&0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNodeChildExistence(int nodeId, byte existence) {
|
||||||
|
int idx = id2idx(nodeId)+1;
|
||||||
|
long data = this.localNodeData[idx];
|
||||||
|
data &= ~(0xFFL<<48);
|
||||||
|
data |= Byte.toUnsignedLong(existence)<<48;
|
||||||
|
this.localNodeData[idx] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Writes out a nodes data to the ptr in the compacted/reduced format
|
//Writes out a nodes data to the ptr in the compacted/reduced format
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
|||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
import me.cortex.voxy.client.core.gl.GlBuffer;
|
import me.cortex.voxy.client.core.gl.GlBuffer;
|
||||||
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
|
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
|
||||||
|
import me.cortex.voxy.client.core.rendering.hierachical2.HierarchicalOcclusionTraverser;
|
||||||
import me.cortex.voxy.client.core.rendering.util.BufferArena;
|
import me.cortex.voxy.client.core.rendering.util.BufferArena;
|
||||||
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||||
import me.cortex.voxy.common.util.HierarchicalBitSet;
|
import me.cortex.voxy.common.util.HierarchicalBitSet;
|
||||||
@@ -64,6 +65,8 @@ public class BasicSectionGeometryManager extends AbstractSectionGeometryManager
|
|||||||
|
|
||||||
//Invalidate the section id
|
//Invalidate the section id
|
||||||
this.invalidatedSectionIds.add(newId);
|
this.invalidatedSectionIds.add(newId);
|
||||||
|
|
||||||
|
HierarchicalOcclusionTraverser.HACKY_SECTION_COUNT = this.allocationSet.getCount();
|
||||||
return newId;
|
return newId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user