package Roguelike.DungeonGeneration.RoomGenerators;
import java.util.Random;
import Roguelike.DungeonGeneration.DungeonFileParser;
import Roguelike.DungeonGeneration.Symbol;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.XmlReader.Element;
/**
* Fill the room with pools of terrain based on ranges within the output of
* simplex noise
*
* @author Philip Collin
*
*/
public class Fractal extends AbstractRoomGenerator
{
private float frequency = 10;
private float amplitude = 0.8f;
private int octaves = 8;
private float scale = 0.005f;
private Array<FractalFeature> features = new Array<FractalFeature>();
@Override
public void process( Symbol[][] grid, Symbol floor, Symbol wall, Random ran, DungeonFileParser dfp )
{
int width = grid.length;
int height = grid[0].length;
for ( int x = 0; x < width; x++ )
{
for ( int y = 0; y < height; y++ )
{
grid[x][y] = wall;
}
}
Chambers chambers = new Chambers();
chambers.process( grid, floor, wall, ran, dfp );
NoiseGenerator noise = new NoiseGenerator( ran.nextInt( 1000 ), frequency, amplitude, octaves, scale );
float[][] simplexGrid = new float[width][height];
float minVal = Float.MAX_VALUE;
float maxVal = 0;
for ( int x = 0; x < width; x++ )
{
for ( int y = 0; y < height; y++ )
{
float noiseVal = noise.generate( x, y );
if ( noiseVal < minVal )
{
minVal = noiseVal;
}
if ( noiseVal > maxVal )
{
maxVal = noiseVal;
}
simplexGrid[x][y] = noiseVal;
}
}
for ( int x = 0; x < width; x++ )
{
for ( int y = 0; y < height; y++ )
{
float val = simplexGrid[x][y];
float zeroed = val - minVal;
float alpha = zeroed / ( maxVal - minVal );
simplexGrid[x][y] = alpha;
}
}
for ( int x = 0; x < width; x++ )
{
for ( int y = 0; y < height; y++ )
{
float val = simplexGrid[x][y];
for ( FractalFeature feature : features )
{
if ( val >= feature.minVal && val <= feature.maxVal )
{
grid[x][y] = feature.getAsSymbol( );
break;
}
}
}
}
}
private static final class NoiseGenerator
{
float offset;
float frequency;
float amplitude;
int octaves;
float scale;
public NoiseGenerator( float offset, float frequency, float amplitude, int octaves, float scale )
{
this.offset = offset;
this.frequency = frequency;
this.amplitude = amplitude;
this.octaves = octaves;
this.scale = scale;
}
public float generate( float x, float y )
{
return FastSimplexNoise.noise( x + offset, 0, y + offset, frequency, amplitude, octaves, scale, true, null );
}
}
// ----------------------------------------------------------------------
public static class FractalFeature
{
public Symbol symbol;
public float minVal;
public float maxVal;
public static FractalFeature load( Element xml )
{
FractalFeature feature = new FractalFeature();
feature.symbol = Symbol.parse( xml );
feature.minVal = xml.getFloat( "MinVal", 0 );
feature.maxVal = xml.getFloat( "MaxVal", 1 );
return feature;
}
public Symbol getAsSymbol( )
{
return symbol;
}
}
@Override
public void parse( Element xml )
{
frequency = xml.getFloat( "Frequency", 10 );
amplitude = xml.getFloat( "Amplitude", 0.8f );
octaves = xml.getInt( "Octaves", 8 );
scale = xml.getFloat( "Scale", 0.005f );
Element featuresElement = xml.getChildByName( "Features" );
for ( int i = 0; i < featuresElement.getChildCount(); i++ )
{
Element featureElement = featuresElement.getChild( i );
FractalFeature feature = FractalFeature.load( featureElement );
features.add( feature );
}
}
}