diff --git a/src/basics/FractalNoise.cpp b/src/basics/FractalNoise.cpp new file mode 100644 index 0000000..d6bb376 --- /dev/null +++ b/src/basics/FractalNoise.cpp @@ -0,0 +1,94 @@ +#include "FractalNoise.h" + +FractalNoise::FractalNoise() +{ + scaling = 1.0; + height = 1.0; + step_scaling = 2.0; + step_height = 0.5; + slope = 0.0; + ridge = 0.0; +} + +void FractalNoise::setScaling(double scaling, double height) +{ + this->scaling = scaling < 0.00000001 ? 0.0 : 1.0 / scaling; + this->height = scaling * height; +} + +void FractalNoise::setStep(double scaling_factor, double height_factor) +{ + this->step_scaling = scaling_factor < 0.00000001 ? 0.0 : 1.0 / scaling_factor; + this->step_height = scaling_factor * height_factor; +} + +void FractalNoise::setSlope(double slope_factor) +{ + this->slope = slope_factor; +} + +void FractalNoise::setRidge(double ridge_factor) +{ + this->ridge = ridge_factor; +} + +double FractalNoise::get1d(double detail, double x) const +{ + double current_scaling = scaling; + double current_height = height; + double result = 0.0; + + while (current_height >= detail) + { + result += getBase1d(x * current_scaling) * current_height; + + current_scaling *= step_scaling; + current_height *= step_height; + } + + return result; +} + +double FractalNoise::get2d(double detail, double x, double y) const +{ + double current_scaling = scaling; + double current_height = height; + double result = 0.0; + + while (current_height >= detail) + { + result += getBase2d(x * current_scaling, y * current_scaling) * current_height; + + current_scaling *= step_scaling; + current_height *= step_height; + } + + return result; +} + +double FractalNoise::get3d(double detail, double x, double y, double z) const +{ + double current_scaling = scaling; + double current_height = height; + double result = 0.0; + + while (current_height >= detail) + { + result += getBase3d(x * current_scaling, y * current_scaling, z * current_scaling) * current_height; + + current_scaling *= step_scaling; + current_height *= step_height; + } + + return result; +} + +double FractalNoise::getBase1d(double x) const +{ + return getBase2d(x, 0.0); +} + +double FractalNoise::getBase2d(double x, double y) const +{ + return getBase3d(x, y, 0.0); +} diff --git a/src/basics/FractalNoise.h b/src/basics/FractalNoise.h new file mode 100644 index 0000000..2057e64 --- /dev/null +++ b/src/basics/FractalNoise.h @@ -0,0 +1,46 @@ +#ifndef FRACTALNOISE_H +#define FRACTALNOISE_H + +#include "basics_global.h" + +#include "NoiseState.h" + +namespace paysages { +namespace basics { + +/*! + * \brief Fractal noise generator, based on a sum of simple noise functions. + */ +class BASICSSHARED_EXPORT FractalNoise +{ +public: + FractalNoise(); + + void setScaling(double scaling, double height=1.0); + void setStep(double scaling_factor, double height_factor=1.0); + void setSlope(double slope_factor); + void setRidge(double ridge_factor); + + double get1d(double detail, double x) const; + double get2d(double detail, double x, double y) const; + double get3d(double detail, double x, double y, double z) const; + + virtual double getBase1d(double x) const; + virtual double getBase2d(double x, double y) const; + virtual double getBase3d(double x, double y, double z) const = 0; + +private: + NoiseState state; + + double scaling; + double height; + double step_scaling; + double step_height; + double slope; + double ridge; +}; + +} +} + +#endif // FRACTALNOISE_H diff --git a/src/basics/basics.pro b/src/basics/basics.pro index 9a2c901..bc03fe0 100644 --- a/src/basics/basics.pro +++ b/src/basics/basics.pro @@ -32,7 +32,8 @@ SOURCES += \ Texture2D.cpp \ Texture3D.cpp \ Texture4D.cpp \ - NoiseState.cpp + NoiseState.cpp \ + FractalNoise.cpp HEADERS +=\ basics_global.h \ @@ -52,7 +53,8 @@ HEADERS +=\ Texture2D.h \ Texture3D.h \ Texture4D.h \ - NoiseState.h + NoiseState.h \ + FractalNoise.h unix:!symbian { maemo5 { diff --git a/src/basics/basics_global.h b/src/basics/basics_global.h index db81286..4ea3e7c 100644 --- a/src/basics/basics_global.h +++ b/src/basics/basics_global.h @@ -19,6 +19,7 @@ namespace basics { class Color; class NoiseGenerator; class NoiseState; + class FractalNoise; class Curve; class ColorProfile; class Texture2D; diff --git a/src/tests/Bruneton_Test.cpp b/src/tests/Bruneton_Test.cpp index f51c999..70d49d9 100644 --- a/src/tests/Bruneton_Test.cpp +++ b/src/tests/Bruneton_Test.cpp @@ -18,6 +18,9 @@ static Color _postProcessFragment(SoftwareRenderer* renderer, const Vector3 &loc TEST(Bruneton, AerialPerspective1) { +#ifndef TESTS_FULL + return; +#endif Scenery scenery; SoftwareRenderer renderer(&scenery); renderer.render_width = 800; @@ -45,6 +48,9 @@ TEST(Bruneton, AerialPerspective1) TEST(Bruneton, AerialPerspective2) { +#ifndef TESTS_FULL + return; +#endif Scenery scenery; AtmosphereDefinition* atmo = scenery.getAtmosphere(); diff --git a/src/tests/FractalNoise_Test.cpp b/src/tests/FractalNoise_Test.cpp new file mode 100644 index 0000000..1834a20 --- /dev/null +++ b/src/tests/FractalNoise_Test.cpp @@ -0,0 +1,169 @@ +#include "BaseTestCase.h" + +#include "FractalNoise.h" + +class TestFractalNoise:public FractalNoise +{ +public: + TestFractalNoise(double value=0.0):FractalNoise(), value(value) + { + calls = 0; + } + + virtual double getBase3d(double x, double y, double z) const override + { + ((TestFractalNoise*)this)->calls++; + return value + x + y + z; + } + +public: + int calls; +private: + double value; +}; + +TEST(FractalNoise, AutoBase2d) +{ + TestFractalNoise noise(0.2); + + double result = noise.getBase2d(0.4, 0.1); + + ASSERT_EQ(1, noise.calls); + EXPECT_DOUBLE_EQ(0.7, result); +} + +TEST(FractalNoise, AutoBase1d) +{ + TestFractalNoise noise(0.2); + + double result = noise.getBase1d(0.4); + + ASSERT_EQ(1, noise.calls); + EXPECT_DOUBLE_EQ(0.6, result); +} + +TEST(FractalNoise, NoStep) +{ + TestFractalNoise noise(0.1); + + double result = noise.get1d(1.1, 1.0); + + ASSERT_EQ(0, noise.calls); + EXPECT_DOUBLE_EQ(0.0, result); +} + +TEST(FractalNoise, SingleStep) +{ + TestFractalNoise noise(0.1); + + double result = noise.get1d(0.7, 1.0); + + ASSERT_EQ(1, noise.calls); + EXPECT_DOUBLE_EQ(1.1, result); +} + +TEST(FractalNoise, Sum2Steps) +{ + TestFractalNoise noise(0.1); + + double result = noise.get1d(0.3, 1.0); + + ASSERT_EQ(2, noise.calls); + EXPECT_DOUBLE_EQ(1.1 + 1.05, result); +} + +TEST(FractalNoise, Sum3Steps) +{ + TestFractalNoise noise(0.1); + + double result = noise.get1d(0.2, 1.0); + + ASSERT_EQ(3, noise.calls); + EXPECT_DOUBLE_EQ(1.1 + 1.05 + 1.025, result); +} + +TEST(FractalNoise, InitialScaling) +{ + TestFractalNoise noise(0.8); + noise.setScaling(0.5); + + double result = noise.get1d(0.2, 1.0); + + ASSERT_EQ(2, noise.calls); + EXPECT_DOUBLE_EQ(1.4 + 1.2, result); +} + +TEST(FractalNoise, InitialHeight) +{ + TestFractalNoise noise(0.8); + noise.setScaling(1.0, 0.5); + + double result = noise.get1d(0.2, 1.0); + + ASSERT_EQ(2, noise.calls); + EXPECT_DOUBLE_EQ(0.9 + 0.7, result); +} + +TEST(FractalNoise, InitialScalingAndHeight) +{ + TestFractalNoise noise(0.8); + noise.setScaling(0.5, 0.5); + + double result = noise.get1d(0.1, 1.0); + + ASSERT_EQ(2, noise.calls); + EXPECT_DOUBLE_EQ(0.7 + 0.6, result); +} + +TEST(FractalNoise, StepScaling) +{ + TestFractalNoise noise(0.1); + noise.setStep(0.8); + + double result = noise.get1d(0.55, 1.0); + + ASSERT_EQ(3, noise.calls); + EXPECT_DOUBLE_EQ(1.1 + 1.08 + 1.064, result); +} + +TEST(FractalNoise, StepHeight) +{ + TestFractalNoise noise(0.1); + noise.setStep(0.5, 0.8); + + double result = noise.get1d(0.4, 1.0); + + ASSERT_EQ(2, noise.calls); + EXPECT_DOUBLE_EQ(1.1 + 0.84, result); +} + +TEST(FractalNoise, StepScalingAndHeight) +{ + TestFractalNoise noise(0.8); + noise.setStep(0.5, 0.5); + + double result = noise.get1d(0.05, 1.0); + + ASSERT_EQ(3, noise.calls); + EXPECT_DOUBLE_EQ(1.8 + 0.7 + 0.3, result); +} + +TEST(FractalNoise, Noise2d) +{ + TestFractalNoise noise(0.8); + + double result = noise.get2d(0.4, 1.0, 0.5); + + ASSERT_EQ(2, noise.calls); + EXPECT_DOUBLE_EQ(2.3 + 1.9, result); +} + +TEST(FractalNoise, Noise3d) +{ + TestFractalNoise noise(0.8); + + double result = noise.get3d(0.4, 1.0, 0.5, 0.3); + + ASSERT_EQ(2, noise.calls); + EXPECT_DOUBLE_EQ(2.6 + 2.2, result); +} diff --git a/src/tests/Render_Test.cpp b/src/tests/Render_Test.cpp index 21b775d..e1914fb 100644 --- a/src/tests/Render_Test.cpp +++ b/src/tests/Render_Test.cpp @@ -51,6 +51,9 @@ static void _render_quad_checker(SoftwareRenderer &renderer) TEST(Render, quad) { +#ifndef TESTS_FULL + return; +#endif SoftwareRenderer renderer; renderer.render_camera->setLocationCoords(0.0, 0.5, 2.0); @@ -73,6 +76,9 @@ TEST(Render, quad) TEST(Render, quad_cut) { +#ifndef TESTS_FULL + return; +#endif SoftwareRenderer renderer; renderer.render_camera->setLocationCoords(0.8, 0.7, 1.0); diff --git a/src/tests/tests.pro b/src/tests/tests.pro index 2e638f3..378272f 100644 --- a/src/tests/tests.pro +++ b/src/tests/tests.pro @@ -18,7 +18,8 @@ SOURCES += main.cpp \ Camera_Test.cpp \ Clouds_Test.cpp \ FluidMediumManager_Test.cpp \ - VertexArray_Test.cpp + VertexArray_Test.cpp \ + FractalNoise_Test.cpp HEADERS += \ BaseTestCase.h