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
|
||||
chunks_test
|
||||
chunk_models_test
|
||||
facets
|
||||
facets
|
||||
polygons
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.TreeSet;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -92,7 +93,8 @@ public class Mesh< T extends Region > {
|
||||
|
||||
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;
|
||||
|
||||
@@ -113,7 +115,7 @@ public class Mesh< T extends Region > {
|
||||
}
|
||||
|
||||
HalfEdge edge = null;
|
||||
for ( Point point : poly.getPoints() ) {
|
||||
for ( final Point point : poly.getPoints() ) {
|
||||
if ( edge == null ) {
|
||||
edge = new HalfEdge();
|
||||
HalfEdge.splice( edge, edge.getSym() );
|
||||
@@ -138,16 +140,28 @@ public class Mesh< T extends Region > {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean addHandler( final MeshEventHandler handler ) {
|
||||
return handlers.add( handler );
|
||||
public boolean addPartitionHandler( final MeshPartitionEventHandler handler ) {
|
||||
return partitionHandlers.add( handler );
|
||||
}
|
||||
|
||||
public boolean removeHandler( final MeshEventHandler handler ) {
|
||||
return handlers.remove( handler );
|
||||
public boolean removePartitionHandler( final MeshPartitionEventHandler handler ) {
|
||||
return partitionHandlers.remove( handler );
|
||||
}
|
||||
|
||||
public Collection< MeshEventHandler > getHandlers() {
|
||||
return Collections.unmodifiableCollection( handlers );
|
||||
public boolean addChainHandler( final MeshChainEventHandler handler ) {
|
||||
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() {
|
||||
@@ -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() );
|
||||
}
|
||||
|
||||
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() {
|
||||
return vertices.size();
|
||||
}
|
||||
|
||||
public int getEdgeCount() {
|
||||
return rules.size();
|
||||
return rules.size() >> 1;
|
||||
}
|
||||
|
||||
public boolean isMergeChains() {
|
||||
@@ -305,7 +342,8 @@ public class Mesh< T extends Region > {
|
||||
vertexSet.parallelStream().forEach( Vertex::update );
|
||||
|
||||
// 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
|
||||
@@ -320,6 +358,8 @@ public class Mesh< T extends Region > {
|
||||
// This set contains the non-redundant vertices.
|
||||
final Set< Vertex > scannedVertices = new HashSet< Vertex >();
|
||||
|
||||
// TODO Remove zero edges
|
||||
|
||||
while ( !vertexSet.isEmpty() ) {
|
||||
final Vertex vertex = vertexSet.pollFirst();
|
||||
final Vector2d pos = vertex.getPosition();
|
||||
@@ -346,11 +386,11 @@ public class Mesh< T extends Region > {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Remove any zero-edges
|
||||
HalfEdge validEdge = null;
|
||||
for ( HalfEdge edge : vertex ) {
|
||||
for ( final HalfEdge edge : vertex ) {
|
||||
if ( edge.isZero() ) {
|
||||
// At this point in time, if the edge is zero,
|
||||
// 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
|
||||
// the same origin, since we are traversing through the vertices
|
||||
// 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
|
||||
if ( checked.add( edge ) ) {
|
||||
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 ) ) {
|
||||
// Do not split edges that are pretty much equal, since they will get merged later
|
||||
if ( !isSimilar( edge.getDest(), other.getDest() ) ) {
|
||||
@@ -550,7 +597,6 @@ public class Mesh< T extends Region > {
|
||||
|
||||
// Ignore edges that are not collinear
|
||||
if ( Math.abs( angle ) <= CROSS_TOLERANCE ) {
|
||||
|
||||
HalfEdge shorter;
|
||||
HalfEdge longer;
|
||||
|
||||
@@ -563,24 +609,54 @@ public class Mesh< T extends Region > {
|
||||
longer = edge;
|
||||
}
|
||||
|
||||
// Update the winding rule for the split
|
||||
final HalfEdge split = longer.split();
|
||||
RegionRule< T > rule = rules.get( longer );
|
||||
rules.put( split, rule );
|
||||
rules.put( split.getSym(), rule.inverse() );
|
||||
|
||||
// Update the vertex for the split
|
||||
final Vertex vert = shorter.getDest();
|
||||
split.setOrigin( vert );
|
||||
longer.getSym().setOrigin( vert );
|
||||
|
||||
// Splice the two together
|
||||
HalfEdge.splice( shorter.getSym(), split );
|
||||
{
|
||||
// Update the winding rule for the split
|
||||
final HalfEdge split = longer.split();
|
||||
final RegionRule< T > rule = rules.get( longer );
|
||||
rules.put( split, rule );
|
||||
rules.put( split.getSym(), rule.inverse() );
|
||||
|
||||
// Update the vertex for the split
|
||||
final Vertex vert = shorter.getDest();
|
||||
split.setOrigin( vert );
|
||||
longer.getSym().setOrigin( vert );
|
||||
vert.setEdge( 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 ) {
|
||||
final Collection< Link > allChains = findChains( vertices, edges );
|
||||
final Collection< Link > chains = maximizeChains( allChains );
|
||||
if ( !handlers.isEmpty() ) {
|
||||
if ( !chainHandlers.isEmpty() ) {
|
||||
final Collection< Chain > newChains = new HashSet< Chain >();
|
||||
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< 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 );
|
||||
@@ -1159,7 +1235,7 @@ public class Mesh< T extends Region > {
|
||||
|
||||
final Collection< EdgePolygon > polys = partitionMonotone( vertices, edges );
|
||||
|
||||
if ( handlers != null ) {
|
||||
if ( partitionHandlers != null ) {
|
||||
final Collection< Polygon > polygons = new LinkedHashSet< Polygon >();
|
||||
|
||||
for ( EdgePolygon p : polys ) {
|
||||
@@ -1172,7 +1248,7 @@ public class Mesh< T extends Region > {
|
||||
polygons.add( new Polygon( points ) );
|
||||
}
|
||||
|
||||
handlers.forEach( h -> h.onPartitionEvent( polygons ) );
|
||||
partitionHandlers.forEach( h -> h.onPartitionEvent( polygons ) );
|
||||
}
|
||||
|
||||
if ( mergeChains ) {
|
||||
@@ -2896,7 +2972,7 @@ public class Mesh< T extends Region > {
|
||||
|
||||
prev = edge;
|
||||
}
|
||||
|
||||
|
||||
// The last edge must be a negative edge, since
|
||||
// the last vertex must terminate the polygon and
|
||||
// therefore have no right-going edges.
|
||||
@@ -2922,7 +2998,7 @@ public class Mesh< T extends Region > {
|
||||
|
||||
polygon.addEdge( newEdge );
|
||||
}
|
||||
|
||||
|
||||
// Convert each vertex to a point
|
||||
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 onPreChainMergeEvent( final Collection< Chain > chains ) {};
|
||||
default void onPartitionEvent( final Collection< Polygon > polygons ) {};
|
||||
}
|
||||
|
||||
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.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -38,7 +39,8 @@ import org.bukkit.util.Vector;
|
||||
|
||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Chain;
|
||||
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.Polygon;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.Segment;
|
||||
@@ -134,7 +136,7 @@ public class MeshingTest2 extends JPanel {
|
||||
|
||||
final List< Plane > masterPlanes = new ArrayList< Plane >();
|
||||
System.out.println( "Adding test plane" );
|
||||
masterPlanes.add( getTestPlane() );
|
||||
masterPlanes.addAll( getTestPlanes() );
|
||||
|
||||
System.out.println( "Chunk files: " + CHUNK_DIR.listFiles().length );
|
||||
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 edge count: " + ( mesh.getEdgeCount() / 2 ) );
|
||||
|
||||
mesh.addHandler( new MeshEventHandler() {
|
||||
mesh.addChainHandler( new MeshChainEventHandler() {
|
||||
@Override
|
||||
public void onChainGenerationEvent( Collection< Chain > chains ) {
|
||||
data.chains = chains;
|
||||
@@ -310,7 +312,9 @@ public class MeshingTest2 extends JPanel {
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
mesh.addPartitionHandler( new MeshPartitionEventHandler() {
|
||||
@Override
|
||||
public void onPartitionEvent( Collection< Polygon > polygons ) {
|
||||
data.polygons = polygons;
|
||||
@@ -391,7 +395,7 @@ public class MeshingTest2 extends JPanel {
|
||||
private static PlaneData test() {
|
||||
final PlaneData data = new PlaneData();
|
||||
final Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
|
||||
mesh.addHandler( new MeshEventHandler() {
|
||||
mesh.addChainHandler( new MeshChainEventHandler() {
|
||||
@Override
|
||||
public void onChainGenerationEvent( Collection< Chain > chains ) {
|
||||
data.chains = chains;
|
||||
@@ -552,11 +556,13 @@ public class MeshingTest2 extends JPanel {
|
||||
return data;
|
||||
}
|
||||
|
||||
private static Plane getTestPlane() {
|
||||
final Plane plane = new Plane();
|
||||
|
||||
plane.normal = new Vector( 0, 0, 1 );
|
||||
plane.point = new Vector( 1, 0, 0 );
|
||||
private static Collection< Plane > getTestPlanes() {
|
||||
final Collection< Plane > planes = new ArrayDeque< 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( 1, 0 ),
|
||||
@@ -586,62 +592,113 @@ public class MeshingTest2 extends JPanel {
|
||||
// new Point( 0, 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, 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, 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 ),
|
||||
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 )
|
||||
) ) );
|
||||
{
|
||||
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( 2, 2 ),
|
||||
new Point( 2, 1 ),
|
||||
new Point( 1, 1 ),
|
||||
new Point( 1, 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 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 ) {
|
||||
|
||||
@@ -8,7 +8,11 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
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 FACET_DIR = new File( BASE, "facets" );
|
||||
|
||||
private static Collection< Facet > facets = Collections.synchronizedCollection( new LinkedHashSet< Facet >() );
|
||||
|
||||
public static void main( String[] args ) {
|
||||
if ( FACET_DIR.exists() && FACET_DIR.isDirectory() ) {
|
||||
System.out.println( "Found " + FACET_DIR.list().length + " files" );
|
||||
@@ -100,7 +106,9 @@ public class MeshingTest5 {
|
||||
mesh.addPolygon( poly, RegionRuleWinding.CLOCKWISE );
|
||||
}
|
||||
|
||||
mesh.meshify();
|
||||
synchronized( facets ) {
|
||||
facets.addAll( plane.convert( mesh.meshify() ) );
|
||||
}
|
||||
} else {
|
||||
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.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.Polygon;
|
||||
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 edge count: " + ( mesh.getEdgeCount() / 2 ) );
|
||||
|
||||
mesh.addHandler( new MeshEventHandler() {
|
||||
mesh.addChainHandler( new MeshChainEventHandler() {
|
||||
@Override
|
||||
public void onChainGenerationEvent( Collection< Chain > chains ) {
|
||||
data.chains = chains;
|
||||
@@ -323,13 +324,15 @@ public class MeshingTest6 extends JPanel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
mesh.addPartitionHandler( new MeshPartitionEventHandler() {
|
||||
@Override
|
||||
public void onPartitionEvent( Collection< Polygon > polygons ) {
|
||||
data.polygons = polygons;
|
||||
}
|
||||
} );
|
||||
|
||||
|
||||
try {
|
||||
// If the chains are the issue, set this to false and see if it still meshes
|
||||
mesh.setMergeChains( true );
|
||||
@@ -411,7 +414,7 @@ public class MeshingTest6 extends JPanel {
|
||||
private static PlaneData test() {
|
||||
final PlaneData data = new PlaneData();
|
||||
final Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
|
||||
mesh.addHandler( new MeshEventHandler() {
|
||||
mesh.addChainHandler( new MeshChainEventHandler() {
|
||||
@Override
|
||||
public void onChainGenerationEvent( Collection< Chain > 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
|
||||
*/
|
||||
public class ChunkLocation {
|
||||
public class ChunkLocation implements Comparable< ChunkLocation > {
|
||||
private int x, z;
|
||||
private String worldName;
|
||||
private World world;
|
||||
@@ -283,4 +283,16 @@ public class ChunkLocation {
|
||||
public String toString() {
|
||||
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();
|
||||
}
|
||||
|
||||
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() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user