NoiseEngine/CubicNoise/Noisers/CubicNoiseEngine.cs

97 lines
5.3 KiB
C#
Raw Normal View History

2020-01-11 18:00:46 +00:00
using System;
using System.Collections.Generic;
2020-01-11 20:14:48 +00:00
using System.Runtime.CompilerServices;
2020-01-11 18:00:46 +00:00
using System.Text;
using CubicNoise.Contracts;
namespace CubicNoise.Noisers
{
public sealed class CubicNoiseEngine : INoiseEngine
{
2020-01-11 20:14:48 +00:00
private const int RANDOM_NUMBER_A = 134_775_813;
private const int RANDOM_NUMBER_B = 1_103_515_245;
private readonly int octave;
private readonly int periodX;
private readonly int periodY;
2020-01-11 22:30:24 +00:00
private readonly int seed;
2020-01-11 18:00:46 +00:00
2020-01-11 22:34:10 +00:00
public CubicNoiseEngine(int seed, IReadOnlyDictionary<IParameterName, int> intParameters)
2020-01-11 18:00:46 +00:00
{
this.seed = seed;
2020-01-11 20:14:48 +00:00
this.octave = intParameters?.ContainsKey(CubicNoiseIntParameters.OCTAVE) == true ? intParameters[CubicNoiseIntParameters.OCTAVE] : 16;
this.periodX = intParameters?.ContainsKey(CubicNoiseIntParameters.PERIOD_X) == true ? intParameters[CubicNoiseIntParameters.PERIOD_X] : 1_000;
this.periodY = intParameters?.ContainsKey(CubicNoiseIntParameters.PERIOD_Y) == true ? intParameters[CubicNoiseIntParameters.PERIOD_Y] : 512;
2020-01-11 18:00:46 +00:00
}
public float Get(float x)
{
2020-01-11 20:14:48 +00:00
var xi = (int)Math.Floor(x / this.octave);
var octaveXFactor = x / this.octave - xi;
2020-01-11 22:34:10 +00:00
return Interpolation(
a: this.RandomNumberGenerator(x: DeterminePatch(xi - 1, this.periodX), y: 0),
b: this.RandomNumberGenerator(x: DeterminePatch(xi + 0, this.periodX), y: 0),
c: this.RandomNumberGenerator(x: DeterminePatch(xi + 1, this.periodX), y: 0),
d: this.RandomNumberGenerator(x: DeterminePatch(xi + 2, this.periodX), y: 0),
2020-01-11 20:14:48 +00:00
x: octaveXFactor) * 0.5f + 0.25f;
2020-01-11 18:00:46 +00:00
}
public float Get(float x, float y)
{
2020-01-11 20:14:48 +00:00
var xi = (int)Math.Floor(x / octave);
var yi = (int)Math.Floor(y / octave);
var octaveXFactor = x / octave - xi;
var octaveYFactor = y / octave - yi;
2020-01-11 22:34:10 +00:00
return Interpolation(
a: Interpolation(
a: this.RandomNumberGenerator(x: DeterminePatch(xi - 1, this.periodX), y: DeterminePatch(yi - 1 + 0, this.periodY)),
b: this.RandomNumberGenerator(x: DeterminePatch(xi + 0, this.periodX), y: DeterminePatch(yi - 1 + 0, this.periodY)),
c: this.RandomNumberGenerator(x: DeterminePatch(xi + 1, this.periodX), y: DeterminePatch(yi - 1 + 0, this.periodY)),
d: this.RandomNumberGenerator(x: DeterminePatch(xi + 2, this.periodX), y: DeterminePatch(yi - 1 + 0, this.periodY)),
2020-01-11 20:14:48 +00:00
x: octaveXFactor),
2020-01-11 22:34:10 +00:00
b: Interpolation(
a: this.RandomNumberGenerator(x: DeterminePatch(xi - 1, this.periodX), y: DeterminePatch(yi - 1 + 1, this.periodY)),
b: this.RandomNumberGenerator(x: DeterminePatch(xi + 0, this.periodX), y: DeterminePatch(yi - 1 + 1, this.periodY)),
c: this.RandomNumberGenerator(x: DeterminePatch(xi + 1, this.periodX), y: DeterminePatch(yi - 1 + 1, this.periodY)),
d: this.RandomNumberGenerator(x: DeterminePatch(xi + 2, this.periodX), y: DeterminePatch(yi - 1 + 1, this.periodY)),
2020-01-11 20:14:48 +00:00
x: octaveXFactor),
2020-01-11 22:34:10 +00:00
c: Interpolation(
a: this.RandomNumberGenerator(x: DeterminePatch(xi - 1, this.periodX), y: DeterminePatch(yi - 1 + 2, this.periodY)),
b: this.RandomNumberGenerator(x: DeterminePatch(xi + 0, this.periodX), y: DeterminePatch(yi - 1 + 2, this.periodY)),
c: this.RandomNumberGenerator(x: DeterminePatch(xi + 1, this.periodX), y: DeterminePatch(yi - 1 + 2, this.periodY)),
d: this.RandomNumberGenerator(x: DeterminePatch(xi + 2, this.periodX), y: DeterminePatch(yi - 1 + 2, this.periodY)),
2020-01-11 20:14:48 +00:00
x: octaveXFactor),
2020-01-11 22:34:10 +00:00
d: Interpolation(
a: this.RandomNumberGenerator(x: DeterminePatch(xi - 1, this.periodX), y: DeterminePatch(yi - 1 + 3, this.periodY)),
b: this.RandomNumberGenerator(x: DeterminePatch(xi + 0, this.periodX), y: DeterminePatch(yi - 1 + 3, this.periodY)),
c: this.RandomNumberGenerator(x: DeterminePatch(xi + 1, this.periodX), y: DeterminePatch(yi - 1 + 3, this.periodY)),
d: this.RandomNumberGenerator(x: DeterminePatch(xi + 2, this.periodX), y: DeterminePatch(yi - 1 + 3, this.periodY)),
2020-01-11 20:14:48 +00:00
x: octaveXFactor),
x: octaveYFactor) * 0.5f + 0.25f;
}
private float RandomNumberGenerator(int x, int y)
{
return (float)((((x ^ y) * RANDOM_NUMBER_A) ^ (this.seed + x)) * (((RANDOM_NUMBER_B * x) << 16) ^ (RANDOM_NUMBER_B * y) - RANDOM_NUMBER_A)) / int.MaxValue;
}
2020-01-11 22:34:10 +00:00
private static int DeterminePatch(int coordinate, int period)
2020-01-11 20:14:48 +00:00
{
return coordinate % period;
}
2020-01-11 22:34:10 +00:00
private static float Interpolation(float a, float b, float c, float d, float x)
2020-01-11 20:14:48 +00:00
{
var p = (d - c) - (a - b);
return x * (x * (x * p + ((a - b) - p)) + (c - a)) + b;
2020-01-11 18:00:46 +00:00
}
}
}