// 0xa000: Rot / Rect / float helpers, random numbers #include "slinky/engine.h" struct Rot { float yaw, pitch; }; struct Rect { float x, y, w, h; }; FN(float, libc_roundf, (float x)); FN(float, libc_fmodf, (float x, float y)); FN(double, time_now, ()); extern "C" float full_turn_degrees, half_turn_degrees_b, offset_neg_360, threshold_neg_180, threshold_1_in_math_helpers_a, three_constant; extern "C" double current_time_seconds; extern "C" __attribute__((noinline)) Rot rot_make_floats(float a, float b) { return Rot{a, b}; } extern "C" Rect make_rect(float x, float y, float w, float h) { return Rect{x, y, w, h}; } extern "C" bool point_in_rect(Rect *r, Rot p) { return p.yaw >= r->x && p.pitch >= r->y && r->x + r->w > p.yaw && r->y + r->h > p.pitch; } extern "C" bool rects_intersect(Rect *a, Rect *b) { if (a->x > b->x + b->w || b->x > a->x + a->w) return false; if (a->y > b->y + b->h) return false; return !(b->y > a->y + a->h); } typedef float v2f __attribute__((ext_vector_type(2))); extern "C" Rect inset_rect(Rect r, float d) { v2f pos = {r.x, r.y}, size = {r.w, r.h}; v2f dd = {d, d}; float d2 = d + d; v2f d22 = {d2, d2}; pos += dd; size -= d22; return Rect{pos.x, pos.y, size.x, size.y}; } extern "C" Rect round_rect(Rect *r) { float x0 = r->x, y0 = r->y; float x = libc_roundf(x0), y = libc_roundf(y0), w = libc_roundf(r->w), h = libc_roundf(r->h); return Rect{x, y, w, h}; } extern "C" Rot offset_rect(Rot *p) { return *p; } extern "C" float limit_rotation_delta(float x, float a, float b) { return (b < x) ? x : (a < b ? a : b); } extern "C" float wrap_angle(float x) { float r = libc_fmodf(x, full_turn_degrees); if (r >= half_turn_degrees_b) return r + offset_neg_360; if (threshold_neg_180 > r) { r += full_turn_degrees; } return r; } extern "C" float lerp_clamped_float(float a, float b, float t) { float m = threshold_1_in_math_helpers_a < t ? threshold_1_in_math_helpers_a : t; return a + m * (b - a); } extern "C" float ease_curve(float t) { float sq = t * t; float d = t + t; return (three_constant - d) * sq; } extern "C" float lerp_unclamped_float(float a, float b, float t) { return a + (b - a) * t; } extern "C" double lerp_double(double a, double b, double t) { return a + (b - a) * t; } extern "C" int chunk_coordinate(int x) { return x >> 4; } extern "C" int block_coordinate(int x) { return x << 4; } extern "C" void update_frame_time() { current_time_seconds = time_now(); } // ---- xoshiro128+ random numbers ---- extern "C" unsigned init_table[4]; extern "C" const float float_epsilon_unused_a, one_in_math_helpers_b, float_epsilon_unused_b, random_range_bound_1_in_math_helpers_c, random_walk_range_epsilon_a, random_range_bound_1_in_math_helpers_d, random_walk_range_epsilon_b; extern "C" const double threshold_0_2, threshold_0_2_in_math_helpers; typedef int v4i __attribute__((vector_size(16))); typedef float v4f __attribute__((vector_size(16))); extern "C" const v4i math_helpers_fabs_masks, math_helpers_fabs_masks_second; // fabs masks static inline __attribute__((always_inline)) unsigned rng_next() { unsigned *s = init_table; unsigned result = s[0] + s[3]; unsigned t = s[1] << 9; s[2] ^= s[0]; s[3] ^= s[1]; s[1] ^= s[2]; s[0] ^= s[3]; s[2] ^= t; s[3] = (s[3] << 11) | (s[3] >> 21); return result; } static inline __attribute__((always_inline)) float rng_range(Rot rotation, float scale) { float d = rotation.pitch - rotation.yaw; return (float)(rng_next() >> 8) * scale * d + rotation.yaw; } static inline __attribute__((always_inline)) float fabs_m(float x, v4i m) { v4f v = {x, 0, 0, 0}; return ((v4f)((v4i)v & m))[0]; } extern "C" float random_rotation(Rot rotation) { return rng_range(rotation, float_epsilon_unused_a); } extern "C" bool random_chance(float p) { return p > rng_range(rot_make_floats(0.0f, one_in_math_helpers_b), float_epsilon_unused_b); } struct Walk { double t0; float a, b; }; extern "C" __attribute__((noinline)) void walk_randomize(Walk *w, bool both) { do { if (both) w->a = rng_range(rot_make_floats(0.0f, random_range_bound_1_in_math_helpers_d), random_walk_range_epsilon_b); w->b = rng_range(rot_make_floats(0.0f, random_range_bound_1_in_math_helpers_d), random_walk_range_epsilon_b); } while (threshold_0_2_in_math_helpers > (double)fabs_m(w->a - w->b, math_helpers_fabs_masks_second)); } // smooth random value in [r.yaw, r.pitch], re-targeted every `period` seconds extern "C" __attribute__((noinline)) float walk_update(Walk *w, Rot rotation, double period) { if (current_time_seconds > w->t0 + period) { w->t0 = current_time_seconds; if (w->a == 0.0f && w->b == 0.0f) { walk_randomize(w, true); } else { w->a = w->b; do { w->b = rng_range(rot_make_floats(0.0f, random_range_bound_1_in_math_helpers_c), random_walk_range_epsilon_a); } while (threshold_0_2 > (double)fabs_m(w->a - w->b, math_helpers_fabs_masks)); } } double t = (current_time_seconds - w->t0) / period; double u = (double)(w->b - w->a) * t + (double)w->a; return (float)((double)(rotation.pitch - rotation.yaw) * u + (double)rotation.yaw); } extern "C" const float random_range_bound_1_in_math_helpers_e, random_walk_range_epsilon_c, random_range_bound_1_in_math_helpers_f, random_walk_range_epsilon_d; extern "C" const double threshold_0_2_in_math_helpers_a; extern "C" const v4i abs_mask; // same walk driven by an accumulated time step instead of the clock extern "C" float walk_update_timed(Walk *w, Rot rotation, double period, double dt) { w->t0 += dt; if (w->t0 > period) { w->t0 = 0.0; if (w->a == 0.0f && w->b == 0.0f) { walk_randomize(w, true); } else { w->a = w->b; do { w->b = rng_range(rot_make_floats(0.0f, random_range_bound_1_in_math_helpers_e), random_walk_range_epsilon_c); } while (threshold_0_2_in_math_helpers_a > (double)fabs_m(w->a - w->b, abs_mask)); } } double t = w->t0 / period; double u = (double)(w->b - w->a) * t + (double)w->a; return (float)((double)(rotation.pitch - rotation.yaw) * u + (double)rotation.yaw); } extern "C" bool walk_should_change(Walk *w, Rot rotation, double period) { float x = rng_range(rot_make_floats(0.0f, random_range_bound_1_in_math_helpers_f), random_walk_range_epsilon_d); return walk_update(w, rotation, period) > x; } // Gaussian random number (Marsaglia polar method, second value cached) FN(float, libc_hypotf_alt, (float a, float b)); FN(float, libc_logf, (float x)); // logf FN(float, libc_sqrtf, (float x)); // sqrtf (errno path) extern "C" const float factor_5_96046eneg_08_in_math_helpers_e, offset_neg_1, threshold_1_in_math_helpers, minus_two; struct Gauss { float spare; bool has; }; extern "C" float gauss_random(Gauss *g) { if (g->has) { g->has = false; return g->spare; } float u, v, s; do { u = (float)(rng_next() >> 8) * factor_5_96046eneg_08_in_math_helpers_e; u = u + u + offset_neg_1; v = (float)(rng_next() >> 8) * factor_5_96046eneg_08_in_math_helpers_e; v = v + v + offset_neg_1; s = libc_hypotf_alt(u, v); } while (s >= threshold_1_in_math_helpers || s == 0.0f); float x = libc_logf(s) * minus_two / s; float m = x >= 0.0f ? __builtin_elementwise_sqrt(x) : libc_sqrtf(x); g->spare = v * m; g->has = true; return u * m; } // define (or find) a class in `loader` and register its native methods #include "slinky/jnienv.h" FN(jclass, find_class, (jobject loader, JNIEnv *env, const char *name)); FN(jobject, class_loader_ref, (jobject loader)); extern "C" int define_class(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, const JNINativeMethod *methods, jclass *out) { jclass cls = find_class(loader, env, name); if (!cls) { (*env)->ExceptionClear(env); auto define = (*env)->DefineClass; cls = define(env, name, class_loader_ref(loader), buf, len); if (!cls) return 0x7d6; } if ((*env)->RegisterNatives(env, cls, methods, 1) != 0) return 0x7d1; *out = cls; return 0; } extern "C" int define_class_with_natives(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, const JNINativeMethod *methods, jint n, jclass *out) { jclass cls = find_class(loader, env, name); if (!cls) { (*env)->ExceptionClear(env); auto define = (*env)->DefineClass; cls = define(env, name, class_loader_ref(loader), buf, len); if (!cls) return 0x7d6; } if ((*env)->RegisterNatives(env, cls, methods, n) != 0) return 0x7d1; *out = cls; return 0; } // one xoshiro128+ step of the shared generator (out-of-line copy of rng_next) extern "C" unsigned xoshiro128_step_shared_generator() { return rng_next(); } // ---- JavaVM lookup: JNI_GetCreatedJavaVMs from the already loaded "jvm" module (one VM) ---- // 0x3e8: no jvm module, 0x3e9: no such export, 0x7d2: the call failed extern "C" const char str_jvm[], str_jni_getcreatedjavavms[]; // "jvm", "JNI_GetCreatedJavaVMs" FN(void *, kernel32_lookups, (const char *module)); FN(void *, get_proc_address, (void *module, const char *name)); typedef int (*GetCreatedJavaVMs)(void **vms, int n, int *count); extern "C" int get_java_vm(void **vm) { int err; if (!vm) return 0x7d2; *vm = nullptr; void *jvm = kernel32_lookups(str_jvm); if (!jvm) { err = 0x3e8; } else { GetCreatedJavaVMs get = (GetCreatedJavaVMs)get_proc_address(jvm, str_jni_getcreatedjavavms); if (!get) { err = 0x3e9; } else { int count = 0; void *created = nullptr; int result = get(&created, 1, &count); if (result == 0 && count >= 1 && created) { *vm = created; err = 0; } else { err = 0x7d2; // call failed or no VM has been created yet } } } SHARED_EPILOG(); return err; }