Added better chunk meshing
Fixed some collinear vertices not being scanned Added live block mesh updates
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -9,4 +9,5 @@ chunk_models
|
|||||||
chunk_models_new
|
chunk_models_new
|
||||||
chunks_test
|
chunks_test
|
||||||
chunk_models_test
|
chunk_models_test
|
||||||
facets
|
facets
|
||||||
|
polygons
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import java.util.Queue;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -92,7 +93,8 @@ public class Mesh< T extends Region > {
|
|||||||
|
|
||||||
protected MeshState state = MeshState.TRIANGULATION_READY;
|
protected MeshState state = MeshState.TRIANGULATION_READY;
|
||||||
|
|
||||||
protected Collection< MeshEventHandler > handlers = new LinkedHashSet< MeshEventHandler >();
|
protected Collection< MeshChainEventHandler > chainHandlers = new LinkedHashSet< MeshChainEventHandler >();
|
||||||
|
protected Collection< MeshPartitionEventHandler > partitionHandlers = new LinkedHashSet< MeshPartitionEventHandler >();
|
||||||
|
|
||||||
protected boolean mergeChains = true;
|
protected boolean mergeChains = true;
|
||||||
|
|
||||||
@@ -113,7 +115,7 @@ public class Mesh< T extends Region > {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HalfEdge edge = null;
|
HalfEdge edge = null;
|
||||||
for ( Point point : poly.getPoints() ) {
|
for ( final Point point : poly.getPoints() ) {
|
||||||
if ( edge == null ) {
|
if ( edge == null ) {
|
||||||
edge = new HalfEdge();
|
edge = new HalfEdge();
|
||||||
HalfEdge.splice( edge, edge.getSym() );
|
HalfEdge.splice( edge, edge.getSym() );
|
||||||
@@ -138,16 +140,28 @@ public class Mesh< T extends Region > {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addHandler( final MeshEventHandler handler ) {
|
public boolean addPartitionHandler( final MeshPartitionEventHandler handler ) {
|
||||||
return handlers.add( handler );
|
return partitionHandlers.add( handler );
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean removeHandler( final MeshEventHandler handler ) {
|
public boolean removePartitionHandler( final MeshPartitionEventHandler handler ) {
|
||||||
return handlers.remove( handler );
|
return partitionHandlers.remove( handler );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection< MeshEventHandler > getHandlers() {
|
public boolean addChainHandler( final MeshChainEventHandler handler ) {
|
||||||
return Collections.unmodifiableCollection( handlers );
|
return chainHandlers.add( handler );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeChainHandler( final MeshChainEventHandler handler ) {
|
||||||
|
return chainHandlers.remove( handler );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection< MeshChainEventHandler > getChainHandlers() {
|
||||||
|
return Collections.unmodifiableCollection( chainHandlers );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection< MeshPartitionEventHandler > getPartitionHandlers() {
|
||||||
|
return Collections.unmodifiableCollection( partitionHandlers );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set< Point > getVertices() {
|
public Set< Point > getVertices() {
|
||||||
@@ -163,12 +177,35 @@ public class Mesh< T extends Region > {
|
|||||||
return set.parallelStream().map( e -> new Segment( pointMap.get( e.getOrigin() ), pointMap.get( e.getDest() ) ) ).collect( Collectors.toSet() );
|
return set.parallelStream().map( e -> new Segment( pointMap.get( e.getOrigin() ), pointMap.get( e.getDest() ) ) ).collect( Collectors.toSet() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection< Polygon > getPolygons() {
|
||||||
|
if ( state != MeshState.TRIANGULATION_READY ) {
|
||||||
|
throw new IllegalStateException( "Cannot form polygons!" );
|
||||||
|
}
|
||||||
|
|
||||||
|
final Collection< Polygon > polygons = new ArrayDeque< Polygon >();
|
||||||
|
|
||||||
|
final Map< Vertex, Point > pointMap = vertices.parallelStream().collect( Collectors.toMap( Function.identity(), v -> new Point( v.getPosition() ) ) );
|
||||||
|
final Collection< HalfEdge > scanned = new HashSet< HalfEdge >();
|
||||||
|
|
||||||
|
for ( HalfEdge edge : interiorEdges ) {
|
||||||
|
if ( scanned.add( edge ) ) {
|
||||||
|
final List< Point > points = new ArrayList< Point >();
|
||||||
|
do {
|
||||||
|
points.add( pointMap.get( edge.getOrigin() ) );
|
||||||
|
} while ( scanned.add( edge = edge.getNext() ) );
|
||||||
|
polygons.add( new Polygon( points ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return polygons;
|
||||||
|
}
|
||||||
|
|
||||||
public int getVertexCount() {
|
public int getVertexCount() {
|
||||||
return vertices.size();
|
return vertices.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getEdgeCount() {
|
public int getEdgeCount() {
|
||||||
return rules.size();
|
return rules.size() >> 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMergeChains() {
|
public boolean isMergeChains() {
|
||||||
@@ -305,7 +342,8 @@ public class Mesh< T extends Region > {
|
|||||||
vertexSet.parallelStream().forEach( Vertex::update );
|
vertexSet.parallelStream().forEach( Vertex::update );
|
||||||
|
|
||||||
// Do a quick merging of edges so we don't have to deal with them later
|
// Do a quick merging of edges so we don't have to deal with them later
|
||||||
mergeOverlappingEdges( vertexSet );
|
// Not really necessary, but _may_ offer a speedup.
|
||||||
|
// mergeOverlappingEdges( vertexSet );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As we iterate through each vertex, there are certain operations
|
* As we iterate through each vertex, there are certain operations
|
||||||
@@ -320,6 +358,8 @@ public class Mesh< T extends Region > {
|
|||||||
// This set contains the non-redundant vertices.
|
// This set contains the non-redundant vertices.
|
||||||
final Set< Vertex > scannedVertices = new HashSet< Vertex >();
|
final Set< Vertex > scannedVertices = new HashSet< Vertex >();
|
||||||
|
|
||||||
|
// TODO Remove zero edges
|
||||||
|
|
||||||
while ( !vertexSet.isEmpty() ) {
|
while ( !vertexSet.isEmpty() ) {
|
||||||
final Vertex vertex = vertexSet.pollFirst();
|
final Vertex vertex = vertexSet.pollFirst();
|
||||||
final Vector2d pos = vertex.getPosition();
|
final Vector2d pos = vertex.getPosition();
|
||||||
@@ -346,11 +386,11 @@ public class Mesh< T extends Region > {
|
|||||||
it.remove();
|
it.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Remove any zero-edges
|
// Remove any zero-edges
|
||||||
HalfEdge validEdge = null;
|
HalfEdge validEdge = null;
|
||||||
for ( HalfEdge edge : vertex ) {
|
for ( final HalfEdge edge : vertex ) {
|
||||||
if ( edge.isZero() ) {
|
if ( edge.isZero() ) {
|
||||||
// At this point in time, if the edge is zero,
|
// At this point in time, if the edge is zero,
|
||||||
// then the origin and destination must be the same
|
// then the origin and destination must be the same
|
||||||
@@ -537,11 +577,18 @@ public class Mesh< T extends Region > {
|
|||||||
// This assumes that if a and b are collinear, then they _must_ share
|
// This assumes that if a and b are collinear, then they _must_ share
|
||||||
// the same origin, since we are traversing through the vertices
|
// the same origin, since we are traversing through the vertices
|
||||||
// starting with the smallest.
|
// starting with the smallest.
|
||||||
for ( final HalfEdge edge : vertex ) {
|
final Collection< HalfEdge > scanned = new HashSet< HalfEdge >();
|
||||||
|
HalfEdge edge = vertex.getEdge();
|
||||||
|
while ( scanned.add( edge ) ) {
|
||||||
// Only check this edge if it is not already scanned
|
// Only check this edge if it is not already scanned
|
||||||
if ( checked.add( edge ) ) {
|
if ( checked.add( edge ) ) {
|
||||||
final Vector2d r = edge.toVector2d().normalize();
|
final Vector2d r = edge.toVector2d().normalize();
|
||||||
for ( final HalfEdge other : vertex ) {
|
|
||||||
|
// Keep track of which edges we have already looped over during this sub-loop
|
||||||
|
// which we have not checked with the main loop
|
||||||
|
final Collection< HalfEdge > subScanned = new HashSet< HalfEdge >( scanned );
|
||||||
|
HalfEdge other = edge.getPrev();
|
||||||
|
while ( subScanned.add( other ) ) {
|
||||||
if ( !checked.contains( other ) ) {
|
if ( !checked.contains( other ) ) {
|
||||||
// Do not split edges that are pretty much equal, since they will get merged later
|
// Do not split edges that are pretty much equal, since they will get merged later
|
||||||
if ( !isSimilar( edge.getDest(), other.getDest() ) ) {
|
if ( !isSimilar( edge.getDest(), other.getDest() ) ) {
|
||||||
@@ -550,7 +597,6 @@ public class Mesh< T extends Region > {
|
|||||||
|
|
||||||
// Ignore edges that are not collinear
|
// Ignore edges that are not collinear
|
||||||
if ( Math.abs( angle ) <= CROSS_TOLERANCE ) {
|
if ( Math.abs( angle ) <= CROSS_TOLERANCE ) {
|
||||||
|
|
||||||
HalfEdge shorter;
|
HalfEdge shorter;
|
||||||
HalfEdge longer;
|
HalfEdge longer;
|
||||||
|
|
||||||
@@ -563,24 +609,54 @@ public class Mesh< T extends Region > {
|
|||||||
longer = edge;
|
longer = edge;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the winding rule for the split
|
{
|
||||||
final HalfEdge split = longer.split();
|
// Update the winding rule for the split
|
||||||
RegionRule< T > rule = rules.get( longer );
|
final HalfEdge split = longer.split();
|
||||||
rules.put( split, rule );
|
final RegionRule< T > rule = rules.get( longer );
|
||||||
rules.put( split.getSym(), rule.inverse() );
|
rules.put( split, rule );
|
||||||
|
rules.put( split.getSym(), rule.inverse() );
|
||||||
// Update the vertex for the split
|
|
||||||
final Vertex vert = shorter.getDest();
|
// Update the vertex for the split
|
||||||
split.setOrigin( vert );
|
final Vertex vert = shorter.getDest();
|
||||||
longer.getSym().setOrigin( vert );
|
split.setOrigin( vert );
|
||||||
|
longer.getSym().setOrigin( vert );
|
||||||
// Splice the two together
|
vert.setEdge( split );
|
||||||
HalfEdge.splice( shorter.getSym(), split );
|
|
||||||
|
// Splice the two together
|
||||||
|
HalfEdge.splice( shorter.getSym(), split );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now that we've successfully split the shorter and longer edges,
|
||||||
|
* remove the other edge, but keep the current edge that we are
|
||||||
|
* iterating over...
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
// Get and merge the rule
|
||||||
|
RegionRule< T > rule = rules.get( edge );
|
||||||
|
|
||||||
|
rule = rule.apply( rules.remove( other ) );
|
||||||
|
rules.remove( other.getSym() );
|
||||||
|
|
||||||
|
// Now remove the edge
|
||||||
|
HalfEdge.splice( other, other.getSym().getNext() );
|
||||||
|
HalfEdge.splice( other.getSym(), other.getNext() );
|
||||||
|
|
||||||
|
rules.put( edge, rule );
|
||||||
|
rules.put( edge.getSym(), rule.inverse() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
other = edge.getPrev();
|
||||||
|
} else {
|
||||||
|
other = other.getPrev();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
edge = edge.getPrev();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1103,7 +1179,7 @@ public class Mesh< T extends Region > {
|
|||||||
if ( mergeChains ) {
|
if ( mergeChains ) {
|
||||||
final Collection< Link > allChains = findChains( vertices, edges );
|
final Collection< Link > allChains = findChains( vertices, edges );
|
||||||
final Collection< Link > chains = maximizeChains( allChains );
|
final Collection< Link > chains = maximizeChains( allChains );
|
||||||
if ( !handlers.isEmpty() ) {
|
if ( !chainHandlers.isEmpty() ) {
|
||||||
final Collection< Chain > newChains = new HashSet< Chain >();
|
final Collection< Chain > newChains = new HashSet< Chain >();
|
||||||
final Collection< Link > seen = new HashSet< Link >();
|
final Collection< Link > seen = new HashSet< Link >();
|
||||||
|
|
||||||
@@ -1127,7 +1203,7 @@ public class Mesh< T extends Region > {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handlers.forEach( h -> h.onChainGenerationEvent( newChains ) );
|
chainHandlers.forEach( h -> h.onChainGenerationEvent( newChains ) );
|
||||||
|
|
||||||
final Collection< Link > selectedSeen = new HashSet< Link >();
|
final Collection< Link > selectedSeen = new HashSet< Link >();
|
||||||
final Collection< Chain > selectedChains = new HashSet< Chain >();
|
final Collection< Chain > selectedChains = new HashSet< Chain >();
|
||||||
@@ -1151,7 +1227,7 @@ public class Mesh< T extends Region > {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handlers.forEach( h -> h.onPreChainMergeEvent( selectedChains ) );
|
chainHandlers.forEach( h -> h.onPreChainMergeEvent( selectedChains ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
mergeChains( chains, edges );
|
mergeChains( chains, edges );
|
||||||
@@ -1159,7 +1235,7 @@ public class Mesh< T extends Region > {
|
|||||||
|
|
||||||
final Collection< EdgePolygon > polys = partitionMonotone( vertices, edges );
|
final Collection< EdgePolygon > polys = partitionMonotone( vertices, edges );
|
||||||
|
|
||||||
if ( handlers != null ) {
|
if ( partitionHandlers != null ) {
|
||||||
final Collection< Polygon > polygons = new LinkedHashSet< Polygon >();
|
final Collection< Polygon > polygons = new LinkedHashSet< Polygon >();
|
||||||
|
|
||||||
for ( EdgePolygon p : polys ) {
|
for ( EdgePolygon p : polys ) {
|
||||||
@@ -1172,7 +1248,7 @@ public class Mesh< T extends Region > {
|
|||||||
polygons.add( new Polygon( points ) );
|
polygons.add( new Polygon( points ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
handlers.forEach( h -> h.onPartitionEvent( polygons ) );
|
partitionHandlers.forEach( h -> h.onPartitionEvent( polygons ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( mergeChains ) {
|
if ( mergeChains ) {
|
||||||
@@ -2896,7 +2972,7 @@ public class Mesh< T extends Region > {
|
|||||||
|
|
||||||
prev = edge;
|
prev = edge;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The last edge must be a negative edge, since
|
// The last edge must be a negative edge, since
|
||||||
// the last vertex must terminate the polygon and
|
// the last vertex must terminate the polygon and
|
||||||
// therefore have no right-going edges.
|
// therefore have no right-going edges.
|
||||||
@@ -2922,7 +2998,7 @@ public class Mesh< T extends Region > {
|
|||||||
|
|
||||||
polygon.addEdge( newEdge );
|
polygon.addEdge( newEdge );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert each vertex to a point
|
// Convert each vertex to a point
|
||||||
final Map< Vertex, Point > pointMap = polygon.vertices.parallelStream().collect( Collectors.toMap( Function.identity(), v -> new Point( v.getPosition() ) ) );
|
final Map< Vertex, Point > pointMap = polygon.vertices.parallelStream().collect( Collectors.toMap( Function.identity(), v -> new Point( v.getPosition() ) ) );
|
||||||
|
|
||||||
@@ -3076,10 +3152,13 @@ public class Mesh< T extends Region > {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static interface MeshEventHandler {
|
public static interface MeshPartitionEventHandler {
|
||||||
|
default void onPartitionEvent( final Collection< Polygon > polygons ) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface MeshChainEventHandler {
|
||||||
default void onChainGenerationEvent( final Collection< Chain > chains ) {};
|
default void onChainGenerationEvent( final Collection< Chain > chains ) {};
|
||||||
default void onPreChainMergeEvent( final Collection< Chain > chains ) {};
|
default void onPreChainMergeEvent( final Collection< Chain > chains ) {};
|
||||||
default void onPartitionEvent( final Collection< Polygon > polygons ) {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected enum MeshState {
|
protected enum MeshState {
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.aaaaahhhhhhh.bananapuncher714.minietest;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.ChunkLocation;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.ChunkMesh;
|
||||||
|
|
||||||
|
public class ChunkMeshCache {
|
||||||
|
final File directory;
|
||||||
|
Map< ChunkLocation, ChunkMesh > meshes = new TreeMap< ChunkLocation, ChunkMesh >();
|
||||||
|
Collection< ChunkLocation > shouldRemove = new HashSet< ChunkLocation >();
|
||||||
|
ReentrantLock lock = new ReentrantLock();
|
||||||
|
|
||||||
|
public ChunkMeshCache( final File directory ) {
|
||||||
|
this.directory = directory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onChunkLoad( final Chunk chunk ) {
|
||||||
|
final ChunkLocation location = new ChunkLocation( chunk );
|
||||||
|
|
||||||
|
// Unqueue this chunk for removal if it's queued
|
||||||
|
shouldRemove.remove( location );
|
||||||
|
|
||||||
|
// TODO Add a ticket
|
||||||
|
chunk.addPluginChunkTicket( null );
|
||||||
|
|
||||||
|
// Does the mesh map contain the current location?
|
||||||
|
{
|
||||||
|
// If not, then load or mesh the chunk
|
||||||
|
// Emit a chunk mesh complete event
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveAndRemove( final ChunkLocation location ) {
|
||||||
|
lock.lock();
|
||||||
|
meshes.remove( location );
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveAndRemoveAll() {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ import java.io.File;
|
|||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -38,7 +39,8 @@ import org.bukkit.util.Vector;
|
|||||||
|
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Chain;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Chain;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh.MeshEventHandler;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh.MeshChainEventHandler;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh.MeshPartitionEventHandler;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Point;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Point;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Polygon;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Polygon;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Segment;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Segment;
|
||||||
@@ -134,7 +136,7 @@ public class MeshingTest2 extends JPanel {
|
|||||||
|
|
||||||
final List< Plane > masterPlanes = new ArrayList< Plane >();
|
final List< Plane > masterPlanes = new ArrayList< Plane >();
|
||||||
System.out.println( "Adding test plane" );
|
System.out.println( "Adding test plane" );
|
||||||
masterPlanes.add( getTestPlane() );
|
masterPlanes.addAll( getTestPlanes() );
|
||||||
|
|
||||||
System.out.println( "Chunk files: " + CHUNK_DIR.listFiles().length );
|
System.out.println( "Chunk files: " + CHUNK_DIR.listFiles().length );
|
||||||
int limit = 1;
|
int limit = 1;
|
||||||
@@ -279,7 +281,7 @@ public class MeshingTest2 extends JPanel {
|
|||||||
System.out.println( "After generating regions vertex count: " + mesh.getVertices().size() );
|
System.out.println( "After generating regions vertex count: " + mesh.getVertices().size() );
|
||||||
System.out.println( "After generating regions edge count: " + ( mesh.getEdgeCount() / 2 ) );
|
System.out.println( "After generating regions edge count: " + ( mesh.getEdgeCount() / 2 ) );
|
||||||
|
|
||||||
mesh.addHandler( new MeshEventHandler() {
|
mesh.addChainHandler( new MeshChainEventHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onChainGenerationEvent( Collection< Chain > chains ) {
|
public void onChainGenerationEvent( Collection< Chain > chains ) {
|
||||||
data.chains = chains;
|
data.chains = chains;
|
||||||
@@ -310,7 +312,9 @@ public class MeshingTest2 extends JPanel {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
mesh.addPartitionHandler( new MeshPartitionEventHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onPartitionEvent( Collection< Polygon > polygons ) {
|
public void onPartitionEvent( Collection< Polygon > polygons ) {
|
||||||
data.polygons = polygons;
|
data.polygons = polygons;
|
||||||
@@ -391,7 +395,7 @@ public class MeshingTest2 extends JPanel {
|
|||||||
private static PlaneData test() {
|
private static PlaneData test() {
|
||||||
final PlaneData data = new PlaneData();
|
final PlaneData data = new PlaneData();
|
||||||
final Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
|
final Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
|
||||||
mesh.addHandler( new MeshEventHandler() {
|
mesh.addChainHandler( new MeshChainEventHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onChainGenerationEvent( Collection< Chain > chains ) {
|
public void onChainGenerationEvent( Collection< Chain > chains ) {
|
||||||
data.chains = chains;
|
data.chains = chains;
|
||||||
@@ -552,11 +556,13 @@ public class MeshingTest2 extends JPanel {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Plane getTestPlane() {
|
private static Collection< Plane > getTestPlanes() {
|
||||||
final Plane plane = new Plane();
|
final Collection< Plane > planes = new ArrayDeque< Plane >();
|
||||||
|
{
|
||||||
plane.normal = new Vector( 0, 0, 1 );
|
final Plane plane = new Plane();
|
||||||
plane.point = new Vector( 1, 0, 0 );
|
|
||||||
|
plane.normal = new Vector( 0, 0, 1 );
|
||||||
|
plane.point = new Vector( 1, 0, 0 );
|
||||||
|
|
||||||
// plane.polygons.add( new Polygon( Arrays.asList(
|
// plane.polygons.add( new Polygon( Arrays.asList(
|
||||||
// new Point( 1, 0 ),
|
// new Point( 1, 0 ),
|
||||||
@@ -586,62 +592,113 @@ public class MeshingTest2 extends JPanel {
|
|||||||
// new Point( 0, 1 )
|
// new Point( 0, 1 )
|
||||||
// ) ) );
|
// ) ) );
|
||||||
|
|
||||||
plane.polygons.add( new Polygon( Arrays.asList(
|
plane.polygons.add( new Polygon( Arrays.asList(
|
||||||
new Point( -1, -1 ),
|
new Point( -1, -1 ),
|
||||||
new Point( 1, -1 ),
|
new Point( 1, -1 ),
|
||||||
new Point( 1, 1 ),
|
new Point( 1, 1 ),
|
||||||
new Point( -1, 1 )
|
new Point( -1, 1 )
|
||||||
) ) );
|
) ) );
|
||||||
plane.polygons.add( new Polygon( Arrays.asList(
|
plane.polygons.add( new Polygon( Arrays.asList(
|
||||||
new Point( -1, -1 ),
|
new Point( -1, -1 ),
|
||||||
new Point( 1, -1 ),
|
new Point( 1, -1 ),
|
||||||
new Point( 1, 1 ),
|
new Point( 1, 1 ),
|
||||||
new Point( -1, 1 )
|
new Point( -1, 1 )
|
||||||
) ) );
|
) ) );
|
||||||
|
|
||||||
|
plane.polygons.add( new Polygon( Arrays.asList(
|
||||||
|
new Point( -1, -1 ),
|
||||||
|
new Point( 1, -1 ),
|
||||||
|
new Point( 1, 1 ),
|
||||||
|
new Point( -1, 1 )
|
||||||
|
) ) );
|
||||||
|
plane.polygons.add( new Polygon( Arrays.asList(
|
||||||
|
new Point( -1, 1 ),
|
||||||
|
new Point( 1, 1 ),
|
||||||
|
new Point( 1, 3 ),
|
||||||
|
new Point( -1, 3 )
|
||||||
|
) ) );
|
||||||
|
plane.polygons.add( new Polygon( Arrays.asList(
|
||||||
|
new Point( -2, -1 ),
|
||||||
|
new Point( -1, -1 ),
|
||||||
|
new Point( -1, 2 ),
|
||||||
|
new Point( -2, 2 )
|
||||||
|
) ) );
|
||||||
|
plane.polygons.add( new Polygon( Arrays.asList(
|
||||||
|
new Point( -4, -2 ),
|
||||||
|
new Point( -1, -2 ),
|
||||||
|
new Point( -1, 1.5 ),
|
||||||
|
new Point( -4, 1.5 )
|
||||||
|
) ) );
|
||||||
|
plane.polygons.add( new Polygon( Arrays.asList(
|
||||||
|
new Point( -3, 0 ),
|
||||||
|
new Point( 3, 0 ),
|
||||||
|
new Point( -1.5, -3 ),
|
||||||
|
new Point( 0, 1.5 ),
|
||||||
|
new Point( 1.5, -3 )
|
||||||
|
) ) );
|
||||||
|
plane.polygons.add( new Polygon( Arrays.asList(
|
||||||
|
new Point( -1, 0 ),
|
||||||
|
new Point( 0, 1.5 ),
|
||||||
|
new Point( 1, 0 )
|
||||||
|
) ) );
|
||||||
|
plane.polygons.add( new Polygon( Arrays.asList(
|
||||||
|
new Point( 1, 0 ),
|
||||||
|
new Point( 0, -2 ),
|
||||||
|
new Point( -1, 0 )
|
||||||
|
) ) );
|
||||||
|
|
||||||
|
planes.add( plane );
|
||||||
|
}
|
||||||
|
|
||||||
plane.polygons.add( new Polygon( Arrays.asList(
|
{
|
||||||
new Point( -1, -1 ),
|
final Plane plane = new Plane();
|
||||||
new Point( 1, -1 ),
|
|
||||||
new Point( 1, 1 ),
|
plane.normal = new Vector( 0, 0, 1 );
|
||||||
new Point( -1, 1 )
|
plane.point = new Vector( 1, 0, 0 );
|
||||||
) ) );
|
|
||||||
plane.polygons.add( new Polygon( Arrays.asList(
|
plane.polygons.add( new Polygon( Arrays.asList(
|
||||||
new Point( -1, 1 ),
|
new Point( 0, 0 ),
|
||||||
new Point( 1, 1 ),
|
new Point( 3, 0 ),
|
||||||
new Point( 1, 3 ),
|
new Point( 3, 2 ),
|
||||||
new Point( -1, 3 )
|
new Point( 2, 2 ),
|
||||||
) ) );
|
new Point( 2, 1 ),
|
||||||
plane.polygons.add( new Polygon( Arrays.asList(
|
new Point( 1, 1 ),
|
||||||
new Point( -2, -1 ),
|
new Point( 1, 2 ),
|
||||||
new Point( -1, -1 ),
|
new Point( 0, 2 )
|
||||||
new Point( -1, 2 ),
|
) ) );
|
||||||
new Point( -2, 2 )
|
plane.polygons.add( new Polygon( Arrays.asList(
|
||||||
) ) );
|
new Point( 1, 1 ),
|
||||||
plane.polygons.add( new Polygon( Arrays.asList(
|
new Point( 2, 1 ),
|
||||||
new Point( -4, -2 ),
|
new Point( 2, 2 ),
|
||||||
new Point( -1, -2 ),
|
new Point( 1, 2 )
|
||||||
new Point( -1, 1.5 ),
|
) ) );
|
||||||
new Point( -4, 1.5 )
|
|
||||||
) ) );
|
planes.add( plane );
|
||||||
plane.polygons.add( new Polygon( Arrays.asList(
|
}
|
||||||
new Point( -3, 0 ),
|
|
||||||
new Point( 3, 0 ),
|
|
||||||
new Point( -1.5, -3 ),
|
|
||||||
new Point( 0, 1.5 ),
|
|
||||||
new Point( 1.5, -3 )
|
|
||||||
) ) );
|
|
||||||
plane.polygons.add( new Polygon( Arrays.asList(
|
|
||||||
new Point( -1, 0 ),
|
|
||||||
new Point( 0, 1.5 ),
|
|
||||||
new Point( 1, 0 )
|
|
||||||
) ) );
|
|
||||||
plane.polygons.add( new Polygon( Arrays.asList(
|
|
||||||
new Point( 1, 0 ),
|
|
||||||
new Point( 0, -2 ),
|
|
||||||
new Point( -1, 0 )
|
|
||||||
) ) );
|
|
||||||
|
|
||||||
return plane;
|
{
|
||||||
|
final Plane plane = new Plane();
|
||||||
|
|
||||||
|
plane.normal = new Vector( 0, 0, 1 );
|
||||||
|
plane.point = new Vector( 1, 0, 0 );
|
||||||
|
|
||||||
|
plane.polygons.add( new Polygon( Arrays.asList(
|
||||||
|
new Point( 0, 0 ),
|
||||||
|
new Point( 3, 0 ),
|
||||||
|
new Point( 3, 2 ),
|
||||||
|
new Point( 0, 2 )
|
||||||
|
) ) );
|
||||||
|
plane.polygons.add( new Polygon( Arrays.asList(
|
||||||
|
new Point( 1, 1 ),
|
||||||
|
new Point( 2, 1 ),
|
||||||
|
new Point( 2, 2 ),
|
||||||
|
new Point( 1, 2 )
|
||||||
|
) ) );
|
||||||
|
|
||||||
|
planes.add( plane );
|
||||||
|
}
|
||||||
|
|
||||||
|
return planes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List< Facet > generateFacetsFor( AABB box ) {
|
private static List< Facet > generateFacetsFor( AABB box ) {
|
||||||
|
|||||||
@@ -8,7 +8,11 @@ import java.io.IOException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
@@ -27,6 +31,8 @@ public class MeshingTest5 {
|
|||||||
private static final File BASE = new File( System.getProperty( "user.dir" ) );
|
private static final File BASE = new File( System.getProperty( "user.dir" ) );
|
||||||
private static final File FACET_DIR = new File( BASE, "facets" );
|
private static final File FACET_DIR = new File( BASE, "facets" );
|
||||||
|
|
||||||
|
private static Collection< Facet > facets = Collections.synchronizedCollection( new LinkedHashSet< Facet >() );
|
||||||
|
|
||||||
public static void main( String[] args ) {
|
public static void main( String[] args ) {
|
||||||
if ( FACET_DIR.exists() && FACET_DIR.isDirectory() ) {
|
if ( FACET_DIR.exists() && FACET_DIR.isDirectory() ) {
|
||||||
System.out.println( "Found " + FACET_DIR.list().length + " files" );
|
System.out.println( "Found " + FACET_DIR.list().length + " files" );
|
||||||
@@ -100,7 +106,9 @@ public class MeshingTest5 {
|
|||||||
mesh.addPolygon( poly, RegionRuleWinding.CLOCKWISE );
|
mesh.addPolygon( poly, RegionRuleWinding.CLOCKWISE );
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh.meshify();
|
synchronized( facets ) {
|
||||||
|
facets.addAll( plane.convert( mesh.meshify() ) );
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
System.out.println( "No data!" );
|
System.out.println( "No data!" );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ import org.bukkit.util.Vector;
|
|||||||
|
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Chain;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Chain;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh.MeshEventHandler;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh.MeshChainEventHandler;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh.MeshPartitionEventHandler;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Point;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Point;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Polygon;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Polygon;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Segment;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Segment;
|
||||||
@@ -292,7 +293,7 @@ public class MeshingTest6 extends JPanel {
|
|||||||
System.out.println( "After generating regions vertex count: " + mesh.getVertices().size() );
|
System.out.println( "After generating regions vertex count: " + mesh.getVertices().size() );
|
||||||
System.out.println( "After generating regions edge count: " + ( mesh.getEdgeCount() / 2 ) );
|
System.out.println( "After generating regions edge count: " + ( mesh.getEdgeCount() / 2 ) );
|
||||||
|
|
||||||
mesh.addHandler( new MeshEventHandler() {
|
mesh.addChainHandler( new MeshChainEventHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onChainGenerationEvent( Collection< Chain > chains ) {
|
public void onChainGenerationEvent( Collection< Chain > chains ) {
|
||||||
data.chains = chains;
|
data.chains = chains;
|
||||||
@@ -323,13 +324,15 @@ public class MeshingTest6 extends JPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
mesh.addPartitionHandler( new MeshPartitionEventHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onPartitionEvent( Collection< Polygon > polygons ) {
|
public void onPartitionEvent( Collection< Polygon > polygons ) {
|
||||||
data.polygons = polygons;
|
data.polygons = polygons;
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// If the chains are the issue, set this to false and see if it still meshes
|
// If the chains are the issue, set this to false and see if it still meshes
|
||||||
mesh.setMergeChains( true );
|
mesh.setMergeChains( true );
|
||||||
@@ -411,7 +414,7 @@ public class MeshingTest6 extends JPanel {
|
|||||||
private static PlaneData test() {
|
private static PlaneData test() {
|
||||||
final PlaneData data = new PlaneData();
|
final PlaneData data = new PlaneData();
|
||||||
final Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
|
final Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
|
||||||
mesh.addHandler( new MeshEventHandler() {
|
mesh.addChainHandler( new MeshChainEventHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onChainGenerationEvent( Collection< Chain > chains ) {
|
public void onChainGenerationEvent( Collection< Chain > chains ) {
|
||||||
data.chains = chains;
|
data.chains = chains;
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package com.aaaaahhhhhhh.bananapuncher714.minietest;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Point;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Polygon;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionRuleWinding;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionSimple;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionSimple.GluWindingRule;
|
||||||
|
|
||||||
|
public class MeshingTest7 {
|
||||||
|
private static final File BASE = new File( System.getProperty( "user.dir" ) );
|
||||||
|
private static final File POLYGON_DIR = new File( BASE, "polygons" );
|
||||||
|
|
||||||
|
public static void main( String[] args ) {
|
||||||
|
if ( POLYGON_DIR.exists() && POLYGON_DIR.isDirectory() ) {
|
||||||
|
System.out.println( "Found " + POLYGON_DIR.list().length + " files" );
|
||||||
|
|
||||||
|
final long allStart = System.currentTimeMillis();
|
||||||
|
final AtomicInteger index = new AtomicInteger( 0 );
|
||||||
|
final Collection< File > files = Arrays.asList( POLYGON_DIR.listFiles() );
|
||||||
|
files.parallelStream().forEach( f -> {
|
||||||
|
final StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
|
builder.append( "Meshing file: " + f + "\n" );
|
||||||
|
|
||||||
|
final long start = System.currentTimeMillis();
|
||||||
|
final List< Polygon > polygons = mesh( f, builder );
|
||||||
|
|
||||||
|
Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
|
||||||
|
for ( Polygon poly : polygons ) {
|
||||||
|
mesh.addPolygon( poly, RegionRuleWinding.CLOCKWISE );
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh.meshify();
|
||||||
|
|
||||||
|
long time = System.currentTimeMillis() - start;
|
||||||
|
|
||||||
|
builder.append( "\tTook " + time + "ms\n" );
|
||||||
|
builder.append( "\tCompleted " + index.incrementAndGet() + "/" + files.size() );
|
||||||
|
|
||||||
|
System.out.println( builder.toString() );
|
||||||
|
} );
|
||||||
|
System.out.println( "Took a total of " + ( System.currentTimeMillis() - allStart ) + "ms" );
|
||||||
|
} else {
|
||||||
|
System.err.println( "No such directory exists: " + POLYGON_DIR );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List< Polygon > mesh( File file, final StringBuilder stringBuilder ) {
|
||||||
|
// First parse the file to get a list of all polygons
|
||||||
|
final List< Polygon > polys = new ArrayList< Polygon >();
|
||||||
|
try ( BufferedReader reader = new BufferedReader( new FileReader( file ) ) ) {
|
||||||
|
String line;
|
||||||
|
while ( ( line = reader.readLine() ) != null ) {
|
||||||
|
if ( !line.isEmpty() ) {
|
||||||
|
final int pointCount = Integer.parseInt( line );
|
||||||
|
|
||||||
|
List< Point > points = new ArrayList< Point >( pointCount );
|
||||||
|
|
||||||
|
int point = 0;
|
||||||
|
while ( point < pointCount && ( line = reader.readLine() ) != null ) {
|
||||||
|
if ( !line.isEmpty() ) {
|
||||||
|
String[] values2 = line.split( " " );
|
||||||
|
final double px = Double.parseDouble( values2[ 0 ] );
|
||||||
|
final double py = Double.parseDouble( values2[ 1 ] );
|
||||||
|
points.add( new Point( px, py ) );
|
||||||
|
++point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
polys.add( new Polygon( points ) ) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch ( FileNotFoundException e ) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
} catch ( IOException e ) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return polys;
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
|||||||
|
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import org.bukkit.util.BoundingBox;
|
||||||
|
|
||||||
|
public class Aabb implements Serializable {
|
||||||
|
private static final long serialVersionUID = 6518512405568765913L;
|
||||||
|
|
||||||
|
public final int minX;
|
||||||
|
public final int minY;
|
||||||
|
public final int minZ;
|
||||||
|
public final int maxX;
|
||||||
|
public final int maxY;
|
||||||
|
public final int maxZ;
|
||||||
|
|
||||||
|
public final int width;
|
||||||
|
public final int depth;
|
||||||
|
public final int height;
|
||||||
|
|
||||||
|
public Aabb( final BoundingBox box ) {
|
||||||
|
this.minX = ( int ) box.getMinX();
|
||||||
|
this.maxX = ( int ) box.getMaxX();
|
||||||
|
this.minY = ( int ) box.getMinY();
|
||||||
|
this.maxY = ( int ) box.getMaxY();
|
||||||
|
this.minZ = ( int ) box.getMinZ();
|
||||||
|
this.maxZ = ( int ) box.getMaxZ();
|
||||||
|
|
||||||
|
this.width = maxX - minX;
|
||||||
|
this.depth = maxZ - minZ;
|
||||||
|
this.height = maxY - minY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getVolume() {
|
||||||
|
return width * depth * height;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects;
|
||||||
|
|
||||||
|
public enum BlockDataType {
|
||||||
|
NONE, COMPLEX, SOLID
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects;
|
||||||
|
|
||||||
|
import java.util.BitSet;
|
||||||
|
|
||||||
|
public class BlockDataTypeSet {
|
||||||
|
private static final int BLOCK_SIZE;
|
||||||
|
private static final BitSet[] SETS;
|
||||||
|
|
||||||
|
static {
|
||||||
|
final int length = BlockDataType.values().length;
|
||||||
|
BLOCK_SIZE = 32 - Integer.numberOfLeadingZeros( length );
|
||||||
|
SETS = new BitSet[ length ];
|
||||||
|
|
||||||
|
// Perhaps not the fastest, since it sets each bit in N time
|
||||||
|
for ( int i = 0; i < length; ++i ) {
|
||||||
|
final BitSet set = new BitSet();
|
||||||
|
for ( int j = 0; j < BLOCK_SIZE; ++j ) {
|
||||||
|
set.set( j, ( ( i >> j ) & 1 ) == 1 );
|
||||||
|
}
|
||||||
|
SETS[ i ] = set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BitSet buffer;
|
||||||
|
|
||||||
|
public BlockDataTypeSet( final int size ) {
|
||||||
|
buffer = new BitSet( size * BLOCK_SIZE );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set( final int index, final BlockDataType type ) {
|
||||||
|
final BitSet set = SETS[ type.ordinal() ];
|
||||||
|
for ( int i = 0; i < BLOCK_SIZE; ++i ) {
|
||||||
|
buffer.set( ( index * BLOCK_SIZE ) + i, set.get( i ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockDataType get( final int index ) {
|
||||||
|
final int bufferIndex = index * BLOCK_SIZE;
|
||||||
|
int ord = 0;
|
||||||
|
for ( int i = buffer.nextSetBit( bufferIndex ); i >= bufferIndex && i < bufferIndex + BLOCK_SIZE; i = buffer.nextSetBit( i + 1 ) ) {
|
||||||
|
ord |= 1 << ( i - bufferIndex );
|
||||||
|
}
|
||||||
|
return BlockDataType.values()[ ord ];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ import org.bukkit.World;
|
|||||||
*
|
*
|
||||||
* @author BananaPuncher714
|
* @author BananaPuncher714
|
||||||
*/
|
*/
|
||||||
public class ChunkLocation {
|
public class ChunkLocation implements Comparable< ChunkLocation > {
|
||||||
private int x, z;
|
private int x, z;
|
||||||
private String worldName;
|
private String worldName;
|
||||||
private World world;
|
private World world;
|
||||||
@@ -283,4 +283,16 @@ public class ChunkLocation {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "ChunkLocation{x:" + x + ",z:" + z + ",world:" + worldName + "}";
|
return "ChunkLocation{x:" + x + ",z:" + z + ",world:" + worldName + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo( ChunkLocation o ) {
|
||||||
|
final int worldCompare = worldName.compareTo( o.worldName );
|
||||||
|
if ( worldCompare == 0 ) {
|
||||||
|
if ( x == o.x ) {
|
||||||
|
return Integer.compare( z, o.z );
|
||||||
|
}
|
||||||
|
return Integer.compare( x, o.x );
|
||||||
|
}
|
||||||
|
return worldCompare;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.util.BoundingBox;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import com.jme3.bullet.collision.shapes.infos.IndexedMesh;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
|
||||||
|
public class ChunkMesh {
|
||||||
|
// TODO Public for now while I figure out how to organize the stuff properly
|
||||||
|
private int[] data;
|
||||||
|
private BoundingBox[][] boxes;
|
||||||
|
private BlockDataTypeSet blockTypes;
|
||||||
|
public TreeSet< VectorReference > pointReferences = new TreeSet< VectorReference >();
|
||||||
|
public Map< MinecraftPlane, PlaneMesh > planes = new TreeMap< MinecraftPlane, PlaneMesh >();
|
||||||
|
private Aabb box;
|
||||||
|
|
||||||
|
public ChunkMesh( BoundingBox box ) {
|
||||||
|
this.box = new Aabb( box );
|
||||||
|
|
||||||
|
final int volume = this.box.getVolume();
|
||||||
|
data = new int[ volume ];
|
||||||
|
boxes = new BoundingBox[ volume ][];
|
||||||
|
blockTypes = new BlockDataTypeSet( volume );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType( final int index, final BlockDataType type ) {
|
||||||
|
blockTypes.set( index, type );
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockDataType getType( final int index ) {
|
||||||
|
return blockTypes.get( index );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData( final int index, final BlockData data ) {
|
||||||
|
this.data[ index ] = data.getAsString().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBoxes( final int index, final BoundingBox[] boxes ) {
|
||||||
|
this.boxes[ index ] = boxes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBlockAt( final int index, final BlockData data ) {
|
||||||
|
return blockTypes.get( index ) == BlockDataType.COMPLEX && this.data[ index ] == data.getAsString().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoundingBox[] getBoxesAt( final int index ) {
|
||||||
|
return boxes[ index ];
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlaneMesh getOrAdd( final MinecraftPlane plane ) {
|
||||||
|
PlaneMesh results = planes.get( plane );
|
||||||
|
if ( results == null ) {
|
||||||
|
results = new PlaneMesh();
|
||||||
|
planes.put( plane, results );
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IndexedMesh toIndexedMesh() {
|
||||||
|
final Vector3f[] positionArray = new Vector3f[ pointReferences.size() ];
|
||||||
|
int vertexIndex = 0;
|
||||||
|
for ( final VectorReference ref : pointReferences ) {
|
||||||
|
final Vector vector = ref.vector;
|
||||||
|
|
||||||
|
positionArray[ vertexIndex ] = new Vector3f( ( float ) vector.getX(), ( float ) vector.getY(), ( float ) vector.getZ() );
|
||||||
|
ref.index = vertexIndex;
|
||||||
|
|
||||||
|
++vertexIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int totalTriangleCount = planes.values().stream().mapToInt( m -> m.completedPolygons.size() ).sum();
|
||||||
|
|
||||||
|
int triangleIndex = 0;
|
||||||
|
final int[] indexArray = new int[ totalTriangleCount * 3 ];
|
||||||
|
for ( final PlaneMesh mesh : planes.values() ) {
|
||||||
|
for ( final IndexedPolygon triangle : mesh.completedPolygons ) {
|
||||||
|
if ( triangle.points.size() != 3 ) {
|
||||||
|
throw new IllegalStateException( "Triangle does not have exactly 3 vertices!" );
|
||||||
|
}
|
||||||
|
|
||||||
|
final int indexArrayStart = triangleIndex * 3;
|
||||||
|
indexArray[ indexArrayStart ] = triangle.points.get( 0 ).index;
|
||||||
|
indexArray[ indexArrayStart + 1 ] = triangle.points.get( 1 ).index;
|
||||||
|
indexArray[ indexArrayStart + 2 ] = triangle.points.get( 2 ).index;
|
||||||
|
|
||||||
|
++triangleIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new IndexedMesh( positionArray, indexArray );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
public class Component {
|
|
||||||
|
|
||||||
|
|
||||||
public Collection< Component > getComponents() {
|
|
||||||
return Collections.emptySet();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class IndexedPolygon {
|
||||||
|
public List< VectorReference > points = new ArrayList< VectorReference >();
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Point;
|
||||||
|
|
||||||
|
public class MinecraftPlane implements Comparable< MinecraftPlane > {
|
||||||
|
public final PlaneAxis normal;
|
||||||
|
public final double offset;
|
||||||
|
|
||||||
|
public MinecraftPlane( final PlaneAxis axis, final double offset ) {
|
||||||
|
this.normal = axis;
|
||||||
|
this.offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector convert( final Point point ) {
|
||||||
|
switch ( normal ) {
|
||||||
|
case X:
|
||||||
|
return new Vector( offset, point.getX(), point.getY() );
|
||||||
|
case Y:
|
||||||
|
return new Vector( point.getX(), offset, point.getY() );
|
||||||
|
case Z:
|
||||||
|
return new Vector( point.getX(), point.getY(), offset );
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException( "No normal set!" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo( final MinecraftPlane o ) {
|
||||||
|
if ( normal == o.normal ) {
|
||||||
|
return Double.compare( offset, o.offset );
|
||||||
|
}
|
||||||
|
return normal.compareTo( o.normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((normal == null) ? 0 : normal.hashCode());
|
||||||
|
long temp;
|
||||||
|
temp = Double.doubleToLongBits(offset);
|
||||||
|
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
MinecraftPlane other = (MinecraftPlane) obj;
|
||||||
|
if (normal != other.normal)
|
||||||
|
return false;
|
||||||
|
if (Double.doubleToLongBits(offset) != Double.doubleToLongBits(other.offset))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "MinecraftPlane{axis=" + normal + ",offset=" + offset + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static enum PlaneAxis {
|
||||||
|
X, Y, Z
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.Polygon;
|
||||||
|
|
||||||
|
public class PlaneMesh {
|
||||||
|
public Collection< Polygon > generatedRegions;
|
||||||
|
public Collection< IndexedPolygon > completedPolygons;
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects;
|
||||||
|
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
public class VectorReference implements Comparable< VectorReference > {
|
||||||
|
public Vector vector;
|
||||||
|
public int referenceCount = 0;
|
||||||
|
public int index = 0;
|
||||||
|
|
||||||
|
public VectorReference( final Vector vector ) {
|
||||||
|
this.vector = vector;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo( final VectorReference o ) {
|
||||||
|
final Vector oVec = o.vector;
|
||||||
|
|
||||||
|
if ( vector.getX() == oVec.getX() ) {
|
||||||
|
if ( vector.getY() == oVec.getY() ) {
|
||||||
|
if ( vector.getZ() == oVec.getZ() ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Double.compare( vector.getZ(), oVec.getZ() );
|
||||||
|
}
|
||||||
|
return Double.compare( vector.getY(), oVec.getY() );
|
||||||
|
}
|
||||||
|
return Double.compare( vector.getX(), oVec.getX() );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.aaaaahhhhhhh.bananapuncher714.minietest.util;
|
||||||
|
|
||||||
|
public class ChunkMeshUtil {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -105,7 +105,7 @@ public final class FileUtil {
|
|||||||
file.delete();
|
file.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static < T extends Serializable > T readObject( Class< T > clazz, File file ) throws IOException, ClassNotFoundException {
|
public static < T extends Serializable > T readObject( File file ) throws IOException, ClassNotFoundException {
|
||||||
if ( !file.exists() ) {
|
if ( !file.exists() ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user