mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-10 05:41:51 +09:00
added sources for Slick
Former-commit-id: 1647fa32ef6894bd7db44f741f07c2f4dcdf9054 Former-commit-id: 0e5810dcfbe1fd59b13e7cabe9f1e93c5542da2d
This commit is contained in:
426
lib/slick-source/org/newdawn/slick/tests/GeomUtilTileTest.java
Normal file
426
lib/slick-source/org/newdawn/slick/tests/GeomUtilTileTest.java
Normal file
@@ -0,0 +1,426 @@
|
||||
package org.newdawn.slick.tests;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.newdawn.slick.AppGameContainer;
|
||||
import org.newdawn.slick.BasicGame;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.GameContainer;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.SlickException;
|
||||
import org.newdawn.slick.geom.Circle;
|
||||
import org.newdawn.slick.geom.GeomUtil;
|
||||
import org.newdawn.slick.geom.GeomUtilListener;
|
||||
import org.newdawn.slick.geom.Polygon;
|
||||
import org.newdawn.slick.geom.Shape;
|
||||
import org.newdawn.slick.geom.Vector2f;
|
||||
|
||||
/**
|
||||
* A test to try shape building from multiple tiles
|
||||
*
|
||||
* @author Kevin Glass
|
||||
*/
|
||||
public class GeomUtilTileTest extends BasicGame implements GeomUtilListener {
|
||||
/** The shape we're cutting out of */
|
||||
private Shape source;
|
||||
/** The shape we're cutting */
|
||||
private Shape cut;
|
||||
/** The resulting shape */
|
||||
private Shape[] result;
|
||||
|
||||
/** The util under test */
|
||||
private GeomUtil util = new GeomUtil();
|
||||
|
||||
/** The original list of shapes */
|
||||
private ArrayList original = new ArrayList();
|
||||
/** The original list of shapes */
|
||||
private ArrayList combined = new ArrayList();
|
||||
|
||||
/** The list of intersection points */
|
||||
private ArrayList intersections = new ArrayList();
|
||||
/** The list of used points */
|
||||
private ArrayList used = new ArrayList();
|
||||
|
||||
/** The quad space of shapes that need to be checked against each other */
|
||||
private ArrayList[][] quadSpace;
|
||||
/** The shapes present in each quad space - used to optimize generation */
|
||||
private Shape[][] quadSpaceShapes;
|
||||
|
||||
/**
|
||||
* Create a simple test
|
||||
*/
|
||||
public GeomUtilTileTest() {
|
||||
super("GeomUtilTileTest");
|
||||
}
|
||||
|
||||
/**
|
||||
* So this is going to generate a quad space that holds that segments the
|
||||
* shapes into quads across the map. This makes it tunable and limits the number
|
||||
* of comparisons that need to be done for each shape
|
||||
*
|
||||
* @param shapes The shapes to be segments
|
||||
* @param minx The minimum x value of the map
|
||||
* @param miny The mimimum y value of the map
|
||||
* @param maxx The maximum x value of the map
|
||||
* @param maxy The maximum y value of the map
|
||||
* @param segments The number of segments to split the map into
|
||||
*/
|
||||
private void generateSpace(ArrayList shapes, float minx, float miny, float maxx, float maxy, int segments) {
|
||||
quadSpace = new ArrayList[segments][segments];
|
||||
quadSpaceShapes = new Shape[segments][segments];
|
||||
|
||||
float dx = (maxx - minx) / segments;
|
||||
float dy = (maxy - miny) / segments;
|
||||
|
||||
for (int x=0;x<segments;x++) {
|
||||
for (int y=0;y<segments;y++) {
|
||||
quadSpace[x][y] = new ArrayList();
|
||||
|
||||
// quad for this segment
|
||||
Polygon segmentPolygon = new Polygon();
|
||||
segmentPolygon.addPoint(minx+(dx*x), miny+(dy*y));
|
||||
segmentPolygon.addPoint(minx+(dx*x)+dx, miny+(dy*y));
|
||||
segmentPolygon.addPoint(minx+(dx*x)+dx, miny+(dy*y)+dy);
|
||||
segmentPolygon.addPoint(minx+(dx*x), miny+(dy*y)+dy);
|
||||
|
||||
for (int i=0;i<shapes.size();i++) {
|
||||
Shape shape = (Shape) shapes.get(i);
|
||||
|
||||
if (collides(shape, segmentPolygon)) {
|
||||
quadSpace[x][y].add(shape);
|
||||
}
|
||||
}
|
||||
|
||||
quadSpaceShapes[x][y] = segmentPolygon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given shape from the quad space
|
||||
*
|
||||
* @param shape The shape to remove
|
||||
*/
|
||||
private void removeFromQuadSpace(Shape shape) {
|
||||
int segments = quadSpace.length;
|
||||
|
||||
for (int x=0;x<segments;x++) {
|
||||
for (int y=0;y<segments;y++) {
|
||||
quadSpace[x][y].remove(shape);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a particular shape to quad space
|
||||
*
|
||||
* @param shape The shape to be added
|
||||
*/
|
||||
private void addToQuadSpace(Shape shape) {
|
||||
int segments = quadSpace.length;
|
||||
|
||||
for (int x=0;x<segments;x++) {
|
||||
for (int y=0;y<segments;y++) {
|
||||
if (collides(shape, quadSpaceShapes[x][y])) {
|
||||
quadSpace[x][y].add(shape);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the cut
|
||||
*/
|
||||
public void init() {
|
||||
int size = 10;
|
||||
int[][] map = new int[][] {
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 },
|
||||
{ 0, 1, 1, 1, 0, 0, 1, 1, 1, 0 },
|
||||
{ 0, 1, 1, 0, 0, 0, 5, 1, 6, 0 },
|
||||
{ 0, 1, 2, 0, 0, 0, 4, 1, 1, 0 },
|
||||
{ 0, 1, 1, 0, 0, 0, 1, 1, 0, 0 },
|
||||
{ 0, 0, 0, 0, 3, 0, 1, 1, 0, 0 },
|
||||
{ 0, 0, 0, 1, 1, 0, 0, 0, 1, 0 },
|
||||
{ 0, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
// size = 100;
|
||||
// map = new int[size][size];
|
||||
// for (int x=0;x<size;x++) {
|
||||
// for (int y=0;y<size;y++) {
|
||||
// if ((x+y) % 2 == 0) {
|
||||
// map[y][x] = 1;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
for (int x = 0; x < map[0].length; x++) {
|
||||
for (int y = 0; y < map.length; y++) {
|
||||
if (map[y][x] != 0) {
|
||||
switch (map[y][x]) {
|
||||
case 1:
|
||||
Polygon p2 = new Polygon();
|
||||
p2.addPoint(x * 32, y * 32);
|
||||
p2.addPoint((x * 32) + 32, y * 32);
|
||||
p2.addPoint((x * 32) + 32, (y * 32) + 32);
|
||||
p2.addPoint(x * 32, (y * 32) + 32);
|
||||
original.add(p2);
|
||||
break;
|
||||
case 2:
|
||||
Polygon poly = new Polygon();
|
||||
poly.addPoint(x * 32, y * 32);
|
||||
poly.addPoint((x * 32) + 32, y * 32);
|
||||
poly.addPoint(x * 32, (y * 32) + 32);
|
||||
original.add(poly);
|
||||
break;
|
||||
case 3:
|
||||
Circle ellipse = new Circle((x*32)+16,(y*32)+32,16,16);
|
||||
original.add(ellipse);
|
||||
break;
|
||||
case 4:
|
||||
Polygon p = new Polygon();
|
||||
p.addPoint((x * 32) + 32, (y * 32));
|
||||
p.addPoint((x * 32) + 32, (y * 32)+32);
|
||||
p.addPoint(x * 32, (y * 32) + 32);
|
||||
original.add(p);
|
||||
break;
|
||||
case 5:
|
||||
Polygon p3 = new Polygon();
|
||||
p3.addPoint((x * 32), (y * 32));
|
||||
p3.addPoint((x * 32) + 32, (y * 32));
|
||||
p3.addPoint((x * 32) + 32, (y * 32)+32);
|
||||
original.add(p3);
|
||||
break;
|
||||
case 6:
|
||||
Polygon p4 = new Polygon();
|
||||
p4.addPoint((x * 32), (y * 32));
|
||||
p4.addPoint((x * 32) + 32, (y * 32));
|
||||
p4.addPoint((x * 32), (y * 32)+32);
|
||||
original.add(p4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long before = System.currentTimeMillis();
|
||||
|
||||
// the quad spaced method
|
||||
generateSpace(original, 0, 0, (size+1)*32,(size+1)*32,8);
|
||||
combined = combineQuadSpace();
|
||||
|
||||
// the brute force method
|
||||
//combined = combine(original);
|
||||
|
||||
long after = System.currentTimeMillis();
|
||||
System.out.println("Combine took: "+(after-before));
|
||||
System.out.println("Combine result: "+combined.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine the shapes in the quad space
|
||||
*
|
||||
* @return The newly combined list of shapes
|
||||
*/
|
||||
private ArrayList combineQuadSpace() {
|
||||
boolean updated = true;
|
||||
while (updated) {
|
||||
updated = false;
|
||||
|
||||
for (int x=0;x<quadSpace.length;x++) {
|
||||
for (int y=0;y<quadSpace.length;y++) {
|
||||
ArrayList shapes = quadSpace[x][y];
|
||||
int before = shapes.size();
|
||||
combine(shapes);
|
||||
int after = shapes.size();
|
||||
|
||||
updated |= before != after;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// at this stage all the shapes that can be combined within their quads
|
||||
// will have gone on - we may need to combine stuff on the boundary tho
|
||||
HashSet result = new HashSet();
|
||||
|
||||
for (int x=0;x<quadSpace.length;x++) {
|
||||
for (int y=0;y<quadSpace.length;y++) {
|
||||
result.addAll(quadSpace[x][y]);
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine a set of shapes together
|
||||
*
|
||||
* @param shapes
|
||||
* The shapes to be combined
|
||||
* @return The list of combined shapes
|
||||
*/
|
||||
private ArrayList combine(ArrayList shapes) {
|
||||
ArrayList last = shapes;
|
||||
ArrayList current = shapes;
|
||||
boolean first = true;
|
||||
|
||||
while ((current.size() != last.size()) || (first)) {
|
||||
first = false;
|
||||
last = current;
|
||||
current = combineImpl(current);
|
||||
}
|
||||
|
||||
ArrayList pruned = new ArrayList();
|
||||
for (int i = 0; i < current.size(); i++) {
|
||||
pruned.add(((Shape) current.get(i)).prune());
|
||||
}
|
||||
return pruned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to find a simple combination that can be performed
|
||||
*
|
||||
* @param shapes
|
||||
* The shapes to be combined
|
||||
* @return The new list of shapes - this will be the same length as the
|
||||
* input if there are no new combinations
|
||||
*/
|
||||
private ArrayList combineImpl(ArrayList shapes) {
|
||||
ArrayList result = new ArrayList(shapes);
|
||||
if (quadSpace != null) {
|
||||
result = shapes;
|
||||
}
|
||||
|
||||
for (int i = 0; i < shapes.size(); i++) {
|
||||
Shape first = (Shape) shapes.get(i);
|
||||
for (int j = i + 1; j < shapes.size(); j++) {
|
||||
Shape second = (Shape) shapes.get(j);
|
||||
|
||||
if (!first.intersects(second)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Shape[] joined = util.union(first, second);
|
||||
if (joined.length == 1) {
|
||||
if (quadSpace != null) {
|
||||
removeFromQuadSpace(first);
|
||||
removeFromQuadSpace(second);
|
||||
addToQuadSpace(joined[0]);
|
||||
} else {
|
||||
result.remove(first);
|
||||
result.remove(second);
|
||||
result.add(joined[0]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if two shapes collide
|
||||
*
|
||||
* @param shape1 The first shape
|
||||
* @param shape2 The second shape
|
||||
* @return True if the shapes collide (i.e. intersection or overlap)
|
||||
*/
|
||||
public boolean collides(Shape shape1, Shape shape2) {
|
||||
if (shape1.intersects(shape2)) {
|
||||
return true;
|
||||
}
|
||||
for (int i=0;i<shape1.getPointCount();i++) {
|
||||
float[] pt = shape1.getPoint(i);
|
||||
if (shape2.contains(pt[0], pt[1])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (int i=0;i<shape2.getPointCount();i++) {
|
||||
float[] pt = shape2.getPoint(i);
|
||||
if (shape1.contains(pt[0], pt[1])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see BasicGame#init(GameContainer)
|
||||
*/
|
||||
public void init(GameContainer container) throws SlickException {
|
||||
util.setListener(this);
|
||||
init();
|
||||
//container.setVSync(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see BasicGame#update(GameContainer, int)
|
||||
*/
|
||||
public void update(GameContainer container, int delta)
|
||||
throws SlickException {
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.Game#render(GameContainer, Graphics)
|
||||
*/
|
||||
public void render(GameContainer container, Graphics g)
|
||||
throws SlickException {
|
||||
g.setColor(Color.green);
|
||||
for (int i = 0; i < original.size(); i++) {
|
||||
Shape shape = (Shape) original.get(i);
|
||||
g.draw(shape);
|
||||
}
|
||||
|
||||
g.setColor(Color.white);
|
||||
if (quadSpaceShapes != null) {
|
||||
g.draw(quadSpaceShapes[0][0]);
|
||||
}
|
||||
|
||||
g.translate(0, 320);
|
||||
|
||||
for (int i = 0; i < combined.size(); i++) {
|
||||
g.setColor(Color.white);
|
||||
Shape shape = (Shape) combined.get(i);
|
||||
g.draw(shape);
|
||||
for (int j = 0; j < shape.getPointCount(); j++) {
|
||||
g.setColor(Color.yellow);
|
||||
float[] pt = shape.getPoint(j);
|
||||
g.fillOval(pt[0] - 1, pt[1] - 1, 3, 3);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point to our test
|
||||
*
|
||||
* @param argv
|
||||
* The arguments passed to the test
|
||||
*/
|
||||
public static void main(String[] argv) {
|
||||
try {
|
||||
AppGameContainer container = new AppGameContainer(
|
||||
new GeomUtilTileTest());
|
||||
container.setDisplayMode(800, 600, false);
|
||||
container.start();
|
||||
} catch (SlickException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void pointExcluded(float x, float y) {
|
||||
}
|
||||
|
||||
public void pointIntersected(float x, float y) {
|
||||
intersections.add(new Vector2f(x, y));
|
||||
}
|
||||
|
||||
public void pointUsed(float x, float y) {
|
||||
used.add(new Vector2f(x, y));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user