diff --git a/src/basics/FractalNoise.cpp b/src/basics/FractalNoise.cpp index d6bb376..e2371df 100644 --- a/src/basics/FractalNoise.cpp +++ b/src/basics/FractalNoise.cpp @@ -32,18 +32,33 @@ void FractalNoise::setRidge(double ridge_factor) this->ridge = ridge_factor; } +void FractalNoise::setState(const NoiseState &state) +{ + state.copy(&this->state); +} + double FractalNoise::get1d(double detail, double x) const { double current_scaling = scaling; double current_height = height; double result = 0.0; + int state_level_count = state.level_offsets.size(); + int i = 0; while (current_height >= detail) { - result += getBase1d(x * current_scaling) * current_height; + const NoiseState::NoiseOffset &offset = state.level_offsets[i]; + + result += getBase1d(offset.x + x * current_scaling) * current_height; current_scaling *= step_scaling; current_height *= step_height; + + i++; + if (i >= state_level_count) + { + i = 0; + } } return result; @@ -54,13 +69,23 @@ double FractalNoise::get2d(double detail, double x, double y) const double current_scaling = scaling; double current_height = height; double result = 0.0; + int state_level_count = state.level_offsets.size(); + int i = 0; while (current_height >= detail) { - result += getBase2d(x * current_scaling, y * current_scaling) * current_height; + const NoiseState::NoiseOffset &offset = state.level_offsets[i]; + + result += getBase2d(offset.x + x * current_scaling, offset.y + y * current_scaling) * current_height; current_scaling *= step_scaling; current_height *= step_height; + + i++; + if (i >= state_level_count) + { + i = 0; + } } return result; @@ -71,13 +96,23 @@ double FractalNoise::get3d(double detail, double x, double y, double z) const double current_scaling = scaling; double current_height = height; double result = 0.0; + int state_level_count = state.level_offsets.size(); + int i = 0; while (current_height >= detail) { - result += getBase3d(x * current_scaling, y * current_scaling, z * current_scaling) * current_height; + const NoiseState::NoiseOffset &offset = state.level_offsets[i]; + + result += getBase3d(offset.x + x * current_scaling, offset.y + y * current_scaling, offset.z + z * current_scaling) * current_height; current_scaling *= step_scaling; current_height *= step_height; + + i++; + if (i >= state_level_count) + { + i = 0; + } } return result; diff --git a/src/basics/FractalNoise.h b/src/basics/FractalNoise.h index 2057e64..10f8494 100644 --- a/src/basics/FractalNoise.h +++ b/src/basics/FractalNoise.h @@ -20,6 +20,7 @@ public: void setStep(double scaling_factor, double height_factor=1.0); void setSlope(double slope_factor); void setRidge(double ridge_factor); + void setState(const NoiseState &state); double get1d(double detail, double x) const; double get2d(double detail, double x, double y) const; diff --git a/src/basics/NoiseState.cpp b/src/basics/NoiseState.cpp index 3e870fd..64ee605 100644 --- a/src/basics/NoiseState.cpp +++ b/src/basics/NoiseState.cpp @@ -63,3 +63,14 @@ void NoiseState::resetOffsets(double x, double y, double z) level_offset.z = z; } } + +void NoiseState::setLevel(int level, double x, double y, double z) +{ + NoiseOffset offset = {x, y, z}; + level_offsets.at(level) = offset; +} + +void NoiseState::setLevelCount(int level_count) +{ + level_offsets.resize(level_count); +} diff --git a/src/basics/NoiseState.h b/src/basics/NoiseState.h index 528ddfb..c19b0ba 100644 --- a/src/basics/NoiseState.h +++ b/src/basics/NoiseState.h @@ -30,10 +30,14 @@ public: void randomizeOffsets(); void resetOffsets(double x=0.0, double y=0.0, double z=0.0); + void setLevel(int level, double x, double y, double z); + void setLevelCount(int level_count); + private: std::vector level_offsets; friend class NoiseGenerator; + friend class FractalNoise; }; } diff --git a/src/tests/FractalNoise_Test.cpp b/src/tests/FractalNoise_Test.cpp index 1834a20..6e4af79 100644 --- a/src/tests/FractalNoise_Test.cpp +++ b/src/tests/FractalNoise_Test.cpp @@ -7,6 +7,10 @@ class TestFractalNoise:public FractalNoise public: TestFractalNoise(double value=0.0):FractalNoise(), value(value) { + NoiseState state; + state.resetOffsets(); + setState(state); + calls = 0; } @@ -148,22 +152,74 @@ TEST(FractalNoise, StepScalingAndHeight) EXPECT_DOUBLE_EQ(1.8 + 0.7 + 0.3, result); } +TEST(FractalNoise, StateOffset) +{ + TestFractalNoise noise(0.8); + NoiseState state; + state.resetOffsets(0.2); + noise.setState(state); + + double result = noise.get1d(0.4, 1.0); + + ASSERT_EQ(2, noise.calls); + EXPECT_DOUBLE_EQ(2.0 + 1.5, result); +} + +TEST(FractalNoise, StateOffsetIter) +{ + TestFractalNoise noise(0.8); + NoiseState state; + state.setLevel(0, 0.1, 0.1, 0.1); + state.setLevel(1, 0.6, 0.6, 0.6); + noise.setState(state); + + double result = noise.get1d(0.4, 1.0); + + ASSERT_EQ(2, noise.calls); + EXPECT_DOUBLE_EQ(1.9 + 1.7, result); +} + +TEST(FractalNoise, StateOffsetLoop) +{ + TestFractalNoise noise(0.8); + NoiseState state; + state.setLevelCount(2); + state.setLevel(0, 0.1, 0.1, 0.1); + state.setLevel(1, 0.6, 0.6, 0.6); + noise.setState(state); + + double result = noise.get1d(0.2, 1.0); + + ASSERT_EQ(3, noise.calls); + EXPECT_DOUBLE_EQ(1.9 + 1.7 + 1.225, result); +} + TEST(FractalNoise, Noise2d) { TestFractalNoise noise(0.8); + NoiseState state; + state.setLevelCount(2); + state.setLevel(0, 0.1, 0.2, 0.3); + state.setLevel(1, 0.6, 0.7, 0.8); + noise.setState(state); double result = noise.get2d(0.4, 1.0, 0.5); ASSERT_EQ(2, noise.calls); - EXPECT_DOUBLE_EQ(2.3 + 1.9, result); + EXPECT_DOUBLE_EQ(2.6 + 2.55, result); } TEST(FractalNoise, Noise3d) { TestFractalNoise noise(0.8); + NoiseState state; + state.setLevelCount(2); + state.setLevel(0, 0.1, 0.2, 0.3); + state.setLevel(1, 0.6, 0.7, 0.8); + noise.setState(state); 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); + EXPECT_DOUBLE_EQ(3.2 + 3.25, result); }