BlockFace[] topExtension = { null, null };
BlockFace[] bottomExtension = { null, null };
for (int i = 0; i < 2; ++i) {
for (BlockFace face : verticalFaces.get(i)) {
Vector2f faceTop = face.getFirstCorner();
Vector2f faceBottom = face.getSecondCorner();
// find right/left neighbour
if (Math.abs(faceTop.x - blockTop[(i + 1) % 2].x) < EPS && faceBottom.y < blockTop[i].y
&& faceTop.y > blockBottom[i].y)
horizontalNeighbours.get((i + 1) % 2).add(face);
// find top/bottom extension
if (Math.abs(faceTop.x - blockTop[i].x) < EPS) {
if (Math.abs(faceBottom.y - blockTop[i].y) < EPS)
topExtension[i] = face;
else if (Math.abs(faceTop.y - blockBottom[i].y) < EPS)
bottomExtension[i] = face;
}
}
}
for (int i = 0; i < 2; ++i) {
BlockFace face = null;
// create a new face if no extension was found
// add it to existing face if there is exactly one extension
// merge to faces if two extensions were found
if (topExtension[i] == null && bottomExtension[i] == null) {
// only if block is not smaller than neighbour
// if it has more than one neighbours it cannot be completely
// hidden by them
BlockFace neighbour = null;
if (horizontalNeighbours.get(i).size() == 1)
neighbour = horizontalNeighbours.get(i).getFirst();
if (neighbour == null || neighbour.getFirstCorner().y < blockTop[i].y
|| neighbour.getSecondCorner().y > blockBottom[i].y) {
face = new BlockFace(block, i == 0 ? FacePlace.LEFT : FacePlace.RIGHT);
verticalFaces.get(i).add(face);
}
} else if (topExtension[i] != null && bottomExtension[i] == null) {
face = topExtension[i];
face.addBack(block);
} else if (topExtension[i] == null && bottomExtension[i] != null) {
face = bottomExtension[i];
face.addFront(block);
} else {
face = topExtension[i];
face.addBack(block);
face.addBack(bottomExtension[i]);
verticalFaces.get(i).remove(bottomExtension[i]);
}
for (BlockFace neighbour : horizontalNeighbours.get(i)) {
float neighbourTop = neighbour.getFirstCorner().y;
float neighbourBottom = neighbour.getSecondCorner().y;
// adjust corners if exactly one overlaps neighbour
// both cases cannot happen for more than one neighbour
// it is not necessary to split face if there is a neighbour in
// the middle
if (face != null) {
if (neighbourTop < face.getFirstCorner().y && neighbourBottom <= face.getSecondCorner().y)
face.setSecondCorner(neighbour.getFirstCorner());
else if (neighbourBottom > face.getSecondCorner().y && neighbourTop >= face.getFirstCorner().y)
face.setFirstCorner(neighbour.getSecondCorner());
}
// delete neighbour if it is smaller
// adjust corners if exactly one overlaps
if (neighbourTop <= blockTop[i].y && neighbourBottom >= blockBottom[i].y)
removeFace(neighbour);
else if (neighbourTop > blockTop[i].y && neighbourBottom >= blockBottom[i].y) {
// follow the block's face upwards
Block lastBlock = block;
boolean found;
do {
found = false;
for (Block nextBlock : blocks) {
Vector2f dv = new Vector2f();
if (i == 0) // left face
Vector2f.sub(lastBlock.getCornerPos(CornerPlace.TOP_LEFT),
nextBlock.getCornerPos(CornerPlace.BOTTOM_LEFT), dv);
else
// right face
Vector2f.sub(lastBlock.getCornerPos(CornerPlace.TOP_RIGHT),
nextBlock.getCornerPos(CornerPlace.BOTTOM_RIGHT), dv);
if (Math.abs(dv.x) < EPS && Math.abs(dv.y) < EPS) {
lastBlock = nextBlock;
found = true;
break;
}
}
} while (found);
neighbour.setSecondCorner(lastBlock.getCornerPos((i == 0) ? CornerPlace.TOP_LEFT
: CornerPlace.TOP_RIGHT));
} else if (neighbourBottom < blockBottom[i].y && neighbourTop <= blockTop[i].y) {
// follow the block's face downwards
Block lastBlock = block;
boolean found;
do {
found = false;
for (Block nextBlock : blocks) {
Vector2f dv = new Vector2f();
if (i == 0) // left face
Vector2f.sub(lastBlock.getCornerPos(CornerPlace.BOTTOM_LEFT),
nextBlock.getCornerPos(CornerPlace.TOP_LEFT), dv);
else
// right face
Vector2f.sub(lastBlock.getCornerPos(CornerPlace.BOTTOM_RIGHT),
nextBlock.getCornerPos(CornerPlace.TOP_RIGHT), dv);
if (Math.abs(dv.x) < EPS && Math.abs(dv.y) < EPS) {
lastBlock = nextBlock;
found = true;
break;
}
}
} while (found);
neighbour.setFirstCorner(lastBlock.getCornerPos((i == 0) ? CornerPlace.BOTTOM_LEFT
: CornerPlace.BOTTOM_RIGHT));
}
}
}
// update the horizontal block faces
ArrayList<LinkedList<BlockFace>> horizontalFaces = new ArrayList<LinkedList<BlockFace>>();
horizontalFaces.add(topBlockFaces);
horizontalFaces.add(bottomBlockFaces);
BlockFace[] leftExtension = { null, null };
BlockFace[] rightExtension = { null, null };
for (int i = 0; i < 2; ++i) {
for (BlockFace face : horizontalFaces.get(i)) {
Vector2f faceLeft = face.getFirstCorner();
Vector2f faceRight = face.getSecondCorner();
// find bottom/top neighbour
if (Math.abs(faceLeft.y - blockLeft[(i + 1) % 2].y) < EPS && faceRight.x > blockLeft[i].x
&& faceLeft.x < blockRight[i].x)
verticalNeighbours.get((i + 1) % 2).add(face);
// find left/right extension
if (Math.abs(faceLeft.y - blockLeft[i].y) < EPS) {
if (Math.abs(faceRight.x - blockLeft[i].x) < EPS)
leftExtension[i] = face;
else if (Math.abs(faceLeft.x - blockRight[i].x) < EPS)
rightExtension[i] = face;
}
}
}
for (int i = 0; i < 2; ++i) {
BlockFace face = null;
// create a new face if no extension was found
// add it to existing face if there is exactly one extension
// merge to faces if two extensions were found
if (leftExtension[i] == null && rightExtension[i] == null) {
// only if block is not smaller than neighbour
// if it has more than one neighbours it cannot be completely
// hidden by them
BlockFace neighbour = null;
if (verticalNeighbours.get(i).size() == 1)
neighbour = verticalNeighbours.get(i).getFirst();
if (neighbour == null || neighbour.getFirstCorner().x > blockLeft[i].x
|| neighbour.getSecondCorner().x < blockRight[i].x) {
face = new BlockFace(block, i == 0 ? FacePlace.TOP : FacePlace.BOTTOM);
horizontalFaces.get(i).add(face);
}
} else if (leftExtension[i] != null && rightExtension[i] == null) {
face = leftExtension[i];
face.addBack(block);
} else if (leftExtension[i] == null && rightExtension[i] != null) {
face = rightExtension[i];
face.addFront(block);
} else {
face = leftExtension[i];
face.addBack(block);
face.addBack(rightExtension[i]);
horizontalFaces.get(i).remove(rightExtension[i]);
}
for (BlockFace neighbour : verticalNeighbours.get(i)) {
float neighbourLeft = neighbour.getFirstCorner().x;
float neighbourRight = neighbour.getSecondCorner().x;
// adjust corners if exactly one overlaps neighbour
// both cases cannot happen for more than one neighbour
// it is not necessary to split face if there is a neighbour in
// the middle
if (face != null) {
if (neighbourLeft > face.getFirstCorner().x && neighbourRight >= face.getSecondCorner().x)
face.setSecondCorner(neighbour.getFirstCorner());
else if (neighbourRight < face.getSecondCorner().x && neighbourLeft <= face.getFirstCorner().x)
face.setFirstCorner(neighbour.getSecondCorner());
}
// delete neighbour if it is smaller
// adjust corners if exactly one overlaps
if (neighbourLeft >= blockLeft[i].x && neighbourRight <= blockRight[i].x)
removeFace(neighbour);
else if (neighbourLeft < blockLeft[i].x && neighbourRight <= blockRight[i].x) {
// follow the block's face leftwards
Block lastBlock = block;
boolean found;
do {
found = false;
for (Block nextBlock : blocks) {
Vector2f dv = new Vector2f();
if (i == 0) // top face
Vector2f.sub(lastBlock.getCornerPos(CornerPlace.TOP_LEFT),
nextBlock.getCornerPos(CornerPlace.TOP_RIGHT), dv);
else
// bottom face
Vector2f.sub(lastBlock.getCornerPos(CornerPlace.BOTTOM_LEFT),
nextBlock.getCornerPos(CornerPlace.BOTTOM_RIGHT), dv);
if (Math.abs(dv.x) < EPS && Math.abs(dv.y) < EPS) {
lastBlock = nextBlock;
found = true;
break;
}
}
} while (found);
neighbour.setSecondCorner(lastBlock.getCornerPos((i == 0) ? CornerPlace.TOP_LEFT
: CornerPlace.BOTTOM_LEFT));
} else if (neighbourRight > blockRight[i].x && neighbourLeft >= blockLeft[i].x) {
// follow the block's face rightwards
Block lastBlock = block;
boolean found;
do {
found = false;
for (Block nextBlock : blocks) {
Vector2f dv = new Vector2f();
if (i == 0) // top face
Vector2f.sub(lastBlock.getCornerPos(CornerPlace.TOP_RIGHT),
nextBlock.getCornerPos(CornerPlace.TOP_LEFT), dv);
else
// bottom face