Files
coven/modules/ufbx/test/hash_scene.c

253 lines
6.1 KiB
C

#define _CRT_SECURE_NO_WARNINGS
#include "../ufbx.h"
#include "hash_scene.h"
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <assert.h>
typedef struct {
size_t pos;
size_t size;
union {
size_t size_and_align[2];
bool reverse;
};
char data[];
} ufbxt_linear_alloactor;
static void *linear_alloc_fn(void *user, size_t size)
{
ufbxt_linear_alloactor *ator = (ufbxt_linear_alloactor*)user;
size = (size + 7u) & ~(size_t)7;
size_t pos = ator->pos;
if (ator->reverse) {
assert(pos >= size);
ator->pos = pos - size;
return ator->data + (pos - size);
} else {
assert(ator->size - pos >= size);
ator->pos = pos + size;
return ator->data + pos;
}
}
static void linear_free_allocator_fn(void *user)
{
ufbxt_linear_alloactor *ator = (ufbxt_linear_alloactor*)user;
free(ator);
}
static void linear_allocator_init(ufbx_allocator *allocator, size_t size, bool reverse)
{
ufbxt_linear_alloactor *ator = (ufbxt_linear_alloactor*)malloc(sizeof(ufbxt_linear_alloactor) + size);
assert(ator);
ator->size = size;
ator->reverse = reverse;
if (reverse) {
ator->pos = ator->size;
} else {
ator->pos = 0;
}
allocator->alloc_fn = &linear_alloc_fn;
allocator->free_allocator_fn = &linear_free_allocator_fn;
allocator->user = ator;
}
typedef struct {
bool dedicated_allocs;
bool no_read_buffer;
const char *allocator;
size_t linear_allocator_size;
} ufbxt_hasher_opts;
static void setup_allocator(ufbx_allocator_opts *ator_opts, ufbxt_hasher_opts *opts)
{
if (opts->dedicated_allocs) {
ator_opts->huge_threshold = 1;
}
size_t linear_size = opts->linear_allocator_size ? opts->linear_allocator_size : 128u*1024u*1024u;
if (opts->allocator) {
if (!strcmp(opts->allocator, "linear")) {
linear_allocator_init(&ator_opts->allocator, linear_size, false);
} else if (!strcmp(opts->allocator, "linear-reverse")) {
linear_allocator_init(&ator_opts->allocator, linear_size, true);
} else {
fprintf(stderr, "Unknown allocator: %s\n", opts->allocator);
exit(1);
}
}
}
static ufbx_scene *load_scene(const char *filename, int frame, ufbxt_hasher_opts *hasher_opts)
{
ufbx_load_opts opts = { 0 };
opts.load_external_files = true;
opts.evaluate_caches = true;
opts.evaluate_skinning = true;
opts.target_axes = ufbx_axes_right_handed_y_up;
opts.target_unit_meters = 1.0f;
if (hasher_opts->no_read_buffer) {
opts.read_buffer_size = 1;
}
setup_allocator(&opts.temp_allocator, hasher_opts);
setup_allocator(&opts.result_allocator, hasher_opts);
ufbx_error error;
ufbx_scene *scene = ufbx_load_file(filename, &opts, &error);
if (!scene) {
fprintf(stderr, "Failed to load scene: %s\n", error.description.data);
exit(2);
}
if (frame > 0) {
ufbx_evaluate_opts eval_opts = { 0 };
eval_opts.evaluate_caches = true;
eval_opts.evaluate_skinning = true;
eval_opts.load_external_files = true;
double time = scene->anim.time_begin + frame / scene->settings.frames_per_second;
ufbx_scene *state = ufbx_evaluate_scene(scene, NULL, time, NULL, &error);
if (!state) {
fprintf(stderr, "Failed to evaluate scene: %s\n", error.description.data);
exit(2);
}
ufbx_free_scene(scene);
scene = state;
}
return scene;
}
int main(int argc, char **argv)
{
const char *filename = NULL;
const char *dump_filename = NULL;
int max_dump_errors = -1;
bool do_check = false;
bool dump_all = false;
bool verbose = false;
ufbxt_hasher_opts hasher_opts = { 0 };
int frame = -1;
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--frame")) {
if (++i < argc) frame = atoi(argv[i]);
} else if (!strcmp(argv[i], "--verbose")) {
verbose = true;
} else if (!strcmp(argv[i], "--check")) {
do_check = true;
} else if (!strcmp(argv[i], "--dump")) {
if (++i < argc) dump_filename = argv[i];
} else if (!strcmp(argv[i], "--dump-all")) {
dump_all = true;
} else if (!strcmp(argv[i], "--dedicated-allocs")) {
hasher_opts.dedicated_allocs = true;
} else if (!strcmp(argv[i], "--no-read-buffer")) {
hasher_opts.no_read_buffer = true;
} else if (!strcmp(argv[i], "--allocator")) {
if (++i < argc) hasher_opts.allocator = argv[i];
} else if (!strcmp(argv[i], "--max-dump-errors")) {
if (++i < argc) max_dump_errors = atoi(argv[i]);
} else {
if (filename) {
if (argv[i][0] == '-') {
fprintf(stderr, "Unknown flag: %s\n", argv[i]);
exit(1);
} else {
fprintf(stderr, "Error: Multiple input files\n");
exit(1);
}
}
filename = argv[i];
}
}
if (!filename) {
fprintf(stderr, "Usage: hash_scene <file.fbx>\n");
fprintf(stderr, " hash_scene --check <hashes.txt>\n");
return 1;
}
int num_fail = 0;
int num_total = 0;
FILE *dump_file = NULL;
if (do_check) {
FILE *f = fopen(filename, "r");
if (!f) {
fprintf(stderr, "Failed to open hash file\n");
return 1;
}
uint64_t fbx_hash = 0;
char fbx_file[1024];
while (fscanf(f, "%" SCNx64 " %d %s", &fbx_hash, &frame, fbx_file) == 3) {
ufbx_scene *scene = load_scene(fbx_file, frame, &hasher_opts);
uint64_t hash = ufbxt_hash_scene(scene, NULL);
if (hash != fbx_hash || dump_all) {
if (num_fail < max_dump_errors || dump_all) {
if (!dump_file) {
dump_file = fopen(dump_filename, "wb");
assert(dump_file);
}
fprintf(dump_file, "\n-- %d %s\n\n", frame, fbx_file);
ufbxt_hash_scene(scene, dump_file);
}
if (!dump_all) {
printf("%s: FAIL %" PRIx64 " (local) vs %" PRIx64 " (reference)\n",
fbx_file, hash, fbx_hash);
num_fail++;
}
} else {
if (verbose) {
printf("%s: OK\n", fbx_file);
}
}
num_total++;
}
fclose(f);
if (!dump_all) {
if (verbose || num_fail > 0) {
printf("\n");
}
printf("%d/%d hashes match\n", num_total - num_fail, num_total);
}
} else {
ufbx_scene *scene = load_scene(filename, frame, &hasher_opts);
if (dump_filename) {
dump_file = fopen(dump_filename, "wb");
assert(dump_file);
}
uint64_t hash = ufbxt_hash_scene(scene, dump_file);
printf("%016" PRIx64 "\n", hash);
}
if (dump_file) {
fclose(dump_file);
}
return num_fail > 0 ? 3 : 0;
}
#define UFBX_NO_MATH_H
#define UFBX_MATH_PREFIX fdlibm_
#include "../ufbx.c"