Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ jobs:
msystem: MINGW64
install: mingw-w64-x86_64-libpng

# setup-msys2 only adds the MSYS2 root to the Windows PATH, so the test
# executable would not find libpng16-16.dll (and libz-1.dll) at runtime and
# fails with 0xc0000135 (STATUS_DLL_NOT_FOUND). Add the mingw64 bin
# directory to the PATH for the build/test steps.
- name: Add MSYS2 mingw64 bin to PATH (Windows)
if: runner.os == 'Windows'
run: |
Add-Content "$env:GITHUB_PATH" "${{ steps.msys2.outputs.msys2-location }}/mingw64/bin"

- name: Configure CMake (Windows)
if: runner.os == 'Windows'
run: >
Expand Down
105 changes: 98 additions & 7 deletions tests/test_OpenSimplex2F.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#endif
#include <string.h>
#include <errno.h>
#include <sys/stat.h>

#include <png.h>

Expand Down Expand Up @@ -68,17 +69,94 @@ static int write_png_image(const char *filename, unsigned char *pixels, int w, i
return rc;
}

/* ---------------------------------------------------------------------------
* Readable test output: every generated image is checked (noise value range
* and PNG file) and reported line by line, so the CI log shows what the
* test did and why it passed or failed.
* ------------------------------------------------------------------------- */

struct noise_stats {
double min;
double max;
double sum;
};

static void stats_init(struct noise_stats *s)
{
s->min = 1e300;
s->max = -1e300;
s->sum = 0.0;
}

static void stats_add(struct noise_stats *s, double value)
{
if (value < s->min)
s->min = value;
if (value > s->max)
s->max = value;
s->sum += value;
}

/* All OpenSimplex2F variants are defined to return values in [-1, 1].
* The 3-octave blend of the 2D image is a convex combination of the same
* functions, so it stays in the same range. A small tolerance covers
* floating point rounding. */
#define NOISE_LIMIT 1.0
#define NOISE_EPSILON 1e-6

static int report_test(int index, int total, const char *name, const char *png,
int write_rc, const struct noise_stats *s)
{
struct stat file;
long long size = 0;
double mean = s->sum / (double) (WIDTH * HEIGHT);
int in_range = (s->min >= -NOISE_LIMIT - NOISE_EPSILON) &&
(s->max <= NOISE_LIMIT + NOISE_EPSILON);
int wrote = (write_rc == 0) && (stat(png, &file) == 0);
int ok = in_range && wrote;

if (wrote)
size = (long long) file.st_size;
printf(" [%d/%d] %-32s min=% .6f max=% .6f mean=% .6f -> %s (%lld bytes) ... %s\n",
index, total, name, s->min, s->max, mean, png, size,
ok ? "PASS" : "FAIL");
if (!in_range)
printf(" noise value outside the expected range [-1, 1]\n");
if (write_rc != 0)
printf(" write_png_image(%s) failed\n", png);
else if (!wrote)
printf(" %s is missing or unreadable\n", png);
return ok;
}

int main(__attribute__((unused)) int argc, __attribute__((unused)) char *argv[])
{
int x, y;
double value;
double v0, v1, v2; /* values from different octaves. */
uint32_t rgb;
uint32_t image2d[HEIGHT][WIDTH];
uint32_t image3d[HEIGHT][WIDTH];
uint32_t image4d[HEIGHT][WIDTH];
int passed = 0;
/* Static storage: 3 x 1MB arrays would not fit the default Windows
* thread stack (1MB) and crash with STATUS_STACK_BUFFER_OVERRUN
* (0xC000013D); Linux survives them only because its default stack
* is 8MB.
*/
static uint32_t image2d[HEIGHT][WIDTH];
static uint32_t image3d[HEIGHT][WIDTH];
static uint32_t image4d[HEIGHT][WIDTH];
struct OpenSimplex2F_context *ctx;
struct noise_stats st2d, st3d, st4d;
#if defined(SINGLE_OCTAVE)
static const char *name2d = "open_simplex_noise4 (1 octave)";
#else
static const char *name2d = "open_simplex_noise4 (3 octaves)";
#endif

stats_init(&st2d);
stats_init(&st3d);
stats_init(&st4d);

printf("OpenSimplex2F tests (seed 77374, image %dx%d)\n", WIDTH, HEIGHT);
OpenSimplex2F(77374, &ctx);

for (y = 0; y < HEIGHT; y++) {
Expand All @@ -95,23 +173,36 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *argv[])
(double) y / FEATURE_SIZE / 1, 0.0, 0.0);
value = v0 * 4 / 7.0 + v1 * 2 / 7.0 + v2 * 1 / 7.0;
#endif
stats_add(&st2d, value);
rgb = 0x010101 * (uint32_t) ((value + 1) * 127.5);
image2d[y][x] = ((uint32_t) 0x0ff << 24) | (rgb);

value = OpenSimplex2F_noise2(ctx, (double) x / FEATURE_SIZE, (double) y / FEATURE_SIZE);
stats_add(&st3d, value);
rgb = 0x010101 * (uint32_t) ((value + 1) * 127.5);
image3d[y][x] = ((uint32_t) 0x0ff << 24) | (rgb);

value = OpenSimplex2F_noise3_Classic(ctx, (double) x / FEATURE_SIZE, (double) y / FEATURE_SIZE, 0.0);
stats_add(&st4d, value);
rgb = 0x010101 * (uint32_t) ((value + 1) * 127.5);
image4d[y][x] = ((uint32_t) 0x0ff << 24) | (rgb);
}
}
write_png_image("test2d.png", (unsigned char *) image2d, WIDTH, HEIGHT, 1);
write_png_image("test3d.png", (unsigned char *) image3d, WIDTH, HEIGHT, 1);
write_png_image("test4d.png", (unsigned char *) image4d, WIDTH, HEIGHT, 1);
if (report_test(1, 3, name2d, "test2d.png",
write_png_image("test2d.png", (unsigned char *) image2d, WIDTH, HEIGHT, 1),
&st2d))
passed++;
if (report_test(2, 3, "OpenSimplex2F_noise2", "test3d.png",
write_png_image("test3d.png", (unsigned char *) image3d, WIDTH, HEIGHT, 1),
&st3d))
passed++;
if (report_test(3, 3, "OpenSimplex2F_noise3_Classic", "test4d.png",
write_png_image("test4d.png", (unsigned char *) image4d, WIDTH, HEIGHT, 1),
&st4d))
passed++;
OpenSimplex2F_free(ctx);
OpenSimplex2F_shutdown();
return 0;
printf("Result: %d/3 tests passed\n", passed);
return (passed == 3) ? 0 : 1;
}

Loading