/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.pepsoft.worldpainter.layers.pockets;
import org.pepsoft.minecraft.Chunk;
import org.pepsoft.util.MathUtils;
import org.pepsoft.util.PerlinNoise;
import org.pepsoft.worldpainter.*;
import org.pepsoft.worldpainter.exporting.AbstractLayerExporter;
import org.pepsoft.worldpainter.exporting.FirstPassLayerExporter;
import org.pepsoft.worldpainter.layers.exporters.ExporterSettings;
import java.awt.image.BufferedImage;
import static org.pepsoft.worldpainter.Constants.TILE_SIZE_BITS;
import static org.pepsoft.worldpainter.Constants.TINY_BLOBS;
/**
*
* @author pepijn
*/
public class UndergroundPocketsLayerExporter extends AbstractLayerExporter<UndergroundPocketsLayer> implements FirstPassLayerExporter {
public UndergroundPocketsLayerExporter(UndergroundPocketsLayer layer) {
super(layer);
}
@Override
public void setSettings(ExporterSettings settings) {
super.setSettings(settings);
init();
}
@Override
public void render(Dimension dimension, Tile tile, Chunk chunk) {
final MixedMaterial material = layer.getMaterial();
final Terrain terrain = layer.getTerrain();
final boolean useMaterial = material != null;
final int minLevel = layer.getMinLevel();
final int maxLevel = layer.getMaxLevel();
final boolean coverSteepTerrain = dimension.isCoverSteepTerrain();
final int xOffset = (chunk.getxPos() & 7) << 4;
final int zOffset = (chunk.getzPos() & 7) << 4;
final long seed = dimension.getSeed();
if (noiseGenerator.getSeed() != seed + seedOffset) {
noiseGenerator.setSeed(seed + seedOffset);
}
// Coordinates in chunk
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
// Coordinates in tile
final int localX = xOffset + x, localY = zOffset + z;
if (tile.getBitLayerValue(org.pepsoft.worldpainter.layers.Void.INSTANCE, localX, localY)) {
continue;
}
final int value = tile.getLayerValue(layer, localX, localY);
if (value > 0) {
final float biasedThreshold = biasedThresholds[value - 1];
final int terrainheight = tile.getIntHeight(localX, localY);
// Coordinates in world
final int worldX = tile.getX() << TILE_SIZE_BITS | localX, worldY = tile.getY() << TILE_SIZE_BITS | localY;
final int minY = Math.max(1, minLevel);
int maxY = Math.min(terrainheight - dimension.getTopLayerDepth(worldX, worldY, terrainheight), maxLevel);
if (coverSteepTerrain) {
maxY = Math.min(maxY,
Math.min(Math.min(dimension.getIntHeightAt(worldX - 1, worldY, Integer.MAX_VALUE),
dimension.getIntHeightAt(worldX + 1, worldY, Integer.MAX_VALUE)),
Math.min(dimension.getIntHeightAt(worldX, worldY - 1, Integer.MAX_VALUE),
dimension.getIntHeightAt(worldX, worldY + 1, Integer.MAX_VALUE))));
}
if (biasedThreshold <= -0.5f) {
// Special case: replace every block
for (int y = maxY; y >= minY; y--) {
if (useMaterial) {
chunk.setMaterial(x, y, z, material.getMaterial(seed, worldX, worldY, y));
} else {
chunk.setMaterial(x, y, z, terrain.getMaterial(seed, worldX, worldY, y, terrainheight));
}
}
} else {
for (int y = maxY; y >= minY; y--) {
double dx = worldX / scale, dy = worldY / scale, dz = y / scale;
if (noiseGenerator.getPerlinNoise(dx, dy, dz) >= biasedThreshold) {
if (useMaterial) {
chunk.setMaterial(x, y, z, material.getMaterial(seed, worldX, worldY, y));
} else {
chunk.setMaterial(x, y, z, terrain.getMaterial(seed, worldX, worldY, y, terrainheight));
}
}
}
}
}
}
}
}
/**
* Create a black and white preview of the layer.
*/
public BufferedImage createPreview(int width, int height) {
init();
final BufferedImage preview = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
// For threshold <= -0.5 the image would be all-black, which it is by
// default anyway
if (threshold > -0.5f) {
for (int x = 0; x < width; x++) {
for (int z = 0; z < height; z++) {
double dx = x / scale, dz = z / scale;
if (noiseGenerator.getPerlinNoise(dx, 0.0, dz) < threshold) {
preview.setRGB(x, height - z - 1, 0xffffff);
}
}
}
}
// drawLabels(preview, height);
return preview;
}
/**
* Create a coloured preview of the layer.
*/
public BufferedImage createPreview(int width, int height, ColourScheme colourScheme, Terrain subsurfaceMaterial) {
init();
final BufferedImage preview = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
final MixedMaterial material = layer.getMaterial();
final Terrain terrain = layer.getTerrain();
final boolean useMaterial = material != null;
if (threshold <= -0.5f) {
// Special case: replace every block
for (int x = 0; x < width; x++) {
for (int z = 0; z < height; z++) {
if (useMaterial) {
preview.setRGB(x, height - z - 1, colourScheme.getColour(material.getMaterial(0L, x, 0, z)));
} else {
preview.setRGB(x, height - z - 1, colourScheme.getColour(terrain.getMaterial(0L, x, 0, z, height - 1)));
}
}
}
} else {
for (int x = 0; x < width; x++) {
for (int z = 0; z < height; z++) {
double dx = x / scale, dz = z / scale;
if (noiseGenerator.getPerlinNoise(dx, 0.0, dz) >= threshold) {
if (useMaterial) {
preview.setRGB(x, height - z - 1, colourScheme.getColour(material.getMaterial(0L, x, 0, z)));
} else {
preview.setRGB(x, height - z - 1, colourScheme.getColour(terrain.getMaterial(0L, x, 0, z, height - 1)));
}
} else {
preview.setRGB(x, height - z - 1, colourScheme.getColour(subsurfaceMaterial.getMaterial(0L, x, 0, z, height - 1)));
}
}
}
}
// drawLabels(preview, height);
return preview;
}
private void init() {
seedOffset = (layer.getMaterial() != null) ? layer.getMaterial().hashCode() : layer.getTerrain().hashCode();
for (int i = 1; i <= 15; i++) {
biasedThresholds[i - 1] = PerlinNoise.getLevelForPromillage(MathUtils.clamp(0f, (float) (layer.getFrequency() * Math.pow(0.9, 8 - i)), 1000f));
}
threshold = biasedThresholds[8];
scale = TINY_BLOBS * (layer.getScale() / 100.0);
}
// private void drawLabels(final BufferedImage preview, final int height) {
// Font font = new Font(Font.DIALOG, Font.PLAIN, 8);
// Graphics2D g2 = preview.createGraphics();
// try {
// g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// g2.setColor(Color.WHITE);
// g2.setFont(font);
// LineMetrics lineMetrics = font.getLineMetrics("000", g2.getFontRenderContext());
// int offset = (int) (lineMetrics.getAscent() / 2 + 0.5f);
// for (int z = 16; z < height; z += 16) {
// String text = Integer.toString(z);
// for (int dx = -1; dx <= 1; dx++) {
// for (int dy = -1; dy <= 1; dy++) {
// g2.drawLine(0, height - z - 1 + dy, 3 + dx, height - z - 1 + dy);
// g2.drawString(text, 5 + dx, height - z - 1 + offset + dy);
// }
// }
// }
// g2.setColor(Color.BLACK);
// g2.setFont(font);
// for (int z = 16; z < height; z += 16) {
// g2.drawLine(0, height - z - 1, 3, height - z - 1);
// g2.drawString(Integer.toString(z), 5, height - z - 1 + offset);
// }
// } finally {
// g2.dispose();
// }
// }
private final PerlinNoise noiseGenerator = new PerlinNoise(0);
/**
* The thresholds for all possible layer values
*/
private final float[] biasedThresholds = new float[15];
private long seedOffset;
/**
* The threshold for value 8 (50% intensity)
*/
private float threshold;
private double scale;
}