Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/noise/tests/test_fastnoise_lite.h
10278 views
1
/**************************************************************************/
2
/* test_fastnoise_lite.h */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#pragma once
32
33
#include "../fastnoise_lite.h"
34
35
#include "tests/test_macros.h"
36
37
namespace TestFastNoiseLite {
38
39
// Uitility functions for finding differences in noise generation
40
41
bool all_equal_approx(const Vector<real_t> &p_values_1, const Vector<real_t> &p_values_2) {
42
ERR_FAIL_COND_V_MSG(p_values_1.size() != p_values_2.size(), false, "Arrays must be the same size. This is a error in the test code.");
43
44
for (int i = 0; i < p_values_1.size(); i++) {
45
if (!Math::is_equal_approx(p_values_1[i], p_values_2[i])) {
46
return false;
47
}
48
}
49
return true;
50
}
51
52
Vector<Pair<size_t, size_t>> find_approx_equal_vec_pairs(std::initializer_list<Vector<real_t>> inputs) {
53
Vector<Vector<real_t>> p_array = Vector<Vector<real_t>>(inputs);
54
55
Vector<Pair<size_t, size_t>> result;
56
for (int i = 0; i < p_array.size(); i++) {
57
for (int j = i + 1; j < p_array.size(); j++) {
58
if (all_equal_approx(p_array[i], p_array[j])) {
59
result.push_back(Pair<size_t, size_t>(i, j));
60
}
61
}
62
}
63
return result;
64
}
65
66
#define CHECK_ARGS_APPROX_PAIRWISE_DISTINCT_VECS(...) \
67
{ \
68
Vector<Pair<size_t, size_t>> equal_pairs = find_approx_equal_vec_pairs({ __VA_ARGS__ }); \
69
for (Pair<size_t, size_t> p : equal_pairs) { \
70
MESSAGE("Argument with index ", p.first, " is approximately equal to argument with index ", p.second); \
71
} \
72
CHECK_MESSAGE(equal_pairs.size() == 0, "All arguments should be pairwise distinct."); \
73
}
74
75
Vector<real_t> get_noise_samples_1d(const FastNoiseLite &p_noise, size_t p_count = 32) {
76
Vector<real_t> result;
77
result.resize(p_count);
78
for (size_t i = 0; i < p_count; i++) {
79
result.write[i] = p_noise.get_noise_1d(i);
80
}
81
return result;
82
}
83
84
Vector<real_t> get_noise_samples_2d(const FastNoiseLite &p_noise, size_t p_count = 32) {
85
Vector<real_t> result;
86
result.resize(p_count);
87
for (size_t i = 0; i < p_count; i++) {
88
result.write[i] = p_noise.get_noise_2d(i, i);
89
}
90
return result;
91
}
92
93
Vector<real_t> get_noise_samples_3d(const FastNoiseLite &p_noise, size_t p_count = 32) {
94
Vector<real_t> result;
95
result.resize(p_count);
96
for (size_t i = 0; i < p_count; i++) {
97
result.write[i] = p_noise.get_noise_3d(i, i, i);
98
}
99
return result;
100
}
101
102
// The following test suite is rather for testing the wrapper code than the actual noise generation.
103
104
TEST_CASE("[FastNoiseLite] Getter and setter") {
105
FastNoiseLite noise;
106
107
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_SIMPLEX_SMOOTH);
108
CHECK(noise.get_noise_type() == FastNoiseLite::NoiseType::TYPE_SIMPLEX_SMOOTH);
109
110
noise.set_seed(123);
111
CHECK(noise.get_seed() == 123);
112
113
noise.set_frequency(0.123);
114
CHECK(noise.get_frequency() == doctest::Approx(0.123));
115
116
noise.set_offset(Vector3(1, 2, 3));
117
CHECK(noise.get_offset() == Vector3(1, 2, 3));
118
119
noise.set_fractal_type(FastNoiseLite::FractalType::FRACTAL_PING_PONG);
120
CHECK(noise.get_fractal_type() == FastNoiseLite::FractalType::FRACTAL_PING_PONG);
121
122
noise.set_fractal_octaves(2);
123
CHECK(noise.get_fractal_octaves() == 2);
124
125
noise.set_fractal_lacunarity(1.123);
126
CHECK(noise.get_fractal_lacunarity() == doctest::Approx(1.123));
127
128
noise.set_fractal_gain(0.123);
129
CHECK(noise.get_fractal_gain() == doctest::Approx(0.123));
130
131
noise.set_fractal_weighted_strength(0.123);
132
CHECK(noise.get_fractal_weighted_strength() == doctest::Approx(0.123));
133
134
noise.set_fractal_ping_pong_strength(0.123);
135
CHECK(noise.get_fractal_ping_pong_strength() == doctest::Approx(0.123));
136
137
noise.set_cellular_distance_function(FastNoiseLite::CellularDistanceFunction::DISTANCE_MANHATTAN);
138
CHECK(noise.get_cellular_distance_function() == FastNoiseLite::CellularDistanceFunction::DISTANCE_MANHATTAN);
139
140
noise.set_cellular_return_type(FastNoiseLite::CellularReturnType::RETURN_DISTANCE2_SUB);
141
CHECK(noise.get_cellular_return_type() == FastNoiseLite::CellularReturnType::RETURN_DISTANCE2_SUB);
142
143
noise.set_cellular_jitter(0.123);
144
CHECK(noise.get_cellular_jitter() == doctest::Approx(0.123));
145
146
noise.set_domain_warp_enabled(true);
147
CHECK(noise.is_domain_warp_enabled() == true);
148
noise.set_domain_warp_enabled(false);
149
CHECK(noise.is_domain_warp_enabled() == false);
150
151
noise.set_domain_warp_type(FastNoiseLite::DomainWarpType::DOMAIN_WARP_SIMPLEX_REDUCED);
152
CHECK(noise.get_domain_warp_type() == FastNoiseLite::DomainWarpType::DOMAIN_WARP_SIMPLEX_REDUCED);
153
154
noise.set_domain_warp_amplitude(0.123);
155
CHECK(noise.get_domain_warp_amplitude() == doctest::Approx(0.123));
156
157
noise.set_domain_warp_frequency(0.123);
158
CHECK(noise.get_domain_warp_frequency() == doctest::Approx(0.123));
159
160
noise.set_domain_warp_fractal_type(FastNoiseLite::DomainWarpFractalType::DOMAIN_WARP_FRACTAL_INDEPENDENT);
161
CHECK(noise.get_domain_warp_fractal_type() == FastNoiseLite::DomainWarpFractalType::DOMAIN_WARP_FRACTAL_INDEPENDENT);
162
163
noise.set_domain_warp_fractal_octaves(2);
164
CHECK(noise.get_domain_warp_fractal_octaves() == 2);
165
166
noise.set_domain_warp_fractal_lacunarity(1.123);
167
CHECK(noise.get_domain_warp_fractal_lacunarity() == doctest::Approx(1.123));
168
169
noise.set_domain_warp_fractal_gain(0.123);
170
CHECK(noise.get_domain_warp_fractal_gain() == doctest::Approx(0.123));
171
}
172
173
TEST_CASE("[FastNoiseLite] Basic noise generation") {
174
FastNoiseLite noise;
175
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_SIMPLEX);
176
noise.set_fractal_type(FastNoiseLite::FractalType::FRACTAL_NONE);
177
noise.set_seed(123);
178
noise.set_offset(Vector3(10, 10, 10));
179
180
// 1D noise will be checked just in the cases where there's the possibility of
181
// finding a bug/regression in the wrapper function.
182
// (since it uses FastNoise's 2D noise generator with the Y coordinate set to 0).
183
184
SUBCASE("Determinacy of noise generation (all noise types)") {
185
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_SIMPLEX);
186
CHECK(noise.get_noise_2d(0, 0) == doctest::Approx(noise.get_noise_2d(0, 0)));
187
CHECK(noise.get_noise_3d(0, 0, 0) == doctest::Approx(noise.get_noise_3d(0, 0, 0)));
188
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_SIMPLEX_SMOOTH);
189
CHECK(noise.get_noise_2d(0, 0) == doctest::Approx(noise.get_noise_2d(0, 0)));
190
CHECK(noise.get_noise_3d(0, 0, 0) == doctest::Approx(noise.get_noise_3d(0, 0, 0)));
191
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_CELLULAR);
192
CHECK(noise.get_noise_2d(0, 0) == doctest::Approx(noise.get_noise_2d(0, 0)));
193
CHECK(noise.get_noise_3d(0, 0, 0) == doctest::Approx(noise.get_noise_3d(0, 0, 0)));
194
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_PERLIN);
195
CHECK(noise.get_noise_2d(0, 0) == doctest::Approx(noise.get_noise_2d(0, 0)));
196
CHECK(noise.get_noise_3d(0, 0, 0) == doctest::Approx(noise.get_noise_3d(0, 0, 0)));
197
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_VALUE);
198
CHECK(noise.get_noise_2d(0, 0) == doctest::Approx(noise.get_noise_2d(0, 0)));
199
CHECK(noise.get_noise_3d(0, 0, 0) == doctest::Approx(noise.get_noise_3d(0, 0, 0)));
200
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_VALUE_CUBIC);
201
CHECK(noise.get_noise_2d(0, 0) == doctest::Approx(noise.get_noise_2d(0, 0)));
202
CHECK(noise.get_noise_3d(0, 0, 0) == doctest::Approx(noise.get_noise_3d(0, 0, 0)));
203
}
204
205
SUBCASE("Different seeds should produce different noise") {
206
noise.set_seed(456);
207
Vector<real_t> noise_seed_1_1d = get_noise_samples_1d(noise);
208
Vector<real_t> noise_seed_1_2d = get_noise_samples_2d(noise);
209
Vector<real_t> noise_seed_1_3d = get_noise_samples_3d(noise);
210
noise.set_seed(123);
211
Vector<real_t> noise_seed_2_1d = get_noise_samples_1d(noise);
212
Vector<real_t> noise_seed_2_2d = get_noise_samples_2d(noise);
213
Vector<real_t> noise_seed_2_3d = get_noise_samples_3d(noise);
214
215
CHECK_FALSE(all_equal_approx(noise_seed_1_1d, noise_seed_2_1d));
216
CHECK_FALSE(all_equal_approx(noise_seed_1_2d, noise_seed_2_2d));
217
CHECK_FALSE(all_equal_approx(noise_seed_1_3d, noise_seed_2_3d));
218
}
219
220
SUBCASE("Different frequencies should produce different noise") {
221
noise.set_frequency(0.1);
222
Vector<real_t> noise_frequency_1_1d = get_noise_samples_1d(noise);
223
Vector<real_t> noise_frequency_1_2d = get_noise_samples_2d(noise);
224
Vector<real_t> noise_frequency_1_3d = get_noise_samples_3d(noise);
225
noise.set_frequency(1.0);
226
Vector<real_t> noise_frequency_2_1d = get_noise_samples_1d(noise);
227
Vector<real_t> noise_frequency_2_2d = get_noise_samples_2d(noise);
228
Vector<real_t> noise_frequency_2_3d = get_noise_samples_3d(noise);
229
230
CHECK_FALSE(all_equal_approx(noise_frequency_1_1d, noise_frequency_2_1d));
231
CHECK_FALSE(all_equal_approx(noise_frequency_1_2d, noise_frequency_2_2d));
232
CHECK_FALSE(all_equal_approx(noise_frequency_1_3d, noise_frequency_2_3d));
233
}
234
235
SUBCASE("Noise should be offset by the offset parameter") {
236
noise.set_offset(Vector3(1, 2, 3));
237
Vector<real_t> noise_offset_1_1d = get_noise_samples_1d(noise);
238
Vector<real_t> noise_offset_1_2d = get_noise_samples_2d(noise);
239
Vector<real_t> noise_offset_1_3d = get_noise_samples_3d(noise);
240
noise.set_offset(Vector3(4, 5, 6));
241
Vector<real_t> noise_offset_2_1d = get_noise_samples_1d(noise);
242
Vector<real_t> noise_offset_2_2d = get_noise_samples_2d(noise);
243
Vector<real_t> noise_offset_2_3d = get_noise_samples_3d(noise);
244
245
CHECK_FALSE(all_equal_approx(noise_offset_1_1d, noise_offset_2_1d));
246
CHECK_FALSE(all_equal_approx(noise_offset_1_2d, noise_offset_2_2d));
247
CHECK_FALSE(all_equal_approx(noise_offset_1_3d, noise_offset_2_3d));
248
}
249
250
SUBCASE("Different noise types should produce different noise") {
251
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_SIMPLEX);
252
Vector<real_t> noise_type_simplex_2d = get_noise_samples_2d(noise);
253
Vector<real_t> noise_type_simplex_3d = get_noise_samples_3d(noise);
254
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_SIMPLEX_SMOOTH);
255
Vector<real_t> noise_type_simplex_smooth_2d = get_noise_samples_2d(noise);
256
Vector<real_t> noise_type_simplex_smooth_3d = get_noise_samples_3d(noise);
257
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_CELLULAR);
258
Vector<real_t> noise_type_cellular_2d = get_noise_samples_2d(noise);
259
Vector<real_t> noise_type_cellular_3d = get_noise_samples_3d(noise);
260
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_PERLIN);
261
Vector<real_t> noise_type_perlin_2d = get_noise_samples_2d(noise);
262
Vector<real_t> noise_type_perlin_3d = get_noise_samples_3d(noise);
263
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_VALUE);
264
Vector<real_t> noise_type_value_2d = get_noise_samples_2d(noise);
265
Vector<real_t> noise_type_value_3d = get_noise_samples_3d(noise);
266
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_VALUE_CUBIC);
267
Vector<real_t> noise_type_value_cubic_2d = get_noise_samples_2d(noise);
268
Vector<real_t> noise_type_value_cubic_3d = get_noise_samples_3d(noise);
269
270
CHECK_ARGS_APPROX_PAIRWISE_DISTINCT_VECS(noise_type_simplex_2d,
271
noise_type_simplex_smooth_2d,
272
noise_type_cellular_2d,
273
noise_type_perlin_2d,
274
noise_type_value_2d,
275
noise_type_value_cubic_2d);
276
277
CHECK_ARGS_APPROX_PAIRWISE_DISTINCT_VECS(noise_type_simplex_3d,
278
noise_type_simplex_smooth_3d,
279
noise_type_cellular_3d,
280
noise_type_perlin_3d,
281
noise_type_value_3d,
282
noise_type_value_cubic_3d);
283
}
284
}
285
286
TEST_CASE("[FastNoiseLite] Fractal noise") {
287
FastNoiseLite noise;
288
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_SIMPLEX);
289
noise.set_offset(Vector3(10, 10, 10));
290
noise.set_frequency(0.01);
291
noise.set_fractal_type(FastNoiseLite::FractalType::FRACTAL_FBM);
292
noise.set_fractal_octaves(4);
293
noise.set_fractal_lacunarity(2.0);
294
noise.set_fractal_gain(0.5);
295
noise.set_fractal_weighted_strength(0.5);
296
noise.set_fractal_ping_pong_strength(2.0);
297
298
SUBCASE("Different fractal types should produce different results") {
299
noise.set_fractal_type(FastNoiseLite::FractalType::FRACTAL_NONE);
300
Vector<real_t> fractal_type_none_2d = get_noise_samples_2d(noise);
301
Vector<real_t> fractal_type_none_3d = get_noise_samples_3d(noise);
302
noise.set_fractal_type(FastNoiseLite::FractalType::FRACTAL_FBM);
303
Vector<real_t> fractal_type_fbm_2d = get_noise_samples_2d(noise);
304
Vector<real_t> fractal_type_fbm_3d = get_noise_samples_3d(noise);
305
noise.set_fractal_type(FastNoiseLite::FractalType::FRACTAL_RIDGED);
306
Vector<real_t> fractal_type_ridged_2d = get_noise_samples_2d(noise);
307
Vector<real_t> fractal_type_ridged_3d = get_noise_samples_3d(noise);
308
noise.set_fractal_type(FastNoiseLite::FractalType::FRACTAL_PING_PONG);
309
Vector<real_t> fractal_type_ping_pong_2d = get_noise_samples_2d(noise);
310
Vector<real_t> fractal_type_ping_pong_3d = get_noise_samples_3d(noise);
311
312
CHECK_ARGS_APPROX_PAIRWISE_DISTINCT_VECS(fractal_type_none_2d,
313
fractal_type_fbm_2d,
314
fractal_type_ridged_2d,
315
fractal_type_ping_pong_2d);
316
317
CHECK_ARGS_APPROX_PAIRWISE_DISTINCT_VECS(fractal_type_none_3d,
318
fractal_type_fbm_3d,
319
fractal_type_ridged_3d,
320
fractal_type_ping_pong_3d);
321
}
322
323
SUBCASE("Different octaves should produce different results") {
324
noise.set_fractal_octaves(1.0);
325
Vector<real_t> fractal_octaves_1_2d = get_noise_samples_2d(noise);
326
Vector<real_t> fractal_octaves_1_3d = get_noise_samples_3d(noise);
327
noise.set_fractal_octaves(8.0);
328
Vector<real_t> fractal_octaves_2_2d = get_noise_samples_2d(noise);
329
Vector<real_t> fractal_octaves_2_3d = get_noise_samples_3d(noise);
330
331
CHECK_FALSE(all_equal_approx(fractal_octaves_1_2d, fractal_octaves_2_2d));
332
CHECK_FALSE(all_equal_approx(fractal_octaves_1_3d, fractal_octaves_2_3d));
333
}
334
335
SUBCASE("Different lacunarity should produce different results") {
336
noise.set_fractal_lacunarity(1.0);
337
Vector<real_t> fractal_lacunarity_1_2d = get_noise_samples_2d(noise);
338
Vector<real_t> fractal_lacunarity_1_3d = get_noise_samples_3d(noise);
339
noise.set_fractal_lacunarity(2.0);
340
Vector<real_t> fractal_lacunarity_2_2d = get_noise_samples_2d(noise);
341
Vector<real_t> fractal_lacunarity_2_3d = get_noise_samples_3d(noise);
342
343
CHECK_FALSE(all_equal_approx(fractal_lacunarity_1_2d, fractal_lacunarity_2_2d));
344
CHECK_FALSE(all_equal_approx(fractal_lacunarity_1_3d, fractal_lacunarity_2_3d));
345
}
346
347
SUBCASE("Different gain should produce different results") {
348
noise.set_fractal_gain(0.5);
349
Vector<real_t> fractal_gain_1_2d = get_noise_samples_2d(noise);
350
Vector<real_t> fractal_gain_1_3d = get_noise_samples_3d(noise);
351
noise.set_fractal_gain(0.75);
352
Vector<real_t> fractal_gain_2_2d = get_noise_samples_2d(noise);
353
Vector<real_t> fractal_gain_2_3d = get_noise_samples_3d(noise);
354
355
CHECK_FALSE(all_equal_approx(fractal_gain_1_2d, fractal_gain_2_2d));
356
CHECK_FALSE(all_equal_approx(fractal_gain_1_3d, fractal_gain_2_3d));
357
}
358
359
SUBCASE("Different weights should produce different results") {
360
noise.set_fractal_weighted_strength(0.5);
361
Vector<real_t> fractal_weighted_strength_1_2d = get_noise_samples_2d(noise);
362
Vector<real_t> fractal_weighted_strength_1_3d = get_noise_samples_3d(noise);
363
noise.set_fractal_weighted_strength(0.75);
364
Vector<real_t> fractal_weighted_strength_2_2d = get_noise_samples_2d(noise);
365
Vector<real_t> fractal_weighted_strength_2_3d = get_noise_samples_3d(noise);
366
367
CHECK_FALSE(all_equal_approx(fractal_weighted_strength_1_2d, fractal_weighted_strength_2_2d));
368
CHECK_FALSE(all_equal_approx(fractal_weighted_strength_1_3d, fractal_weighted_strength_2_3d));
369
}
370
371
SUBCASE("Different ping pong strength should produce different results") {
372
noise.set_fractal_type(FastNoiseLite::FractalType::FRACTAL_PING_PONG);
373
noise.set_fractal_ping_pong_strength(0.5);
374
Vector<real_t> fractal_ping_pong_strength_1_2d = get_noise_samples_2d(noise);
375
Vector<real_t> fractal_ping_pong_strength_1_3d = get_noise_samples_3d(noise);
376
noise.set_fractal_ping_pong_strength(0.75);
377
Vector<real_t> fractal_ping_pong_strength_2_2d = get_noise_samples_2d(noise);
378
Vector<real_t> fractal_ping_pong_strength_2_3d = get_noise_samples_3d(noise);
379
380
CHECK_FALSE(all_equal_approx(fractal_ping_pong_strength_1_2d, fractal_ping_pong_strength_2_2d));
381
CHECK_FALSE(all_equal_approx(fractal_ping_pong_strength_1_3d, fractal_ping_pong_strength_2_3d));
382
}
383
}
384
385
TEST_CASE("[FastNoiseLite] Cellular noise") {
386
FastNoiseLite noise;
387
noise.set_fractal_type(FastNoiseLite::FractalType::FRACTAL_NONE);
388
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_CELLULAR);
389
noise.set_cellular_distance_function(FastNoiseLite::CellularDistanceFunction::DISTANCE_EUCLIDEAN);
390
noise.set_cellular_return_type(FastNoiseLite::CellularReturnType::RETURN_DISTANCE);
391
noise.set_frequency(1.0);
392
393
SUBCASE("Different distance functions should produce different results") {
394
noise.set_cellular_distance_function(FastNoiseLite::CellularDistanceFunction::DISTANCE_EUCLIDEAN);
395
Vector<real_t> cellular_distance_function_euclidean_2d = get_noise_samples_2d(noise);
396
Vector<real_t> cellular_distance_function_euclidean_3d = get_noise_samples_3d(noise);
397
noise.set_cellular_distance_function(FastNoiseLite::CellularDistanceFunction::DISTANCE_EUCLIDEAN_SQUARED);
398
Vector<real_t> cellular_distance_function_euclidean_squared_2d = get_noise_samples_2d(noise);
399
Vector<real_t> cellular_distance_function_euclidean_squared_3d = get_noise_samples_3d(noise);
400
noise.set_cellular_distance_function(FastNoiseLite::CellularDistanceFunction::DISTANCE_MANHATTAN);
401
Vector<real_t> cellular_distance_function_manhattan_2d = get_noise_samples_2d(noise);
402
Vector<real_t> cellular_distance_function_manhattan_3d = get_noise_samples_3d(noise);
403
noise.set_cellular_distance_function(FastNoiseLite::CellularDistanceFunction::DISTANCE_HYBRID);
404
Vector<real_t> cellular_distance_function_hybrid_2d = get_noise_samples_2d(noise);
405
Vector<real_t> cellular_distance_function_hybrid_3d = get_noise_samples_3d(noise);
406
407
CHECK_ARGS_APPROX_PAIRWISE_DISTINCT_VECS(cellular_distance_function_euclidean_2d,
408
cellular_distance_function_euclidean_squared_2d,
409
cellular_distance_function_manhattan_2d,
410
cellular_distance_function_hybrid_2d);
411
412
CHECK_ARGS_APPROX_PAIRWISE_DISTINCT_VECS(cellular_distance_function_euclidean_3d,
413
cellular_distance_function_euclidean_squared_3d,
414
cellular_distance_function_manhattan_3d,
415
cellular_distance_function_hybrid_3d);
416
}
417
418
SUBCASE("Different return function types should produce different results") {
419
noise.set_cellular_return_type(FastNoiseLite::CellularReturnType::RETURN_CELL_VALUE);
420
Vector<real_t> cellular_return_type_cell_value_2d = get_noise_samples_2d(noise);
421
Vector<real_t> cellular_return_type_cell_value_3d = get_noise_samples_3d(noise);
422
noise.set_cellular_return_type(FastNoiseLite::CellularReturnType::RETURN_DISTANCE);
423
Vector<real_t> cellular_return_type_distance_2d = get_noise_samples_2d(noise);
424
Vector<real_t> cellular_return_type_distance_3d = get_noise_samples_3d(noise);
425
noise.set_cellular_return_type(FastNoiseLite::CellularReturnType::RETURN_DISTANCE2);
426
Vector<real_t> cellular_return_type_distance2_2d = get_noise_samples_2d(noise);
427
Vector<real_t> cellular_return_type_distance2_3d = get_noise_samples_3d(noise);
428
noise.set_cellular_return_type(FastNoiseLite::CellularReturnType::RETURN_DISTANCE2_ADD);
429
Vector<real_t> cellular_return_type_distance2_add_2d = get_noise_samples_2d(noise);
430
Vector<real_t> cellular_return_type_distance2_add_3d = get_noise_samples_3d(noise);
431
noise.set_cellular_return_type(FastNoiseLite::CellularReturnType::RETURN_DISTANCE2_SUB);
432
Vector<real_t> cellular_return_type_distance2_sub_2d = get_noise_samples_2d(noise);
433
Vector<real_t> cellular_return_type_distance2_sub_3d = get_noise_samples_3d(noise);
434
noise.set_cellular_return_type(FastNoiseLite::CellularReturnType::RETURN_DISTANCE2_MUL);
435
Vector<real_t> cellular_return_type_distance2_mul_2d = get_noise_samples_2d(noise);
436
Vector<real_t> cellular_return_type_distance2_mul_3d = get_noise_samples_3d(noise);
437
noise.set_cellular_return_type(FastNoiseLite::CellularReturnType::RETURN_DISTANCE2_DIV);
438
Vector<real_t> cellular_return_type_distance2_div_2d = get_noise_samples_2d(noise);
439
Vector<real_t> cellular_return_type_distance2_div_3d = get_noise_samples_3d(noise);
440
441
CHECK_ARGS_APPROX_PAIRWISE_DISTINCT_VECS(cellular_return_type_cell_value_2d,
442
cellular_return_type_distance_2d,
443
cellular_return_type_distance2_2d,
444
cellular_return_type_distance2_add_2d,
445
cellular_return_type_distance2_sub_2d,
446
cellular_return_type_distance2_mul_2d,
447
cellular_return_type_distance2_div_2d);
448
449
CHECK_ARGS_APPROX_PAIRWISE_DISTINCT_VECS(cellular_return_type_cell_value_3d,
450
cellular_return_type_distance_3d,
451
cellular_return_type_distance2_3d,
452
cellular_return_type_distance2_add_3d,
453
cellular_return_type_distance2_sub_3d,
454
cellular_return_type_distance2_mul_3d,
455
cellular_return_type_distance2_div_3d);
456
}
457
458
SUBCASE("Different cellular jitter should produce different results") {
459
noise.set_cellular_jitter(0.0);
460
Vector<real_t> cellular_jitter_1_2d = get_noise_samples_2d(noise);
461
Vector<real_t> cellular_jitter_1_3d = get_noise_samples_3d(noise);
462
noise.set_cellular_jitter(0.5);
463
Vector<real_t> cellular_jitter_2_2d = get_noise_samples_2d(noise);
464
Vector<real_t> cellular_jitter_2_3d = get_noise_samples_3d(noise);
465
466
CHECK_FALSE(all_equal_approx(cellular_jitter_1_2d, cellular_jitter_2_2d));
467
CHECK_FALSE(all_equal_approx(cellular_jitter_1_3d, cellular_jitter_2_3d));
468
}
469
}
470
471
TEST_CASE("[FastNoiseLite] Domain warp") {
472
FastNoiseLite noise;
473
noise.set_frequency(1.0);
474
noise.set_domain_warp_amplitude(200.0);
475
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_SIMPLEX);
476
noise.set_domain_warp_enabled(true);
477
478
SUBCASE("Different domain warp types should produce different results") {
479
noise.set_domain_warp_type(FastNoiseLite::DomainWarpType::DOMAIN_WARP_SIMPLEX);
480
Vector<real_t> domain_warp_type_simplex_2d = get_noise_samples_2d(noise);
481
Vector<real_t> domain_warp_type_simplex_3d = get_noise_samples_3d(noise);
482
noise.set_domain_warp_type(FastNoiseLite::DomainWarpType::DOMAIN_WARP_SIMPLEX_REDUCED);
483
Vector<real_t> domain_warp_type_simplex_reduced_2d = get_noise_samples_2d(noise);
484
Vector<real_t> domain_warp_type_simplex_reduced_3d = get_noise_samples_3d(noise);
485
noise.set_domain_warp_type(FastNoiseLite::DomainWarpType::DOMAIN_WARP_BASIC_GRID);
486
Vector<real_t> domain_warp_type_basic_grid_2d = get_noise_samples_2d(noise);
487
Vector<real_t> domain_warp_type_basic_grid_3d = get_noise_samples_3d(noise);
488
489
CHECK_ARGS_APPROX_PAIRWISE_DISTINCT_VECS(domain_warp_type_simplex_2d,
490
domain_warp_type_simplex_reduced_2d,
491
domain_warp_type_basic_grid_2d);
492
493
CHECK_ARGS_APPROX_PAIRWISE_DISTINCT_VECS(domain_warp_type_simplex_3d,
494
domain_warp_type_simplex_reduced_3d,
495
domain_warp_type_basic_grid_3d);
496
}
497
498
SUBCASE("Different domain warp amplitude should produce different results") {
499
noise.set_domain_warp_amplitude(0.0);
500
Vector<real_t> domain_warp_amplitude_1_2d = get_noise_samples_2d(noise);
501
Vector<real_t> domain_warp_amplitude_1_3d = get_noise_samples_3d(noise);
502
noise.set_domain_warp_amplitude(100.0);
503
Vector<real_t> domain_warp_amplitude_2_2d = get_noise_samples_2d(noise);
504
Vector<real_t> domain_warp_amplitude_2_3d = get_noise_samples_3d(noise);
505
506
CHECK_FALSE(all_equal_approx(domain_warp_amplitude_1_2d, domain_warp_amplitude_2_2d));
507
CHECK_FALSE(all_equal_approx(domain_warp_amplitude_1_3d, domain_warp_amplitude_2_3d));
508
}
509
510
SUBCASE("Different domain warp frequency should produce different results") {
511
noise.set_domain_warp_frequency(0.1);
512
Vector<real_t> domain_warp_frequency_1_2d = get_noise_samples_2d(noise);
513
Vector<real_t> domain_warp_frequency_1_3d = get_noise_samples_3d(noise);
514
noise.set_domain_warp_frequency(2.0);
515
Vector<real_t> domain_warp_frequency_2_2d = get_noise_samples_2d(noise);
516
Vector<real_t> domain_warp_frequency_2_3d = get_noise_samples_3d(noise);
517
518
CHECK_FALSE(all_equal_approx(domain_warp_frequency_1_2d, domain_warp_frequency_2_2d));
519
CHECK_FALSE(all_equal_approx(domain_warp_frequency_1_3d, domain_warp_frequency_2_3d));
520
}
521
522
SUBCASE("Different domain warp fractal type should produce different results") {
523
noise.set_domain_warp_fractal_type(FastNoiseLite::DomainWarpFractalType::DOMAIN_WARP_FRACTAL_NONE);
524
Vector<real_t> domain_warp_fractal_type_none_2d = get_noise_samples_2d(noise);
525
Vector<real_t> domain_warp_fractal_type_none_3d = get_noise_samples_3d(noise);
526
noise.set_domain_warp_fractal_type(FastNoiseLite::DomainWarpFractalType::DOMAIN_WARP_FRACTAL_PROGRESSIVE);
527
Vector<real_t> domain_warp_fractal_type_progressive_2d = get_noise_samples_2d(noise);
528
Vector<real_t> domain_warp_fractal_type_progressive_3d = get_noise_samples_3d(noise);
529
noise.set_domain_warp_fractal_type(FastNoiseLite::DomainWarpFractalType::DOMAIN_WARP_FRACTAL_INDEPENDENT);
530
Vector<real_t> domain_warp_fractal_type_independent_2d = get_noise_samples_2d(noise);
531
Vector<real_t> domain_warp_fractal_type_independent_3d = get_noise_samples_3d(noise);
532
533
CHECK_ARGS_APPROX_PAIRWISE_DISTINCT_VECS(domain_warp_fractal_type_none_2d,
534
domain_warp_fractal_type_progressive_2d,
535
domain_warp_fractal_type_independent_2d);
536
537
CHECK_ARGS_APPROX_PAIRWISE_DISTINCT_VECS(domain_warp_fractal_type_none_3d,
538
domain_warp_fractal_type_progressive_3d,
539
domain_warp_fractal_type_independent_3d);
540
}
541
542
SUBCASE("Different domain warp fractal octaves should produce different results") {
543
noise.set_domain_warp_fractal_octaves(1);
544
Vector<real_t> domain_warp_fractal_octaves_1_2d = get_noise_samples_2d(noise);
545
Vector<real_t> domain_warp_fractal_octaves_1_3d = get_noise_samples_3d(noise);
546
noise.set_domain_warp_fractal_octaves(6);
547
Vector<real_t> domain_warp_fractal_octaves_2_2d = get_noise_samples_2d(noise);
548
Vector<real_t> domain_warp_fractal_octaves_2_3d = get_noise_samples_3d(noise);
549
550
CHECK_FALSE(all_equal_approx(domain_warp_fractal_octaves_1_2d, domain_warp_fractal_octaves_2_2d));
551
CHECK_FALSE(all_equal_approx(domain_warp_fractal_octaves_1_3d, domain_warp_fractal_octaves_2_3d));
552
}
553
554
SUBCASE("Different domain warp fractal lacunarity should produce different results") {
555
noise.set_domain_warp_fractal_lacunarity(0.5);
556
Vector<real_t> domain_warp_fractal_lacunarity_1_2d = get_noise_samples_2d(noise);
557
Vector<real_t> domain_warp_fractal_lacunarity_1_3d = get_noise_samples_3d(noise);
558
noise.set_domain_warp_fractal_lacunarity(5.0);
559
Vector<real_t> domain_warp_fractal_lacunarity_2_2d = get_noise_samples_2d(noise);
560
Vector<real_t> domain_warp_fractal_lacunarity_2_3d = get_noise_samples_3d(noise);
561
562
CHECK_FALSE(all_equal_approx(domain_warp_fractal_lacunarity_1_2d, domain_warp_fractal_lacunarity_2_2d));
563
CHECK_FALSE(all_equal_approx(domain_warp_fractal_lacunarity_1_3d, domain_warp_fractal_lacunarity_2_3d));
564
}
565
566
SUBCASE("Different domain warp fractal gain should produce different results") {
567
noise.set_domain_warp_fractal_gain(0.1);
568
Vector<real_t> domain_warp_fractal_gain_1_2d = get_noise_samples_2d(noise);
569
Vector<real_t> domain_warp_fractal_gain_1_3d = get_noise_samples_3d(noise);
570
noise.set_domain_warp_fractal_gain(0.9);
571
Vector<real_t> domain_warp_fractal_gain_2_2d = get_noise_samples_2d(noise);
572
Vector<real_t> domain_warp_fractal_gain_2_3d = get_noise_samples_3d(noise);
573
574
CHECK_FALSE(all_equal_approx(domain_warp_fractal_gain_1_2d, domain_warp_fractal_gain_2_2d));
575
CHECK_FALSE(all_equal_approx(domain_warp_fractal_gain_1_3d, domain_warp_fractal_gain_2_3d));
576
}
577
}
578
579
// Raw image data for the reference images used in the regression tests.
580
// Generated with the following code:
581
// for (int y = 0; y < img->get_data().size(); y++) {
582
// printf("0x%x,", img->get_data()[y]);
583
// }
584
585
const Vector<uint8_t> ref_img_1_data = { 0xff, 0xe6, 0xd2, 0xc2, 0xb7, 0xb4, 0xb4, 0xb7, 0xc2, 0xd2, 0xe6, 0xe6, 0xcb, 0xb4, 0xa1, 0x94, 0x90, 0x90, 0x94, 0xa1, 0xb4, 0xcb, 0xd2, 0xb4, 0x99, 0x82, 0x72, 0x6c, 0x6c, 0x72, 0x82, 0x99, 0xb4, 0xc2, 0xa1, 0x82, 0x65, 0x50, 0x48, 0x48, 0x50, 0x65, 0x82, 0xa1, 0xb7, 0x94, 0x72, 0x50, 0x32, 0x24, 0x24, 0x32, 0x50, 0x72, 0x94, 0xb4, 0x90, 0x6c, 0x48, 0x24, 0x0, 0x0, 0x24, 0x48, 0x6c, 0x90, 0xb4, 0x90, 0x6c, 0x48, 0x24, 0x0, 0x0, 0x24, 0x48, 0x6c, 0x90, 0xb7, 0x94, 0x72, 0x50, 0x32, 0x24, 0x24, 0x33, 0x50, 0x72, 0x94, 0xc2, 0xa1, 0x82, 0x65, 0x50, 0x48, 0x48, 0x50, 0x66, 0x82, 0xa1, 0xd2, 0xb4, 0x99, 0x82, 0x72, 0x6c, 0x6c, 0x72, 0x82, 0x99, 0xb4, 0xe6, 0xcb, 0xb4, 0xa1, 0x94, 0x90, 0x90, 0x94, 0xa1, 0xb4, 0xcc };
586
const Vector<uint8_t> ref_img_2_data = { 0xff, 0xe6, 0xd2, 0xc2, 0xb7, 0xb4, 0xb4, 0xb7, 0xc2, 0xd2, 0xe6, 0xe6, 0xcb, 0xb4, 0xa1, 0x94, 0x90, 0x90, 0x94, 0xa1, 0xb4, 0xcb, 0xd2, 0xb4, 0x99, 0x82, 0x72, 0x6c, 0x6c, 0x72, 0x82, 0x99, 0xb4, 0xc2, 0xa1, 0x82, 0x65, 0x50, 0x48, 0x48, 0x50, 0x65, 0x82, 0xa1, 0xb7, 0x94, 0x72, 0x50, 0x32, 0x24, 0x24, 0x32, 0x50, 0x72, 0x94, 0xb4, 0x90, 0x6c, 0x48, 0x24, 0x0, 0x0, 0x24, 0x48, 0x6c, 0x90, 0xb4, 0x90, 0x6c, 0x48, 0x24, 0x0, 0x0, 0x24, 0x48, 0x6c, 0x90, 0xb7, 0x94, 0x72, 0x50, 0x32, 0x24, 0x24, 0x33, 0x50, 0x72, 0x94, 0xc2, 0xa1, 0x82, 0x65, 0x50, 0x48, 0x48, 0x50, 0x66, 0x82, 0xa1, 0xd2, 0xb4, 0x99, 0x82, 0x72, 0x6c, 0x6c, 0x72, 0x82, 0x99, 0xb4, 0xe6, 0xcb, 0xb4, 0xa1, 0x94, 0x90, 0x90, 0x94, 0xa1, 0xb4, 0xcc };
587
const Vector<uint8_t> ref_img_3_data = { 0xff, 0xe6, 0xd2, 0xc2, 0xb7, 0xb4, 0xb4, 0xb7, 0xc2, 0xd2, 0xe6, 0xe6, 0xcb, 0xb4, 0xa1, 0x94, 0x90, 0x90, 0x94, 0xa1, 0xb4, 0xcb, 0xd2, 0xb4, 0x99, 0x82, 0x72, 0x6c, 0x6c, 0x72, 0x82, 0x99, 0xb4, 0xc2, 0xa1, 0x82, 0x65, 0x50, 0x48, 0x48, 0x50, 0x65, 0x82, 0xa1, 0xb7, 0x94, 0x72, 0x50, 0x32, 0x24, 0x24, 0x32, 0x50, 0x72, 0x94, 0xb4, 0x90, 0x6c, 0x48, 0x24, 0x0, 0x0, 0x24, 0x48, 0x6c, 0x90, 0xb4, 0x90, 0x6c, 0x48, 0x24, 0x0, 0x0, 0x24, 0x48, 0x6c, 0x90, 0xb7, 0x94, 0x72, 0x50, 0x32, 0x24, 0x24, 0x33, 0x50, 0x72, 0x94, 0xc2, 0xa1, 0x82, 0x65, 0x50, 0x48, 0x48, 0x50, 0x66, 0x82, 0xa1, 0xd2, 0xb4, 0x99, 0x82, 0x72, 0x6c, 0x6c, 0x72, 0x82, 0x99, 0xb4, 0xe6, 0xcb, 0xb4, 0xa1, 0x94, 0x90, 0x90, 0x94, 0xa1, 0xb4, 0xcc };
588
589
// Utiliy function to compare two images pixel by pixel (for easy debugging of regressions)
590
void compare_image_with_reference(const Ref<Image> &p_img, const Ref<Image> &p_reference_img) {
591
for (int y = 0; y < p_img->get_height(); y++) {
592
for (int x = 0; x < p_img->get_width(); x++) {
593
CHECK(p_img->get_pixel(x, y) == p_reference_img->get_pixel(x, y));
594
}
595
}
596
}
597
598
TEST_CASE("[FastNoiseLite] Generating seamless 2D images (11x11px) and compare to reference images") {
599
FastNoiseLite noise;
600
noise.set_noise_type(FastNoiseLite::NoiseType::TYPE_CELLULAR);
601
noise.set_fractal_type(FastNoiseLite::FractalType::FRACTAL_NONE);
602
noise.set_cellular_distance_function(FastNoiseLite::CellularDistanceFunction::DISTANCE_EUCLIDEAN);
603
noise.set_frequency(0.1);
604
noise.set_cellular_jitter(0.0);
605
606
SUBCASE("Blend skirt 0.0") {
607
Ref<Image> img = noise.get_seamless_image(11, 11, false, false, 0.0);
608
609
Ref<Image> ref_img_1 = memnew(Image);
610
ref_img_1->set_data(11, 11, false, Image::FORMAT_L8, ref_img_1_data);
611
612
compare_image_with_reference(img, ref_img_1);
613
}
614
615
SUBCASE("Blend skirt 0.1") {
616
Ref<Image> img = noise.get_seamless_image(11, 11, false, false, 0.1);
617
618
Ref<Image> ref_img_2 = memnew(Image);
619
ref_img_2->set_data(11, 11, false, Image::FORMAT_L8, ref_img_2_data);
620
621
compare_image_with_reference(img, ref_img_2);
622
}
623
624
SUBCASE("Blend skirt 1.0") {
625
Ref<Image> img = noise.get_seamless_image(11, 11, false, false, 0.1);
626
627
Ref<Image> ref_img_3 = memnew(Image);
628
ref_img_3->set_data(11, 11, false, Image::FORMAT_L8, ref_img_3_data);
629
630
compare_image_with_reference(img, ref_img_3);
631
}
632
}
633
634
} //namespace TestFastNoiseLite
635
636