Skip to content

Instantly share code, notes, and snippets.

@binji
Created January 8, 2019 16:54
Show Gist options
  • Save binji/301f3f720c2fa0f64147eb9cf02a2540 to your computer and use it in GitHub Desktop.
Save binji/301f3f720c2fa0f64147eb9cf02a2540 to your computer and use it in GitHub Desktop.
FunkyKarts wasm2c main
#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