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.ModelStore;
|
||||
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.hierachical2.HierarchicalNodeManager;
|
||||
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);
|
||||
|
||||
//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);
|
||||
|
||||
|
||||
@@ -105,9 +105,11 @@ public class RenderGenerationService {
|
||||
|
||||
byte childMask = section.getNonEmptyChildren();
|
||||
section.release();
|
||||
if (mesh != null) {
|
||||
//Time is the time at the start of the update
|
||||
this.resultConsumer.accept(new SectionUpdate(section.key, time, mesh, childMask));
|
||||
}
|
||||
}
|
||||
|
||||
public void enqueueTask(int lvl, int x, int y, int z) {
|
||||
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;
|
||||
|
||||
public class SectionPositionUpdateFilterer {
|
||||
public class SectionUpdateRouter {
|
||||
private static final int SLICES = 1<<2;
|
||||
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.longs.Long2IntOpenHashMap;
|
||||
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.section.AbstractSectionGeometryManager;
|
||||
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 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
|
||||
public class HierarchicalNodeManager {
|
||||
public static final int NODE_MSK = ((1<<24)-1);
|
||||
private static final int NO_NODE = -1;
|
||||
private static final int SENTINAL_TOP_NODE_INFLIGHT = -2;
|
||||
|
||||
private static final int ID_TYPE_MSK = (3<<30);
|
||||
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);
|
||||
|
||||
public final int maxNodeCount;
|
||||
@@ -33,9 +35,9 @@ public class HierarchicalNodeManager {
|
||||
private final ExpandingObjectAllocationList<NodeChildRequest> requests = new ExpandingObjectAllocationList<>(NodeChildRequest[]::new);
|
||||
|
||||
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)) {
|
||||
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");
|
||||
}
|
||||
this.activeSectionMap.defaultReturnValue(NO_NODE);
|
||||
this.updateFilterer = updateFilterer;
|
||||
this.updateRouter = updateRouter;
|
||||
this.maxNodeCount = maxNodeCount;
|
||||
this.nodeData = new NodeStore(maxNodeCount);
|
||||
this.geometryManager = geometryManager;
|
||||
@@ -54,15 +56,13 @@ public class HierarchicalNodeManager {
|
||||
throw new IllegalArgumentException("Position already in node set: " + WorldEngine.pprintPos(position));
|
||||
}
|
||||
this.activeSectionMap.put(position, SENTINAL_TOP_NODE_INFLIGHT);
|
||||
this.updateFilterer.watch(position);
|
||||
this.updateRouter.watch(position);
|
||||
}
|
||||
|
||||
public void removeTopLevelNode(long position) {
|
||||
if (!this.activeSectionMap.containsKey(position)) {
|
||||
throw new IllegalArgumentException("Position not in node set: " + WorldEngine.pprintPos(position));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void processRequestQueue(int count, long ptr) {
|
||||
@@ -73,7 +73,7 @@ public class HierarchicalNodeManager {
|
||||
}
|
||||
|
||||
private void processRequest(int op) {
|
||||
int node = op&NODE_MSK;
|
||||
int node = op& NODE_ID_MSK;
|
||||
if (!this.nodeData.nodeExists(node)) {
|
||||
throw new IllegalStateException("Tried processing a node that doesnt exist: " + node);
|
||||
}
|
||||
@@ -109,12 +109,12 @@ public class HierarchicalNodeManager {
|
||||
long childPos = makeChildPos(pos, i);
|
||||
request.addChildRequirement(i);
|
||||
//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!");
|
||||
}
|
||||
|
||||
//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");
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
//Need to handle cases
|
||||
// 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
|
||||
// new count of children
|
||||
|
||||
//If the sections child existance bits fully empty, then the section should be removed
|
||||
|
||||
|
||||
final long position = update.position();
|
||||
final var geometryData = update.geometry();
|
||||
int nodeId = this.activeSectionMap.get(position);
|
||||
@@ -164,10 +225,13 @@ public class HierarchicalNodeManager {
|
||||
} else {
|
||||
int type = (nodeId & ID_TYPE_MSK);
|
||||
nodeId &= ~ID_TYPE_MSK;
|
||||
if (type == ID_TYPE_LEAF) {
|
||||
this.leafDataUpdate(nodeId, update);
|
||||
if (type == ID_TYPE_REQUEST) {
|
||||
this.requestDataUpdate(nodeId, update);
|
||||
} 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 {
|
||||
throw new IllegalStateException("Should not reach here");
|
||||
}
|
||||
@@ -181,17 +245,33 @@ public class HierarchicalNodeManager {
|
||||
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);
|
||||
//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) {
|
||||
int previousGeometry = this.nodeData.getNodeGeometry(node);
|
||||
int newGeometry = -1;
|
||||
if (previousGeometry != -1) {
|
||||
int newGeometry = EMPTY_GEOMETRY_ID;
|
||||
if (previousGeometry != EMPTY_GEOMETRY_ID) {
|
||||
if (!geometry.isEmpty()) {
|
||||
newGeometry = this.geometryManager.uploadReplaceSection(previousGeometry, geometry);
|
||||
} else {
|
||||
@@ -209,17 +289,13 @@ public class HierarchicalNodeManager {
|
||||
}
|
||||
if (previousGeometry == newGeometry) {
|
||||
return 0;//No change
|
||||
} else if (previousGeometry == -1) {
|
||||
} else if (previousGeometry == EMPTY_GEOMETRY_ID) {
|
||||
return 1;//Became non-empty
|
||||
} else {
|
||||
return 2;//Became empty
|
||||
}
|
||||
}
|
||||
|
||||
private void createSingleNode() {
|
||||
|
||||
}
|
||||
|
||||
private static int getChildIdx(long pos) {
|
||||
int x = WorldEngine.getX(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) {
|
||||
//Compute the mip chain
|
||||
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
|
||||
// TODO: swap to persistent gpu thread instead
|
||||
|
||||
/*
|
||||
if (HACKY_SECTION_COUNT != 0) {
|
||||
long uploadPtr = UploadStream.INSTANCE.upload(this.renderList, 0, HACKY_SECTION_COUNT*4L+4);
|
||||
|
||||
@@ -61,7 +61,6 @@ public class HierarchicalOcclusionTraverser {
|
||||
|
||||
UploadStream.INSTANCE.commit();
|
||||
}
|
||||
*/
|
||||
|
||||
this.downloadResetRequestQueue();
|
||||
}
|
||||
|
||||
@@ -66,4 +66,8 @@ class NodeChildRequest {
|
||||
public boolean isSatisfied() {
|
||||
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;
|
||||
|
||||
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 INCREMENT_SIZE = 1<<16;
|
||||
private final HierarchicalBitSet allocationSet;
|
||||
private long[] localNodeData;
|
||||
public NodeStore(int maxNodeCount) {
|
||||
if (maxNodeCount>=SENTINEL_NULL_NODE_ID) {
|
||||
throw new IllegalArgumentException("Max count too large");
|
||||
}
|
||||
//Initial count is 1024
|
||||
this.localNodeData = new long[INCREMENT_SIZE*LONGS_PER_NODE];
|
||||
this.allocationSet = new HierarchicalBitSet(maxNodeCount);
|
||||
@@ -54,20 +65,28 @@ public final class NodeStore {
|
||||
}
|
||||
|
||||
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)) {
|
||||
throw new IllegalStateException("Node " + nodeId + " was not allocated!");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
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) {
|
||||
this.localNodeData[id2idx(node)] = position;
|
||||
}
|
||||
@@ -81,40 +100,88 @@ public final class NodeStore {
|
||||
}
|
||||
|
||||
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 geometryPtr;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
}
|
||||
|
||||
public void markRequestInFlight(int nodeId) {
|
||||
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
int idx = id2idx(node)+1;
|
||||
long data = this.localNodeData[idx];
|
||||
data &= ~GEOMETRY_ID_MSK;
|
||||
data |= geometryId;
|
||||
this.localNodeData[idx] = data;
|
||||
}
|
||||
|
||||
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 nodePtr;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -5,6 +5,7 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import me.cortex.voxy.client.core.gl.GlBuffer;
|
||||
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.UploadStream;
|
||||
import me.cortex.voxy.common.util.HierarchicalBitSet;
|
||||
@@ -64,6 +65,8 @@ public class BasicSectionGeometryManager extends AbstractSectionGeometryManager
|
||||
|
||||
//Invalidate the section id
|
||||
this.invalidatedSectionIds.add(newId);
|
||||
|
||||
HierarchicalOcclusionTraverser.HACKY_SECTION_COUNT = this.allocationSet.getCount();
|
||||
return newId;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user