#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "bench.h"
#if defined(_WIN32)
#include <windows.h>
void* load_library(const char* path) {
return LoadLibraryExA(path, NULL, 0);
}
void* load_symbol(void* dll, const char* proc_name) {
return (void*)GetProcAddress(dll, proc_name);
}
#elif defined(__linux__)
#include <dlfcn.h>
void* load_library(const char* path) {
return dlopen(path, RTLD_NOW);
}
void* load_symbol(void* dll, const char* proc_name) {
return (void*)dlsym(dll, proc_name);
}
#endif
static game_fn_ptr game_fn_print_number = {0};
static game_fn_ptr game_fn_get_1 = {0};
static game_fn_ptr game_fn_get_mass = {0};
static game_fn_ptr game_fn_get_number = {0};
static game_fn_ptr game_fn_x = {0};
static game_fn_ptr game_fn_y = {0};
static game_fn_ptr game_fn_sqrt = {0};
static game_fn_ptr game_fn_set_acc = {0};
typedef __typeof__(&grug_bench_run) p_grug_bench_run;
struct ParticleData {
double index;
};
typedef void (*on_fn_ptr)(void* state, double* entity_data, union grug_value* values, size_t values_len);
void on_print(void* state, double* entity_data, union grug_value* values, size_t values_len) {
(void)(values);
(void)(values_len);
game_fn_print_number(state, &(union grug_value) {.number = *entity_data});
}
void on_increment(void* state, double* entity_data, union grug_value* values, size_t values_len) {
(void)(values);
(void)(values_len);
*entity_data += game_fn_get_1(state, NULL).number;
}
double calc_fib(double i) {
if (i < 0) return 0;
if (i <= 2) return 1;
return calc_fib(i - 1) + calc_fib(i - 2);
}
void on_fib(void* state, double* entity_data, union grug_value* values, size_t values_len) {
(void)(entity_data);
(void)(values);
(void)(values_len);
assert(values_len == 1);
double i = values->number;
game_fn_print_number(state, &(union grug_value) {.number = calc_fib(i)});
}
void on_tick(void* state, struct ParticleData* entity_data, union grug_value* values, size_t values_len) {
(void)(entity_data);
(void)(values);
(void)(values_len);
assert(values_len == 1);
double max_particles = values[0].number;
const double g = 10;
const double scale = 5;
const double min_dist = 0.5;
double my_mass = game_fn_get_mass(state, &(union grug_value){.number = entity_data->index}).number;
double x_i = game_fn_x(state, &(union grug_value){.number = entity_data->index}).number;
double y_i = game_fn_y(state, &(union grug_value){.number = entity_data->index}).number;
double a_x = 0;
double a_y = 0;
for (size_t j = 0; j < (size_t)max_particles; j++) {
if (j == entity_data->index) {
continue;
}
double j_mass = game_fn_get_mass(state, &(union grug_value){.number = (double)j}).number;
double dx = (game_fn_x(state, &(union grug_value){.number = (double)j}).number - x_i) / scale;
double dy = (game_fn_y(state, &(union grug_value){.number = (double)j}).number - y_i) / scale;
double dist2 = dx * dx + dy * dy + min_dist;
double force = g * my_mass * j_mass / dist2;
double invr = 1 / game_fn_sqrt(state, &(union grug_value) {.number = dist2}).number;
double fx = force * dx * invr;
double fy = force * dy * invr;
a_x += fx / my_mass;
a_y += fy / my_mass;
}
game_fn_set_acc(state, (union grug_value[]) {
{.number = entity_data->index},
{.number = a_x},
{.number = a_y}
});
}
void* create_grug_state(const char* mod_api_path, const char* mods_dir) {
(void)(mod_api_path);
(void)(mods_dir);
return NULL;
}
void destroy_grug_state(void* state) {
(void)(state);
}
void* compile_grug_file(void* state, const char* file_path) {
(void)state;
(void)file_path;
if (strcmp(file_path, "bench/basic-Bench.grug") == 0) {
return (void*)1;
} else if (strcmp(file_path, "bench/fib-FibBench.grug") == 0) {
return (void*)2;
} else if (strcmp(file_path, "bench/light-Particle.grug") == 0) {
return (void*)3;
}
exit(2);
}
void* create_entity(void* state, void* grug_script_id) {
(void)state;
if ((size_t)grug_script_id == 1) {
double* entity_data = malloc(sizeof(double));
*entity_data = 0.0;
return entity_data;
} else if ((size_t)grug_script_id == 2) {
return NULL;
} else if ((size_t)grug_script_id == 3) {
struct ParticleData* data = malloc(sizeof(struct ParticleData));
*data = (struct ParticleData) {
.index = game_fn_get_number(state, NULL).number
};
return data;
}
exit(2);
}
void destroy_entity(void* state, void* entity) {
(void)state;
if (entity) free(entity);
}
void* get_on_fn_id(void* state, const char* entity_type, const char* function_name) {
(void)(state);
(void)(entity_type);
if (strcmp(entity_type, "Bench") == 0) {
if (strcmp(function_name, "on_print") == 0) {
return (void*)on_print;
} else if (strcmp(function_name, "on_increment") == 0) {
return (void*)on_increment;
} else {
return NULL;
}
} else if (strcmp(entity_type, "FibBench") == 0) {
if (strcmp(function_name, "on_fib") == 0) {
return (void*)on_fib;
} else {
return NULL;
}
} else if (strcmp(entity_type, "Particle") == 0) {
if (strcmp(function_name, "on_tick") == 0) {
return (void*)on_tick;
} else {
return NULL;
}
}
exit(2);
}
void call_entity_on_fn(void* state, void* entity_data, void* on_fn_id, union grug_value* values, size_t values_len) {
((on_fn_ptr)on_fn_id)(state, entity_data, values, values_len);
}
int main () {
void* dll;
(dll = load_library("bench.dll"))? (void)(0):
(dll = load_library("libbench.dll"))? (void)(0):
(dll = load_library("libbench.so"))? (void)(0): NULL;
if (!dll) {
fprintf(stderr, "could not open dll\n");
exit(1);
}
p_grug_bench_run grug_bench_run = (__typeof__(p_grug_bench_run ))load_symbol(dll, "grug_bench_run" );
game_fn_print_number = (__typeof__(game_fn_print_number))load_symbol(dll, "game_fn_print_number");
game_fn_get_1 = (__typeof__(game_fn_get_1 ))load_symbol(dll, "game_fn_get_1" );
game_fn_get_mass = (__typeof__(game_fn_get_mass ))load_symbol(dll, "game_fn_get_mass" );
game_fn_get_number = (__typeof__(game_fn_get_number ))load_symbol(dll, "game_fn_get_number" );
game_fn_x = (__typeof__(game_fn_x ))load_symbol(dll, "game_fn_x" );
game_fn_y = (__typeof__(game_fn_y ))load_symbol(dll, "game_fn_y" );
game_fn_sqrt = (__typeof__(game_fn_sqrt ))load_symbol(dll, "game_fn_sqrt" );
game_fn_set_acc = (__typeof__(game_fn_set_acc ))load_symbol(dll, "game_fn_set_acc" );
if (!(grug_bench_run && game_fn_print_number && game_fn_print_number)) {
fprintf(stderr, "could not load symbols\n");
return 1;
}
struct grug_state_vtable vtable = {
.create_grug_state = create_grug_state,
.destroy_grug_state = destroy_grug_state,
.compile_grug_file = compile_grug_file,
.create_entity = create_entity,
.destroy_entity = destroy_entity,
.get_on_fn_id = get_on_fn_id,
.call_entity_on_fn = call_entity_on_fn,
};
grug_bench_run(
"./mod_api.json",
"./mods",
&vtable,
0
);
return 0;
}