Created
January 8, 2019 16:54
-
-
Save binji/301f3f720c2fa0f64147eb9cf02a2540 to your computer and use it in GitHub Desktop.
FunkyKarts wasm2c main
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> | |
#include <math.h> | |
#include <stdbool.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <time.h> | |
#define GL_GLEXT_PROTOTYPES | |
#include <SDL2/SDL.h> | |
#include <SDL2/SDL_opengl.h> | |
#include <GL/glext.h> | |
#include "out/fk.h" | |
#if 0 | |
#define LOG(...) fprintf(stdout, __VA_ARGS__) | |
#else | |
#define LOG(...) (void)0 | |
#endif | |
#if 0 | |
#define DEBUG(...) LOG(__VA_ARGS__) | |
#else | |
#define DEBUG(...) (void)0 | |
#endif | |
#if 0 | |
#define FUNC0() LOG("%s:\n", __func__) | |
#define FUNC(fmt, ...) LOG("%s:" fmt "\n", __func__, __VA_ARGS__) | |
#define FUNCINFO(fmt, ...) LOG(" " fmt, __VA_ARGS__) | |
#else | |
#define FUNC0(fmt) (void)0 | |
#define FUNC(fmt, ...) (void)0 | |
#define FUNCINFO(fmt, ...) (void)0 | |
#endif | |
#define EXT_SYM(type, name) \ | |
type real_##name; \ | |
type* name = &real_##name | |
#define EXT_FUNC(type, name, ...) \ | |
type real_##name(__VA_ARGS__); \ | |
type (*name)(__VA_ARGS__) = &real_##name; \ | |
type real_##name(__VA_ARGS__) | |
typedef enum EventId { | |
EVENT_KEYDOWN_ID = 2, | |
EVENT_KEYUP_ID = 3, | |
EVENT_MOUSEDOWN_ID = 5, | |
EVENT_MOUSEUP_ID = 6, | |
EVENT_RESIZE_ID = 10, | |
EVENT_BLUR_ID = 12, | |
EVENT_FOCUS_ID = 13, | |
EVENT_VISIBILITY_CHANGE_ID = 21, | |
EVENT_TOUCHSTART_ID = 22, | |
EVENT_TOUCHCANCEL_ID = 25, | |
} EventId; | |
typedef struct Callback { | |
EventId id; | |
u32 func; | |
u32 user_data; | |
u32 ptr; | |
bool active; | |
} Callback; | |
typedef struct LoadedAudioFX { | |
u32 id; | |
f32* buf; | |
u32 len; | |
} LoadedAudioFX; | |
typedef struct PlayingAudioFX { | |
LoadedAudioFX* loaded; | |
u32 offset; | |
} PlayingAudioFX; | |
extern void init(void); | |
uint32_t wasm_rt_call_stack_depth; | |
EXT_SYM(wasm_rt_memory_t, Z_envZ_memory); | |
EXT_SYM(wasm_rt_table_t,Z_envZ_table); | |
EXT_SYM(u32, Z_envZ_DYNAMICTOP_PTRZ_i); | |
EXT_SYM(u32, Z_envZ_tempDoublePtrZ_i); | |
EXT_SYM(u32, Z_envZ_STACKTOPZ_i); | |
EXT_SYM(u32, Z_envZ_STACK_MAXZ_i); | |
EXT_SYM(u32, Z_envZ_tableBaseZ_i); | |
SDL_Window* window; | |
SDL_GLContext gl_context; | |
SDL_AudioDeviceID audio_device; | |
SDL_AudioSpec audio_spec; | |
u32 audio_left_p; | |
u32 audio_right_p; | |
f64 midi_volume = 1.0; | |
f64 fx_volume = 1.0; | |
#define MAX_AUDIO_FX 100 | |
LoadedAudioFX loaded_audio_fx[MAX_AUDIO_FX]; | |
PlayingAudioFX playing_audio_fx[MAX_AUDIO_FX]; | |
u32 loaded_audio_fx_count; | |
u32 playing_audio_fx_count; | |
Callback on_blur = {EVENT_BLUR_ID}; | |
Callback on_focus = {EVENT_FOCUS_ID}; | |
Callback on_keydown = {EVENT_KEYDOWN_ID}; | |
Callback on_keyup = {EVENT_KEYUP_ID}; | |
Callback on_mousedown = {EVENT_MOUSEDOWN_ID}; | |
Callback on_mouseup = {EVENT_MOUSEUP_ID}; | |
Callback on_resize = {EVENT_RESIZE_ID}; | |
Callback on_visibility_change = {EVENT_VISIBILITY_CHANGE_ID}; | |
static inline u8* addr_ptr(u32 addr) { | |
return addr ? &Z_envZ_memory->data[addr] : NULL; | |
} | |
#define DEFINE_STORE(name, t) \ | |
static inline void name(u32 addr, t x) { \ | |
memcpy(addr_ptr(addr), &x, sizeof(x)); \ | |
} | |
DEFINE_STORE(u8_store, u8) | |
DEFINE_STORE(u16_store, u16) | |
DEFINE_STORE(u32_store, u32) | |
DEFINE_STORE(f64_store, f64) | |
#define DEFINE_LOAD(name, t) \ | |
static inline t name(u32 addr) { \ | |
t result; \ | |
memcpy(&result, addr_ptr(addr), sizeof(result)); \ | |
return result; \ | |
} | |
DEFINE_LOAD(u32_load, u32) | |
DEFINE_LOAD(f32_load, f32) | |
extern u32 (*Z__mallocZ_ii)(u32); | |
static u32 string_dup(const char* s) { | |
u32 len = strlen(s); | |
u32 addr = Z__mallocZ_ii(len); | |
memcpy(addr_ptr(addr), s, len + 1); | |
return addr; | |
} | |
static void string_copy_n(u32 addr, const char* s, u32 n) { | |
strncpy((char*)addr_ptr(addr), s, n); | |
} | |
u32 wasm_rt_register_func_type(u32 params, u32 results, ...) { | |
static u32 func_types = 0; | |
return func_types++; | |
} | |
void wasm_rt_trap(wasm_rt_trap_t t) { | |
__builtin_trap(); | |
} | |
EXT_FUNC(f64, Z_envZ__llvm_exp2_f32Z_dd, f64 x) { | |
return pow(2, x); | |
} | |
EXT_FUNC(u32, Z_asm2wasmZ_f64Z2DtoZ2DintZ_id, f64 p0) { | |
FUNC("%f", p0); | |
return (u32)(s32)p0; | |
} | |
EXT_FUNC(u32, Z_envZ_abortOnCannotGrowMemoryZ_iv, void) { | |
assert(0); | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ__clock_gettimeZ_iii, u32 clk_id, u32 tp) { | |
FUNC("%u %u", clk_id, tp); | |
struct timespec ts; | |
int res = clock_gettime(clk_id, &ts); | |
if (res < 0) { | |
return res; | |
} | |
u32_store(tp, ts.tv_sec); | |
u32_store(tp + 4, ts.tv_nsec); | |
FUNCINFO("sec=%u nsec=%u\n", (u32)ts.tv_sec, (u32)ts.tv_nsec); | |
return 0; | |
} | |
EXT_FUNC(u32, | |
Z_envZ__emscripten_asm_const_iiiZ_iiii, | |
u32 code, | |
u32 a0, | |
u32 a1) { | |
FUNC("%u %u %u", code, a0, a1); | |
switch (code) { | |
case 0: | |
FUNCINFO("Initialize analytics: %s %s\n", addr_ptr(a0), addr_ptr(a1)); | |
return 0; | |
case 1: { | |
FUNCINFO("Set #display width:%u height:%u\n", a0, a1); | |
SDL_SetWindowSize(window, a0, a1); | |
SDL_ShowWindow(window); | |
return 0; | |
} | |
} | |
assert(0); | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ__emscripten_asm_const_iiZ_iii, u32 code, u32 a0) { | |
FUNC("%u %u", code, a0); | |
switch (code) { | |
case 7: | |
FUNCINFO("Send analytics: %s\n", addr_ptr(a0)); | |
return 0; | |
} | |
assert(0); | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ__emscripten_asm_const_iZ_ii, u32 code) { | |
FUNC("%u", code); | |
switch (code) { | |
case 2: // UserAgent/navigator platform detection. | |
return 1; // Windows. | |
case 4: // Is fullscreen? | |
return 0; | |
case 5: // Has fullscreen element? | |
return 0; | |
} | |
assert(0); | |
return 0; | |
} | |
EXT_FUNC(u32, | |
Z_envZ__emscripten_get_element_css_sizeZ_iiii, | |
u32 target, | |
u32 width, | |
u32 height) { | |
FUNC("%u(%s) %u %u", target, addr_ptr(target), width, height); | |
// TODO(binji): real values. | |
if (window) { | |
int w, h; | |
SDL_GetWindowSize(window, &w, &h); | |
f64_store(width, w); | |
f64_store(height, h); | |
} else { | |
f64_store(width, 1920); | |
f64_store(height, 1080); | |
} | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ__emscripten_memcpy_bigZ_iiii, u32 dest, u32 src, u32 n) { | |
FUNC("%u %u %u", dest, src, n); | |
// TODO(binji): bounds checks. | |
memcpy(addr_ptr(dest), addr_ptr(src), n); | |
return dest; | |
} | |
static void maybe_allocate_focus_ptr(void) { | |
if (!on_blur.ptr) { | |
on_focus.ptr = on_blur.ptr = Z__mallocZ_ii(256); | |
} | |
} | |
EXT_FUNC(u32, | |
Z_envZ__emscripten_set_blur_callbackZ_iiiii, | |
u32 target, | |
u32 user_data, | |
u32 use_capture, | |
u32 callbackfunc) { | |
FUNC("%u %u %u %u", target, user_data, use_capture, callbackfunc); | |
on_blur.active = true; | |
on_blur.func = callbackfunc; | |
on_blur.user_data = user_data; | |
maybe_allocate_focus_ptr(); | |
return 0; | |
} | |
EXT_FUNC(u32, | |
Z_envZ__emscripten_set_focus_callbackZ_iiiii, | |
u32 target, | |
u32 user_data, | |
u32 use_capture, | |
u32 callbackfunc) { | |
FUNC("%u %u %u %u", target, user_data, use_capture, callbackfunc); | |
on_focus.active = true; | |
on_focus.func = callbackfunc; | |
on_focus.user_data = user_data; | |
maybe_allocate_focus_ptr(); | |
return 0; | |
} | |
static void maybe_allocate_key_ptr(void) { | |
if (!on_keydown.ptr) { | |
on_keydown.ptr = on_keyup.ptr = Z__mallocZ_ii(164); | |
} | |
} | |
EXT_FUNC(u32, | |
Z_envZ__emscripten_set_keydown_callbackZ_iiiii, | |
u32 target, | |
u32 user_data, | |
u32 use_capture, | |
u32 callbackfunc) { | |
FUNC("%u %u %u %u", target, user_data, use_capture, callbackfunc); | |
on_keydown.active = true; | |
on_keydown.func = callbackfunc; | |
on_keydown.user_data = user_data; | |
maybe_allocate_key_ptr(); | |
return 0; | |
} | |
EXT_FUNC(u32, | |
Z_envZ__emscripten_set_keyup_callbackZ_iiiii, | |
u32 target, | |
u32 user_data, | |
u32 use_capture, | |
u32 callbackfunc) { | |
FUNC("%u %u %u %u", target, user_data, use_capture, callbackfunc); | |
on_keyup.active = true; | |
on_keyup.func = callbackfunc; | |
on_keyup.user_data = user_data; | |
maybe_allocate_key_ptr(); | |
return 0; | |
} | |
static void maybe_allocate_mouse_ptr(void) { | |
if (!on_mousedown.ptr) { | |
on_mousedown.ptr = on_mouseup.ptr = Z__mallocZ_ii(72); | |
} | |
} | |
EXT_FUNC(u32, | |
Z_envZ__emscripten_set_mousedown_callbackZ_iiiii, | |
u32 target, | |
u32 user_data, | |
u32 use_capture, | |
u32 callbackfunc) { | |
FUNC("%u %u %u %u", target, user_data, use_capture, callbackfunc); | |
on_mousedown.active = true; | |
on_mousedown.func = callbackfunc; | |
on_mousedown.user_data = user_data; | |
maybe_allocate_mouse_ptr(); | |
return 0; | |
} | |
EXT_FUNC(u32, | |
Z_envZ__emscripten_set_mouseup_callbackZ_iiiii, | |
u32 target, | |
u32 user_data, | |
u32 use_capture, | |
u32 callbackfunc) { | |
FUNC("%u %u %u %u", target, user_data, use_capture, callbackfunc); | |
on_mouseup.active = true; | |
on_mouseup.func = callbackfunc; | |
on_mouseup.user_data = user_data; | |
maybe_allocate_mouse_ptr(); | |
return 0; | |
} | |
EXT_FUNC(u32, | |
Z_envZ__emscripten_set_resize_callbackZ_iiiii, | |
u32 target, | |
u32 user_data, | |
u32 use_capture, | |
u32 callbackfunc) { | |
FUNC("%u %u %u %u", target, user_data, use_capture, callbackfunc); | |
on_resize.active = true; | |
on_resize.func = callbackfunc; | |
on_resize.user_data = user_data; | |
if (!on_resize.ptr) { | |
on_resize.ptr = Z__mallocZ_ii(36); | |
} | |
return 0; | |
} | |
EXT_FUNC(u32, | |
Z_envZ__emscripten_set_touchcancel_callbackZ_iiiii, | |
u32 target, | |
u32 user_data, | |
u32 use_capture, | |
u32 callbackfunc) { | |
FUNC("%u %u %u %u", target, user_data, use_capture, callbackfunc); | |
return 0; | |
} | |
EXT_FUNC(u32, | |
Z_envZ__emscripten_set_touchend_callbackZ_iiiii, | |
u32 target, | |
u32 user_data, | |
u32 use_capture, | |
u32 callbackfunc) { | |
FUNC("%u %u %u %u", target, user_data, use_capture, callbackfunc); | |
return 0; | |
} | |
EXT_FUNC(u32, | |
Z_envZ__emscripten_set_touchstart_callbackZ_iiiii, | |
u32 target, | |
u32 user_data, | |
u32 use_capture, | |
u32 callbackfunc) { | |
FUNC("%u %u %u %u", target, user_data, use_capture, callbackfunc); | |
return 0; | |
} | |
EXT_FUNC(u32, | |
Z_envZ__emscripten_set_visibilitychange_callbackZ_iiii, | |
u32 user_data, | |
u32 use_capture, | |
u32 callbackfunc) { | |
FUNC("%u %u %u", user_data, use_capture, callbackfunc); | |
on_visibility_change.active = true; | |
on_visibility_change.func = callbackfunc; | |
on_visibility_change.user_data = user_data; | |
if (!on_visibility_change.ptr) { | |
on_visibility_change.ptr = Z__mallocZ_ii(8); | |
} | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ__emscripten_webgl_create_contextZ_iii, u32 p0, u32 p1) { | |
FUNC("%u(%s) %u", p0, addr_ptr(p0), p1); | |
u32 alpha = u32_load(p1); | |
u32 depth = u32_load(p1 + 4); | |
u32 stencil = u32_load(p1 + 8); | |
u32 antialias = u32_load(p1 + 12); | |
u32 premultiplied_alpha = u32_load(p1 + 16); | |
u32 preserve_drawing_buffer = u32_load(p1 + 20); | |
u32 prefer_low_power_to_high_performance = u32_load(p1 + 24); | |
u32 fail_if_major_performance_caveat = u32_load(p1 + 28); | |
u32 major_version = u32_load(p1 + 32); | |
u32 minor_version = u32_load(p1 + 36); | |
u32 explicit_swap_control = u32_load(p1 + 40); | |
FUNCINFO("alpha: %d\n", alpha); | |
FUNCINFO("depth: %d\n", depth); | |
FUNCINFO("stencil: %d\n", stencil); | |
FUNCINFO("antialias: %d\n", antialias); | |
FUNCINFO("premultiplied_alpha: %d\n", premultiplied_alpha); | |
FUNCINFO("preserve_drawing_buffer: %d\n", preserve_drawing_buffer); | |
FUNCINFO("prefer_low_power_to_high_performance: %d\n", | |
prefer_low_power_to_high_performance); | |
FUNCINFO("fail_if_major_performance_caveat: %d\n", | |
fail_if_major_performance_caveat); | |
FUNCINFO("major_version: %d\n", major_version); | |
FUNCINFO("minor_version: %d\n", minor_version); | |
FUNCINFO("explicit_swap_control: %d\n", explicit_swap_control); | |
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); | |
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); | |
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); | |
window = SDL_CreateWindow( | |
"canvas", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1920, 1080, | |
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN); | |
if (!window) { | |
SDL_Quit(); | |
return -1; | |
} | |
gl_context = SDL_GL_CreateContext(window); | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ__emscripten_webgl_make_context_currentZ_ii, u32 p0) { | |
FUNC("%u", p0); | |
SDL_GL_MakeCurrent(window, gl_context); | |
// Arggghhhhh | |
GLuint vao; | |
glGenVertexArrays(1, &vao); | |
glBindVertexArray(vao); | |
glEnable(GL_PROGRAM_POINT_SIZE); | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ_enlargeMemoryZ_iv, void) { | |
assert(0); | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ_getTotalMemoryZ_iv, void) { | |
return Z_envZ_memory->size; | |
} | |
EXT_FUNC(u32, Z_envZ__glCreateProgramZ_iv, void) { | |
FUNC0(); | |
GLuint program = glCreateProgram(); | |
FUNCINFO("program = %u\n", program); | |
return program; | |
} | |
EXT_FUNC(u32, Z_envZ__glCreateShaderZ_ii, u32 shader_type) { | |
FUNC("%#x", shader_type); | |
GLuint shader = glCreateShader(shader_type); | |
FUNCINFO("shader = %u\n", shader); | |
return shader; | |
} | |
EXT_FUNC(u32, Z_envZ__glGetUniformLocationZ_iii, u32 program, u32 name) { | |
FUNC("%u %u(%s)", program, name, addr_ptr(name)); | |
GLint location = glGetUniformLocation(program, (const GLchar*)addr_ptr(name)); | |
FUNCINFO("location = %u\n", location); | |
return location; | |
} | |
EXT_FUNC(u32, Z_envZ__pthread_getspecificZ_ii, u32 p0) { | |
assert(0); | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ__pthread_key_createZ_iii, u32 p0, u32 p1) { | |
assert(0); | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ__pthread_onceZ_iii, u32 p0, u32 p1) { | |
assert(0); | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ__pthread_setspecificZ_iii, u32 p0, u32 p1) { | |
assert(0); | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ____syscall140Z_iii, u32 p0, u32 p1) { | |
assert(0); | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ____syscall145Z_iii, u32 p0, u32 p1) { | |
assert(0); | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ____syscall146Z_iii, u32 p0, u32 p1) { | |
assert(0); | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ____syscall221Z_iii, u32 p0, u32 p1) { | |
assert(0); | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ____syscall54Z_iii, u32 p0, u32 p1) { | |
assert(0); | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ____syscall5Z_iii, u32 p0, u32 p1) { | |
assert(0); | |
return 0; | |
} | |
EXT_FUNC(u32, Z_envZ____syscall6Z_iii, u32 p0, u32 p1) { | |
assert(0); | |
return 0; | |
} | |
EXT_FUNC(void, Z_envZ_abortZ_vi, u32 p0) { | |
assert(0); | |
} | |
EXT_FUNC(void, Z_envZ__abortZ_vv, void) { | |
assert(0); | |
} | |
EXT_FUNC(void, Z_envZ__AudioInitializeZ_vv, void) { | |
FUNC0(); | |
SDL_AudioSpec want = { | |
.freq = 44100, .format = AUDIO_F32, .channels = 2, .samples = 8192}; | |
audio_device = SDL_OpenAudioDevice(NULL, 0, &want, &audio_spec, 0); | |
audio_left_p = Z__mallocZ_ii(4096 * 4); | |
audio_right_p = Z__mallocZ_ii(4096 * 4); | |
LOG("audio freq:%u fmt:%#x chan:%u samples:%u\n", audio_spec.freq, | |
audio_spec.format, audio_spec.channels, audio_spec.samples); | |
assert(audio_spec.format == AUDIO_F32); | |
} | |
static void play_audio_fx(u32 id) { | |
if (playing_audio_fx_count >= MAX_AUDIO_FX) { | |
LOG("!!! Unable to load audio id:%u.\n", id); | |
return; | |
} | |
LoadedAudioFX* loaded = NULL; | |
int i; | |
for (i = 0; i < loaded_audio_fx_count; ++i) { | |
if (loaded_audio_fx[i].id == id) { | |
loaded = &loaded_audio_fx[i]; | |
break; | |
} | |
} | |
if (loaded) { | |
PlayingAudioFX* playing = &playing_audio_fx[playing_audio_fx_count++]; | |
playing->loaded = loaded; | |
playing->offset = 0; | |
} else { | |
LOG("!!! Unknown audio id:%u.\n", id); | |
} | |
} | |
EXT_FUNC(void, | |
Z_envZ__AudioLoadAndStartFXZ_viii, | |
u32 id, | |
u32 bytes, | |
u32 byte_length) { | |
#if 1 | |
FUNC("%u %u %u", id, bytes, byte_length); | |
const u8* data = addr_ptr(bytes); | |
if (loaded_audio_fx_count >= MAX_AUDIO_FX) { | |
LOG("!!! Unable to load audio id:%u.\n", id); | |
return; | |
} | |
LoadedAudioFX* fx = &loaded_audio_fx[loaded_audio_fx_count++]; | |
fx->id = id; | |
SDL_RWops* rwops = SDL_RWFromConstMem(data, byte_length); | |
SDL_AudioSpec wav_spec; | |
u8* wav_buf; | |
u32 wav_len; | |
if (SDL_LoadWAV_RW(rwops, 1, &wav_spec, &wav_buf, &wav_len)) { | |
SDL_AudioCVT cvt; | |
SDL_BuildAudioCVT(&cvt, wav_spec.format, wav_spec.channels, wav_spec.freq, | |
audio_spec.format, audio_spec.channels, audio_spec.freq); | |
cvt.len = wav_len; | |
cvt.buf = calloc(wav_len, cvt.len_mult); | |
memcpy(cvt.buf, wav_buf, wav_len); | |
SDL_ConvertAudio(&cvt); | |
fx->buf = (f32*)cvt.buf; | |
fx->len = cvt.len_cvt / sizeof(f32); | |
SDL_FreeWAV(wav_buf); | |
play_audio_fx(id); | |
} else { | |
LOG("!!! Error loading audio id:%u.\n", id); | |
} | |
#endif | |
} | |
EXT_FUNC(void, Z_envZ__AudioPauseZ_vv, void) { | |
FUNC0(); | |
SDL_PauseAudioDevice(audio_device, 1); | |
} | |
EXT_FUNC(void, Z_envZ__AudioResumeZ_vv, void) { | |
FUNC0(); | |
SDL_PauseAudioDevice(audio_device, 0); | |
} | |
EXT_FUNC(void, Z_envZ__AudioSetFXVolumeZ_vd, f64 p0) { | |
FUNC("%f", p0); | |
fx_volume = p0; | |
} | |
EXT_FUNC(void, Z_envZ__AudioSetMidiVolumeZ_vd, f64 p0) { | |
FUNC("%f", p0); | |
midi_volume = p0; | |
} | |
EXT_FUNC(void, Z_envZ__AudioStartFXZ_vi, u32 id) { | |
FUNC("%u", id); | |
play_audio_fx(id); | |
} | |
EXT_FUNC(void, Z_envZ____cxa_pure_virtualZ_vv, void) { | |
assert(0); | |
} | |
EXT_FUNC(void, Z_envZ__emscripten_asm_const_vZ_vi, u32 p0) { | |
assert(0); | |
} | |
static int mainloop_func = 0; | |
EXT_FUNC(void, Z_envZ__emscripten_set_main_loopZ_viii, u32 p0, u32 p1, u32 p2) { | |
FUNC("%u %u %u", p0, p1, p2); | |
u32 func = p0; | |
u32 fps = p1; | |
u32 simulate_infinite_loop = p2; | |
mainloop_func = func; | |
// TODO(binji): supposed to throw if simulate_infinite_loop == 1. | |
} | |
EXT_FUNC(void, Z_envZ__emscripten_webgl_init_context_attributesZ_vi, u32 p0) { | |
FUNC("%u", p0); | |
// TODO(binji): magic | |
u32_store(p0, 1); | |
u32_store(p0 + 4, 1); | |
u32_store(p0 + 8, 0); | |
u32_store(p0 + 12, 1); | |
u32_store(p0 + 16, 1); | |
u32_store(p0 + 20, 0); | |
u32_store(p0 + 24, 0); | |
u32_store(p0 + 28, 0); | |
u32_store(p0 + 32, 1); | |
u32_store(p0 + 36, 0); | |
u32_store(p0 + 40, 1); | |
u32_store(p0 + 44, 0); | |
} | |
EXT_FUNC(void, Z_envZ__exitZ_vi, u32 p0) { | |
assert(0); | |
} | |
EXT_FUNC(void, Z_envZ__glActiveTextureZ_vi, u32 texture) { | |
FUNC("%#x", texture); | |
glActiveTexture(texture); | |
} | |
EXT_FUNC(void, Z_envZ__glAttachShaderZ_vii, u32 program, u32 shader) { | |
FUNC("%u %u", program, shader); | |
glAttachShader(program, shader); | |
} | |
EXT_FUNC(void, | |
Z_envZ__glBindAttribLocationZ_viii, | |
u32 program, | |
u32 index, | |
u32 name) { | |
FUNC("%u %u %u(%s)", program, index, name, addr_ptr(name)); | |
glBindAttribLocation(program, index, (const GLchar*)addr_ptr(name)); | |
} | |
EXT_FUNC(void, Z_envZ__glBindBufferZ_vii, u32 target, u32 buffer) { | |
FUNC("%#x %u", target, buffer); | |
glBindBuffer(target, buffer); | |
} | |
EXT_FUNC(void, Z_envZ__glBindFramebufferZ_vii, u32 target, u32 framebuffer) { | |
FUNC("%#x %u", target, framebuffer); | |
glBindFramebuffer(target, framebuffer); | |
} | |
EXT_FUNC(void, Z_envZ__glBindTextureZ_vii, u32 target, u32 texture) { | |
FUNC("%#x %u", target, texture); | |
glBindTexture(target, texture); | |
} | |
EXT_FUNC(void, Z_envZ__glBlendFuncZ_vii, u32 sfactor, u32 dfactor) { | |
FUNC("%#x %#x", sfactor, dfactor); | |
glBlendFunc(sfactor, dfactor); | |
} | |
EXT_FUNC(void, | |
Z_envZ__glBufferDataZ_viiii, | |
u32 target, | |
u32 size, | |
u32 data, | |
u32 usage) { | |
FUNC("%#x %u %u %#x", target, size, data, usage); | |
glBufferData(target, size, addr_ptr(data), usage); | |
} | |
EXT_FUNC(void, | |
Z_envZ__glClearColorZ_vdddd, | |
f64 red, | |
f64 green, | |
f64 blue, | |
f64 alpha) { | |
FUNC("%f %f %f %f", red, green, blue, alpha); | |
glClearColor(red, green, blue, alpha); | |
} | |
EXT_FUNC(void, Z_envZ__glClearZ_vi, u32 mask) { | |
FUNC("%#x", mask); | |
glClear(mask); | |
} | |
EXT_FUNC(void, Z_envZ__glCompileShaderZ_vi, u32 shader) { | |
FUNC("%u", shader); | |
glCompileShader(shader); | |
} | |
EXT_FUNC(void, Z_envZ__glDeleteBuffersZ_vii, u32 n, u32 buffers) { | |
FUNC("%u %u", n, buffers); | |
assert(sizeof(u32) == sizeof(GLuint)); | |
glDeleteBuffers(n, (GLuint*)addr_ptr(buffers)); | |
} | |
EXT_FUNC(void, Z_envZ__glDeleteFramebuffersZ_vii, u32 n, u32 framebuffers) { | |
FUNC("%u %u", n, framebuffers); | |
assert(sizeof(u32) == sizeof(GLuint)); | |
glDeleteFramebuffers(n, (GLuint*)addr_ptr(framebuffers)); | |
} | |
EXT_FUNC(void, Z_envZ__glDepthMaskZ_vi, u32 flag) { | |
FUNC("%u", flag); | |
glDepthMask(flag); | |
} | |
EXT_FUNC(void, Z_envZ__glDisableZ_vi, u32 cap) { | |
FUNC("%#x", cap); | |
glDisable(cap); | |
} | |
EXT_FUNC(void, Z_envZ__glDrawArraysZ_viii, u32 mode, u32 first, u32 count) { | |
FUNC("%#x %u %u", mode, first, count); | |
glDrawArrays(mode, first, count); | |
} | |
EXT_FUNC(void, Z_envZ__glEnableZ_vi, u32 cap) { | |
FUNC("%#x", cap); | |
glEnable(cap); | |
} | |
EXT_FUNC(void, Z_envZ__glEnableVertexAttribArrayZ_vi, u32 index) { | |
FUNC("%u", index); | |
glEnableVertexAttribArray(index); | |
} | |
EXT_FUNC(void, | |
Z_envZ__glFramebufferTexture2DZ_viiiii, | |
u32 target, | |
u32 attachment, | |
u32 textarget, | |
u32 texture, | |
u32 level) { | |
FUNC("%#x %#x %#x %u %u", target, attachment, textarget, texture, level); | |
glFramebufferTexture2D(target, attachment, textarget, texture, level); | |
} | |
EXT_FUNC(void, Z_envZ__glGenBuffersZ_vii, u32 n, u32 buffers) { | |
FUNC("%u %u", n, buffers); | |
assert(sizeof(u32) == sizeof(GLuint)); | |
glGenBuffers(n, (GLuint*)addr_ptr(buffers)); | |
u32 i; | |
for (i = 0; i < n; ++i) { | |
FUNCINFO("[%u] = %u\n", i, u32_load(buffers + i * 4)); | |
} | |
} | |
EXT_FUNC(void, Z_envZ__glGenFramebuffersZ_vii, u32 n, u32 framebuffers) { | |
FUNC("%u %u", n, framebuffers); | |
assert(sizeof(u32) == sizeof(GLuint)); | |
glGenFramebuffers(n, (GLuint*)addr_ptr(framebuffers)); | |
u32 i; | |
for (i = 0; i < n; ++i) { | |
FUNCINFO("[%u] = %u\n", i, u32_load(framebuffers + i * 4)); | |
} | |
} | |
EXT_FUNC(void, Z_envZ__glGenTexturesZ_vii, u32 n, u32 textures) { | |
FUNC("%u %u", n, textures); | |
assert(sizeof(u32) == sizeof(GLuint)); | |
glGenTextures(n, (GLuint*)addr_ptr(textures)); | |
u32 i; | |
for (i = 0; i < n; ++i) { | |
FUNCINFO("[%u] = %u\n", i, u32_load(textures + i * 4)); | |
} | |
} | |
EXT_FUNC(void, Z_envZ__glGetIntegervZ_vii, u32 pname, u32 params) { | |
FUNC("%#x %u", pname, params); | |
assert(sizeof(u32) == sizeof(GLint)); | |
glGetIntegerv(pname, (GLint*)addr_ptr(params)); | |
} | |
EXT_FUNC(void, Z_envZ__glLinkProgramZ_vi, u32 program) { | |
FUNC("%u", program); | |
glLinkProgram(program); | |
} | |
EXT_FUNC(void, | |
Z_envZ__glShaderSourceZ_viiii, | |
u32 shader, | |
u32 count, | |
u32 string_p, | |
u32 length_p) { | |
FUNC("%u %u %u %u", shader, count, string_p, length_p); | |
const GLchar *strings[count + 1]; | |
const GLint* length = length_p ? (const GLint*)addr_ptr(length_p) : NULL; | |
u32 i; | |
strings[0] = "#version 100\n"; | |
for (i = 0; i < count; ++i) { | |
strings[i + 1] = (const GLchar*)addr_ptr(u32_load(string_p + i * 4)); | |
FUNCINFO("source[%u]: %s\n", i, strings[i + 1]); | |
} | |
glShaderSource(shader, count + 1, strings, length); | |
} | |
EXT_FUNC(void, | |
Z_envZ__glTexImage2DZ_viiiiiiiii, | |
u32 target, | |
u32 level, | |
u32 internal_format, | |
u32 width, | |
u32 height, | |
u32 border, | |
u32 format, | |
u32 type, | |
u32 pixels) { | |
FUNC("%#x %u %#x %u %u %u %#x %#x %u", target, level, internal_format, width, | |
height, border, format, type, pixels); | |
glTexImage2D(target, level, internal_format, width, height, border, format, | |
type, addr_ptr(pixels)); | |
} | |
EXT_FUNC(void, | |
Z_envZ__glTexParameteriZ_viii, | |
u32 target, | |
u32 pname, | |
u32 param) { | |
FUNC("%#x %#x %#x", target, pname, param); | |
glTexParameteri(target, pname, param); | |
} | |
EXT_FUNC(void, Z_envZ__glUniform1fZ_vid, u32 location, f64 v0) { | |
FUNC("%u %f", location, v0); | |
glUniform1f(location, v0); | |
} | |
EXT_FUNC(void, Z_envZ__glUniform1iZ_vii, u32 location, u32 v0) { | |
FUNC("%u %u", location, v0); | |
glUniform1i(location, v0); | |
} | |
EXT_FUNC(void, | |
Z_envZ__glUniformMatrix4fvZ_viiii, | |
u32 location, | |
u32 count, | |
u32 transpose, | |
u32 value) { | |
FUNC("%u %u %u %u", location, count, transpose, value); | |
glUniformMatrix4fv(location, count, transpose, | |
(const GLfloat*)addr_ptr(value)); | |
} | |
EXT_FUNC(void, Z_envZ__glUseProgramZ_vi, u32 program) { | |
FUNC("%u", program); | |
glUseProgram(program); | |
} | |
EXT_FUNC(void, | |
Z_envZ__glVertexAttribPointerZ_viiiiii, | |
u32 index, | |
u32 size, | |
u32 type, | |
u32 normalized, | |
u32 stride, | |
u32 pointer) { | |
FUNC("%u %u %#x %u %u %u", index, size, type, normalized, stride, pointer); | |
glVertexAttribPointer(index, size, type, normalized, stride, | |
(const GLvoid*)(uintptr_t)pointer); | |
} | |
EXT_FUNC(void, Z_envZ__glViewportZ_viiii, u32 x, u32 y, u32 width, u32 height) { | |
FUNC("%u %u %u %u", x, y, width, height); | |
glViewport(x, y, width, height); | |
} | |
EXT_FUNC(void, Z_envZ____lockZ_vi, u32 p0) { | |
assert(0); | |
} | |
EXT_FUNC(void, Z_envZ____setErrNoZ_vi, u32 p0) { | |
assert(0); | |
} | |
EXT_FUNC(void, Z_envZ____unlockZ_vi, u32 p0) { | |
assert(0); | |
} | |
const u32 TOTAL_STACK = 5242880; | |
const u32 TOTAL_MEMORY = 33554432; | |
const u32 STATIC_BASE = 1024; | |
const u32 TABLE_SIZE = 1845; | |
void init_memory(void) { | |
u32 STATICTOP = STATIC_BASE + 1939872; | |
const size_t mem_size = TOTAL_MEMORY; | |
Z_envZ_memory->data = calloc(mem_size, 1); | |
Z_envZ_memory->pages = Z_envZ_memory->max_pages = 512; | |
Z_envZ_memory->size = mem_size; | |
*Z_envZ_tempDoublePtrZ_i = STATICTOP; STATICTOP += 16; | |
*Z_envZ_DYNAMICTOP_PTRZ_i = STATICTOP; STATICTOP += 4; | |
*Z_envZ_STACKTOPZ_i = (STATICTOP + 15) & ~15; | |
u32 STACK_BASE = *Z_envZ_STACKTOPZ_i; | |
*Z_envZ_STACK_MAXZ_i = STACK_BASE + TOTAL_STACK; | |
u32 DYNAMIC_BASE = (*Z_envZ_STACK_MAXZ_i + 15) & ~15; | |
u32_store(*Z_envZ_DYNAMICTOP_PTRZ_i, DYNAMIC_BASE); | |
} | |
void init_table(void) { | |
const size_t table_size = TABLE_SIZE; | |
Z_envZ_table->data = calloc(table_size, sizeof(wasm_rt_elem_t)); | |
Z_envZ_table->size = table_size; | |
*Z_envZ_tableBaseZ_i = 0; | |
} | |
static void poll_events(bool* running); | |
static void queue_audio(void); | |
void do_main(void) { | |
u32 argc = 1; | |
u32 arg0 = string_dup("thisProgram"); | |
u32 argv = Z__mallocZ_ii((argc + 1) * sizeof(u32)); | |
u32_store(argv, arg0); | |
u32_store(argv + 4, 0); | |
u32 ret = Z__mainZ_iii(argc, argv); | |
DEBUG("Z__main returned %d\n", ret); | |
if (mainloop_func) { | |
GLenum error = glGetError(); | |
if (error != 0) { | |
DEBUG("glGetError = %u\n", error); | |
return; | |
} | |
bool running = true; | |
while (running) { | |
DEBUG("--- frame ---\n"); | |
Z_dynCall_vZ_vi(mainloop_func); | |
poll_events(&running); | |
queue_audio(); | |
SDL_GL_SwapWindow(window); | |
} | |
} | |
} | |
static void window_size_callback(int width, int height); | |
static void window_focus_callback(int focused); | |
static void window_iconify_callback(int iconified); | |
static void key_callback(SDL_Event*); | |
static void mouse_button_callback(SDL_Event*); | |
static void poll_events(bool* running) { | |
SDL_Event event; | |
while (SDL_PollEvent(&event)) { | |
switch (event.type) { | |
case SDL_KEYDOWN: | |
case SDL_KEYUP: | |
key_callback(&event); | |
break; | |
case SDL_MOUSEBUTTONDOWN: | |
case SDL_MOUSEBUTTONUP: | |
mouse_button_callback(&event); | |
break; | |
case SDL_WINDOWEVENT: | |
switch (event.window.event) { | |
case SDL_WINDOWEVENT_SHOWN: | |
window_iconify_callback(0); | |
break; | |
case SDL_WINDOWEVENT_HIDDEN: | |
window_iconify_callback(1); | |
break; | |
case SDL_WINDOWEVENT_FOCUS_GAINED: | |
window_focus_callback(1); | |
break; | |
case SDL_WINDOWEVENT_FOCUS_LOST: | |
window_focus_callback(0); | |
break; | |
case SDL_WINDOWEVENT_RESIZED: | |
window_size_callback(event.window.data1, event.window.data2); | |
break; | |
} | |
break; | |
case SDL_QUIT: | |
*running = false; | |
break; | |
} | |
} | |
} | |
static void queue_audio(void) { | |
u32 bytes = SDL_GetQueuedAudioSize(audio_device); | |
if (bytes < audio_spec.size * 2) { | |
LOG("queueing audio... %u < %u (%u)\n", bytes, audio_spec.size * 2, | |
playing_audio_fx_count); | |
int i; | |
for (i = 0; i < 8; ++i) { | |
Z__Midi_FillBuffersZ_vii(audio_left_p + 512 * 4 * i, | |
audio_right_p + 512 * 4 * i); | |
} | |
// Interleave data and queue it. | |
const f32* midi_left = (const f32*)addr_ptr(audio_left_p); | |
const f32* midi_right = (const f32*)addr_ptr(audio_right_p); | |
f32 mix_buf[512 * 8 * 2] = {0}; | |
for (i = 0; i < 512 * 8; ++i) { | |
f32 left = midi_left[i] * midi_volume; | |
f32 right = midi_right[i] * midi_volume; | |
int j; | |
for (j = 0; j < playing_audio_fx_count; ++j) { | |
PlayingAudioFX* playing = &playing_audio_fx[j]; | |
left += playing->loaded->buf[playing->offset++] * fx_volume; | |
right += playing->loaded->buf[playing->offset++] * fx_volume; | |
if (playing->offset >= playing->loaded->len) { | |
memmove(playing, &playing_audio_fx[--playing_audio_fx_count], | |
sizeof(PlayingAudioFX)); | |
--j; | |
} | |
} | |
mix_buf[2*i] = left < -1 ? -1 : left > 1 ? 1 : left; | |
mix_buf[2*i+1] = right < -1 ? -1 : right > 1 ? 1: right; | |
} | |
SDL_QueueAudio(audio_device, mix_buf, sizeof(mix_buf)); | |
} | |
} | |
static void do_event_callback(Callback* cb) { | |
Z_dynCall_iiiiZ_iiiii(cb->func, cb->id, cb->ptr, cb->user_data); | |
} | |
static void window_size_callback(int width, int height) { | |
LOG("-> %s: %d %d\n", __func__, width, height); | |
u32_store(on_resize.ptr, 0); // e.detail | |
u32_store(on_resize.ptr + 4, width); // document.body.clientWidth | |
u32_store(on_resize.ptr + 8, height); // document.body.clientHeight | |
u32_store(on_resize.ptr + 12, width); // window.innerWidth | |
u32_store(on_resize.ptr + 16, height); // window.innerHeight | |
u32_store(on_resize.ptr + 20, width); // window.outerWidth | |
u32_store(on_resize.ptr + 24, height); // window.outerHeight | |
u32_store(on_resize.ptr + 28, 0); // scrollPos[0] | |
u32_store(on_resize.ptr + 32, 0); // scrollPos[1] | |
do_event_callback(&on_resize); | |
} | |
static void window_focus_callback(int focused) { | |
LOG("-> %s: %d\n", __func__, focused); | |
Callback* cb = focused ? &on_focus : &on_blur; | |
string_copy_n(cb->ptr, "#display", 128); | |
string_copy_n(cb->ptr + 128, "", 128); | |
do_event_callback(cb); | |
} | |
static void window_iconify_callback(int iconified) { | |
enum { HIDDEN = 0, VISIBLE = 1, PRERENDER = 2, UNLOADED = 3 }; | |
LOG("-> %s: %d\n", __func__, iconified); | |
u32_store(on_resize.ptr, iconified); // document.hidden | |
u32_store(on_resize.ptr + 4, | |
iconified ? HIDDEN : VISIBLE); // visibility state | |
do_event_callback(&on_resize); | |
} | |
static void key_callback(SDL_Event* event) { | |
u32 type = event->type; | |
SDL_Keycode key = event->key.keysym.sym; | |
SDL_Scancode scancode = event->key.keysym.scancode; | |
u16 mods = event->key.keysym.mod; | |
LOG("-> %s: %u %u %u %u\n", __func__, type, key, scancode, mods); | |
Callback* cb = NULL; | |
switch (type) { | |
case SDL_KEYDOWN: cb = &on_keydown; break; | |
case SDL_KEYUP: cb = &on_keyup; break; | |
} | |
char* key_string = ""; | |
char* code_string = ""; | |
char* char_string = ""; | |
u32 char_code = 0; | |
u32 key_code; | |
switch (key) { | |
case SDLK_RETURN: | |
key_string = "Enter"; | |
key_code = 0xd; | |
break; | |
case SDLK_UP: | |
key_string = "ArrowUp"; | |
key_code = 0x26; | |
break; | |
case SDLK_DOWN: | |
key_string = "ArrowDown"; | |
key_code = 0x28; | |
break; | |
case SDLK_LEFT: | |
key_string = "ArrowLeft"; | |
key_code = 0x25; | |
break; | |
case SDLK_RIGHT: | |
key_string = "ArrowRight"; | |
key_code = 0x27; | |
break; | |
} | |
// TODO(binji): uggggh | |
assert(cb); | |
string_copy_n(cb->ptr, key_string, 32); // e.key | |
string_copy_n(cb->ptr + 32, code_string, 32); // e.code | |
u32_store(cb->ptr + 64, 0); // e.location | |
u32_store(cb->ptr + 68, !!(mods & KMOD_CTRL)); // e.ctrlKey | |
u32_store(cb->ptr + 72, !!(mods & KMOD_SHIFT)); // e.shiftKey | |
u32_store(cb->ptr + 76, !!(mods & KMOD_ALT)); // e.altKey | |
u32_store(cb->ptr + 80, !!(mods & KMOD_GUI)); // e.metaKey | |
u32_store(cb->ptr + 84, !!event->key.repeat); // e.repeat | |
string_copy_n(cb->ptr + 88, "", 32); // e.locale | |
string_copy_n(cb->ptr + 120, char_string, 32); // e.char | |
u32_store(cb->ptr + 152, char_code); // e.charCode | |
u32_store(cb->ptr + 156, key_code); // e.keyCode | |
u32_store(cb->ptr + 160, key_code); // e.which | |
do_event_callback(cb); | |
} | |
static void mouse_button_callback(SDL_Event* event) { | |
u8 button = event->button.button; | |
u8 state = event->button.state; | |
u8 mod = 0; | |
LOG("-> %s: %u %u %u\n", __func__, button, state, mod); | |
s32 x = event->button.x; | |
s32 y = event->button.y; | |
Callback* cb = state == SDL_PRESSED ? &on_mousedown : &on_mouseup; | |
u32 buttons = SDL_GetMouseState(NULL, NULL); | |
f64_store(cb->ptr, 0); // tick | |
u32_store(cb->ptr + 8, (u32)x); // e.screenX | |
u32_store(cb->ptr + 12, (u32)y); // e.screenY | |
u32_store(cb->ptr + 16, (u32)x); // e.clientX | |
u32_store(cb->ptr + 20, (u32)y); // e.clientY | |
u32_store(cb->ptr + 24, !!(mod & KMOD_CTRL)); // e.ctrlKey | |
u32_store(cb->ptr + 28, !!(mod & KMOD_SHIFT)); // e.shiftKey | |
u32_store(cb->ptr + 32, !!(mod & KMOD_ALT)); // e.altKey | |
u32_store(cb->ptr + 36, !!(mod & KMOD_GUI)); // e.metaKey | |
u16_store(cb->ptr + 40, button); // e.button | |
u16_store(cb->ptr + 42, buttons); // e.buttons | |
u32_store(cb->ptr + 44, 0); // e.movementX | |
u32_store(cb->ptr + 48, 0); // e.movementY | |
u32_store(cb->ptr + 52, 0); // e.clientX - target rect.left | |
u32_store(cb->ptr + 56, 0); // e.clientY - target rect.top | |
u32_store(cb->ptr + 60, 0); // e.clientX - canvas rect.left | |
u32_store(cb->ptr + 64, 0); // e.clientY - canvas rect.top | |
do_event_callback(cb); | |
} | |
int main(int argc, char** argv) { | |
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) | |
return -1; | |
init_memory(); | |
init_table(); | |
init(); | |
Z___GLOBAL__sub_I_web_main_cppZ_vv(); | |
Z___GLOBAL__sub_I_condition_cppZ_vv(); | |
Z___GLOBAL__sub_I_engine_cppZ_vv(); | |
Z___GLOBAL__sub_I_particle_cppZ_vv(); | |
Z___GLOBAL__sub_I_vmath_cppZ_vv(); | |
do_main(); | |
SDL_Quit(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment