diff --git a/src/rendering/noise.c b/src/rendering/noise.c index 60b652f..0baa57e 100644 --- a/src/rendering/noise.c +++ b/src/rendering/noise.c @@ -229,6 +229,13 @@ void noiseSetFunction(NoiseGenerator* generator, NoiseFunction* function) noiseValidate(generator); } +void noiseSetCustomFunction(NoiseGenerator* generator, double (*func1d)(double x), double (*func2d)(double x, double y), double (*func3d)(double x, double y, double z)) +{ + generator->_func_noise_1d = func1d; + generator->_func_noise_2d = func2d; + generator->_func_noise_3d = func3d; +} + void noiseSetFunctionParams(NoiseGenerator* generator, NoiseFunctionAlgorithm algorithm, double ridge_factor, double curve_factor) { NoiseFunction function = {algorithm, ridge_factor, curve_factor}; diff --git a/src/rendering/noise.h b/src/rendering/noise.h index 5a30114..a8dea1a 100644 --- a/src/rendering/noise.h +++ b/src/rendering/noise.h @@ -46,6 +46,7 @@ void noiseCopy(NoiseGenerator* source, NoiseGenerator* destination); void noiseValidate(NoiseGenerator* generator); void noiseRandomizeOffsets(NoiseGenerator* generator); NoiseFunction noiseGetFunction(NoiseGenerator* generator); +void noiseSetCustomFunction(NoiseGenerator* generator, double (*func1d)(double x), double (*func2d)(double x, double y), double (*func3d)(double x, double y, double z)); void noiseSetFunction(NoiseGenerator* generator, NoiseFunction* function); void noiseSetFunctionParams(NoiseGenerator* generator, NoiseFunctionAlgorithm algorithm, double ridge_factor, double curve_factor); void noiseForceValue(NoiseGenerator* generator, double value); diff --git a/src/testing/main.c b/src/testing/main.c index 78b74d9..10ca434 100644 --- a/src/testing/main.c +++ b/src/testing/main.c @@ -7,6 +7,7 @@ extern void test_euclid_case(Suite* s); extern void test_camera_case(Suite* s); extern void test_clouds_case(Suite* s); extern void test_noise_case(Suite* s); +extern void test_terrain_painting_case(Suite* s); int main(int argc, char** argv) { @@ -20,6 +21,7 @@ int main(int argc, char** argv) test_camera_case(s); test_clouds_case(s); test_noise_case(s); + test_terrain_painting_case(s); SRunner *sr = srunner_create(s); srunner_run_all(sr, CK_NORMAL); diff --git a/src/testing/test_terrain_painting.c b/src/testing/test_terrain_painting.c new file mode 100644 index 0000000..c7750a7 --- /dev/null +++ b/src/testing/test_terrain_painting.c @@ -0,0 +1,95 @@ +#include "testing/common.h" + +#include +#include "rendering/tools.h" +#include "rendering/terrain/public.h" + +/* Noise sin period is defined at 20.0 */ +#define X_FACTOR (M_PI / 10.0) + +static double _noise1dMock(double x) +{ + return sin(x * X_FACTOR) * 0.5 + 0.5; +} + +static double _noise2dMock(double x, double y) +{ + UNUSED(y); + return sin(x * X_FACTOR) * 0.5 + 0.5; +} + +static double _noise3dMock(double x, double y, double z) +{ + UNUSED(y); + UNUSED(z); + return sin(x * X_FACTOR) * 0.5 + 0.5; +} + +static TerrainDefinition* _setUpDefinition() +{ + TerrainDefinition* terrain = (TerrainDefinition*)TerrainDefinitionClass.create(); + terrain->height = 3.0; + terrain->scaling = 1.0; + noiseClearLevels(terrain->_height_noise); + NoiseLevel level = {1.0, 2.0, -1.0, 0.0, 0.0, 0.0}; + noiseAddLevel(terrain->_height_noise, level, 0); + noiseSetCustomFunction(terrain->_height_noise, _noise1dMock, _noise2dMock, _noise3dMock); + return terrain; +} + +static void _tearDownDefinition(TerrainDefinition* terrain) +{ + TerrainDefinitionClass.destroy(terrain); +} + +START_TEST(test_terrain_painting_grid) +{ + /* Set up */ + TerrainDefinition* terrain = _setUpDefinition(); + + /* Test base grid */ + ck_assert_double_eq(terrainGetGridHeight(terrain, 0, 0, 0), 0.0); + ck_assert_double_eq(terrainGetGridHeight(terrain, 0, 1, 0), 0.0); + ck_assert_double_eq(terrainGetGridHeight(terrain, 0, 0, 1), 0.0); + ck_assert_double_eq(terrainGetGridHeight(terrain, 1, 0, 0), sin(1.0 * X_FACTOR)); + ck_assert_double_eq(terrainGetGridHeight(terrain, 2, 0, 0), sin(2.0 * X_FACTOR)); + ck_assert_double_eq(terrainGetGridHeight(terrain, 3, 0, 0), sin(3.0 * X_FACTOR)); + ck_assert_double_eq(terrainGetGridHeight(terrain, 4, 0, 0), sin(4.0 * X_FACTOR)); + ck_assert_double_eq(terrainGetGridHeight(terrain, 5, 0, 0), 1.0); + ck_assert_double_eq(terrainGetGridHeight(terrain, 6, 0, 0), sin(4.0 * X_FACTOR)); + ck_assert_double_eq(terrainGetGridHeight(terrain, -1, 0, 0), -sin(1.0 * X_FACTOR)); + ck_assert_double_eq(terrainGetGridHeight(terrain, 10, 0, 0), 0.0); + ck_assert_double_eq(terrainGetGridHeight(terrain, 15, 0, 0), -1.0); + ck_assert_double_eq(terrainGetGridHeight(terrain, 20, 0, 0), 0.0); + ck_assert_double_eq(terrainGetGridHeight(terrain, -5, 0, 0), -1.0); + + /* Test interpolated result */ + ck_assert_double_eq(terrainGetInterpolatedHeight(terrain, 0.0, 0.0, 0, 0), 0.0); + ck_assert_double_in_range(terrainGetInterpolatedHeight(terrain, 0.5, 0.0, 0, 0), 0.1564, 0.1566); + ck_assert_double_eq(terrainGetInterpolatedHeight(terrain, 1.0, 0.0, 0, 0), sin(1.0 * X_FACTOR)); + ck_assert_double_eq(terrainGetInterpolatedHeight(terrain, 0.0, 0.0, 1, 0), 0.0); + ck_assert_double_in_range(terrainGetInterpolatedHeight(terrain, 0.5, 0.0, 1, 0), 3.0 * 0.1564, 3.0 * 0.1566); + ck_assert_double_eq(terrainGetInterpolatedHeight(terrain, 1.0, 0.0, 1, 0), 3.0 * sin(1.0 * X_FACTOR)); + + /* Test scaling */ + terrain->scaling = 2.0; + ck_assert_double_eq(terrainGetGridHeight(terrain, 0, 0, 0), 0.0); + ck_assert_double_eq(terrainGetGridHeight(terrain, 1, 0, 0), sin(1.0 * X_FACTOR)); + ck_assert_double_eq(terrainGetGridHeight(terrain, 2, 0, 0), sin(2.0 * X_FACTOR)); + ck_assert_double_eq(terrainGetGridHeight(terrain, 3, 0, 0), sin(3.0 * X_FACTOR)); + ck_assert_double_eq(terrainGetInterpolatedHeight(terrain, 0, 0, 0, 0), 0.0); + ck_assert_double_eq(terrainGetInterpolatedHeight(terrain, 1, 0, 0, 0), sin(0.5 * X_FACTOR)); + ck_assert_double_eq(terrainGetInterpolatedHeight(terrain, 2, 0, 0, 0), sin(1.0 * X_FACTOR)); + ck_assert_double_eq(terrainGetInterpolatedHeight(terrain, 3, 0, 0, 0), sin(1.5 * X_FACTOR)); + ck_assert_double_eq(terrainGetInterpolatedHeight(terrain, 0, 0, 1, 0), 0.0); + ck_assert_double_eq(terrainGetInterpolatedHeight(terrain, 1, 0, 1, 0), 6.0 * sin(0.5 * X_FACTOR)); + ck_assert_double_eq(terrainGetInterpolatedHeight(terrain, 2, 0, 1, 0), 6.0 * sin(1.0 * X_FACTOR)); + ck_assert_double_eq(terrainGetInterpolatedHeight(terrain, 3, 0, 1, 0), 6.0 * sin(1.5 * X_FACTOR)); + + /* Tear down */ + _tearDownDefinition(terrain); +} +END_TEST + +TEST_CASE(terrain_painting, test_terrain_painting_grid) +