/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.pepsoft.worldpainter.themes.impl.fancy;
import java.util.HashSet;
import java.util.Random;
import javax.vecmath.Point3i;
import org.pepsoft.util.undo.UndoManager;
import org.pepsoft.worldpainter.Dimension;
import org.pepsoft.worldpainter.Tile;
import static org.pepsoft.worldpainter.Constants.*;
import org.pepsoft.worldpainter.gardenofeden.Garden;
/**
*
* @author pepijn
*/
public class RiverGenerator {
public RiverGenerator(Dimension dimension) {
this.dimension = dimension;
}
public void generateRivers() {
dimension.setEventsInhibited(true);
UndoManager undoManager = new UndoManager(2);
dimension.register(undoManager);
snapshot = dimension.getSnapshot();
dimension.armSavePoint();
garden = dimension.getGarden();
try {
dimension.getTiles().forEach(this::generateRivers);
// Grow seeds until all activity has ceased
while (! garden.tick());
// Apply the river nodes to the landscape
// A river source
dimension.getGarden().getSeeds().stream().filter(seed -> (seed instanceof RiverNode) && (seed.getParent() == null)).forEach(seed -> {
// A river source
((RiverNode) seed).apply(dimension, snapshot, new HashSet<>());
});
} finally {
garden = null;
snapshot = null;
dimension.unregister();
dimension.setEventsInhibited(false);
}
}
public void generateRivers(Tile tile) {
long seed = dimension.getSeed() + tile.getX() * 65537 + tile.getY();
Random random = new Random(seed);
for (int x = 0; x < TILE_SIZE; x++) {
for (int y = 0; y < TILE_SIZE; y++) {
if (random.nextInt(1000) == 0) {
generateRiver((tile.getX() << TILE_SIZE_BITS) | x, (tile.getY() << TILE_SIZE_BITS) | y);
}
}
}
}
public void generateRiver(int x, int y) {
// System.out.println("Start coordinates: " + x + ", " + y);
int waterLevel = snapshot.getWaterLevelAt(x, y);
float height = snapshot.getHeightAt(x, y);
int intHeight = (int) (height + 0.5f);
if (waterLevel > intHeight) {
// Already flooded
} else {
garden.plantSeed(new RiverNode(garden, new Point3i(x, y, -1), 1));
}
// while (true) {
// if (waterLevel > intHeight) {
// // Already flooded
//// System.out.println("Already flooded");
// return;
// } else {
// int lowestSurroundingDryHeight = getLowestSurroundingDryHeight(x, y);
// if (lowestSurroundingDryHeight == 0) {
// // At bedrock; can't go any deeper
//// System.out.println("Lowest surrounding dry block is at level 0");
// return;
// } else if (lowestSurroundingDryHeight == Integer.MAX_VALUE) {
// // This means that all surrounding blocks are flooded.
// dimension.setWaterLevelAt(x, y, getLowestSurroundingWaterLevel(x, y));
// return;
// } else {
// dimension.setHeightAt(x, y, lowestSurroundingDryHeight - 1);
// dimension.setWaterLevelAt(x, y, lowestSurroundingDryHeight);
// }
// }
// int nextX = 0, nextY = 0;
// float lowestSurroundingHeight = height;
// for (int dx = -2; dx <= 2; dx++) {
// for (int dy = -2; dy <= 2; dy++) {
// if ((dx != 0) || (dy != 0)) {
// float surroundingHeight = snapshot.getHeightAt(x + dx, y + dy);
// if (surroundingHeight < lowestSurroundingHeight) {
// lowestSurroundingHeight = surroundingHeight;
// nextX = x + dx;
// nextY = y + dy;
// }
// }
// }
// }
// if (lowestSurroundingHeight == height) {
// // No lower block found; end of river
// // TODO: start a lake?
//// System.out.println("No lower surrounding block found");
// return;
// }
// x = nextX;
// y = nextY;
//// System.out.println("Next coordinates: " + x + ", " + y);
// waterLevel = snapshot.getWaterLevelAt(x, y);
// height = snapshot.getHeightAt(x, y);
// intHeight = (int) (height + 0.5f);
// }
}
public int getLowestSurroundingDryHeight(int x, int y) {
int lowestSurroundingDryHeight = Integer.MAX_VALUE;
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) {
if ((dx != 0) || (dy != 0)) {
int height = snapshot.getIntHeightAt(x + dx, y + dy);
if ((height >= snapshot.getWaterLevelAt(x + dx, y + dy)) && (height < lowestSurroundingDryHeight)) {
if (height == 0) {
return 0;
} else {
lowestSurroundingDryHeight = height;
}
}
}
}
}
return lowestSurroundingDryHeight;
}
public int getLowestSurroundingWaterLevel(int x, int y) {
int lowestSurroundingWaterLevel = Integer.MAX_VALUE;
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) {
if ((dx != 0) || (dy != 0)) {
int waterLevel = snapshot.getWaterLevelAt(x + dx, y + dy);
if ((waterLevel > snapshot.getIntHeightAt(x + dx, y + dy)) && (waterLevel < lowestSurroundingWaterLevel)) {
if (waterLevel == 0) {
return 0;
} else {
lowestSurroundingWaterLevel = waterLevel;
}
}
}
}
}
return lowestSurroundingWaterLevel;
}
private final Dimension dimension;
private Dimension snapshot;
private Garden garden;
}