using System;
namespace Assets.Scripts.LevelGeneration
{
public class PlasmaFractal
{
public double Roughness { get; private set; }
public double BigSize { get; private set; }
private readonly Random _random = new Random();
// generates and returns the plasma fractal
public double[,] Generate(int width, int height, double roughness)
{
var points = new double[width + 1, height + 1];
var c1 = _random.NextDouble();
var c2 = _random.NextDouble();
var c3 = _random.NextDouble();
var c4 = _random.NextDouble();
Roughness = roughness;
BigSize = width + height;
DivideGrid(ref points, 0, 0, width, height, c1, c2, c3, c4);
return points;
}
private void DivideGrid(ref double[,] points, double x, double y,
double width, double height,
double c1, double c2, double c3, double c4)
{
var newWidth = Math.Floor(width / 2);
var newHeight = Math.Floor(height / 2);
if (width > 1 || height > 1)
{
var middle = ((c1 + c2 + c3 + c4) / 4) + Displace(newWidth + newHeight);
var edge1 = ((c1 + c2) / 2);
var edge2 = ((c2 + c3) / 2);
var edge3 = ((c3 + c4) / 2);
var edge4 = ((c4 + c1) / 2);
middle = Rectify(middle);
edge1 = Rectify(edge1);
edge2 = Rectify(edge2);
edge3 = Rectify(edge3);
edge4 = Rectify(edge4);
DivideGrid(ref points, x, y, newWidth, newHeight,
c1, edge1, middle, edge4);
DivideGrid(ref points, x + newWidth, y,
width - newWidth, newHeight,
edge1, c2, edge2, middle);
DivideGrid(ref points, x + newWidth, y + newHeight,
width - newWidth, height - newHeight,
middle, edge2, c3, edge3);
DivideGrid(ref points, x, y + newHeight,
newWidth, height - newHeight,
edge4, middle, edge3, c4);
}
else
{
var c = (c1 + c2 + c3 + c4) / 4;
points[(int)x, (int)y] = c;
if (width == 2)
{
points[(int)x + 1, (int)y] = c;
}
if (height == 2)
{
points[(int)x, (int)y + 1] = c;
}
if (width == 2 && height == 2)
{
points[(int)x + 1, (int)y + 1] = c;
}
}
}
private static double Rectify(double number)
{
if (number < 0)
{
number = 0;
}
else if (number > 1.0)
{
number = 1.0;
}
return number;
}
private double Displace(double smallSize)
{
var max = smallSize / BigSize * Roughness;
return (_random.NextDouble() - 0.5) * max;
}
}
}