Initial commit. Refactor successful
This commit is contained in:
parent
d999a6fc5a
commit
559544b3bb
|
|
@ -0,0 +1,11 @@
|
|||
project (fugg)
|
||||
cmake_minimum_required(VERSION 3.5.1)
|
||||
|
||||
set(CMAKE_C_FLAGS "-Os")
|
||||
set(CMAKE_CXX_FLAGS "-Os")
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
|
||||
set(CMAKE_EXECUTABLE_SUFFIX ".js")
|
||||
|
||||
add_subdirectory(flyff-client)
|
||||
add_subdirectory(fugg-core)
|
||||
add_subdirectory(fugg-client)
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
add_subdirectory("wasm-rt")
|
||||
|
||||
add_library (
|
||||
flyff-client
|
||||
"src/client.cpp"
|
||||
"include/client.h"
|
||||
)
|
||||
|
||||
target_include_directories(flyff-client PUBLIC "include")
|
||||
target_link_libraries (flyff-client LINK_PUBLIC wasm-rt)
|
||||
|
|
@ -0,0 +1 @@
|
|||
# Decompiled Flyff Universe source
|
||||
|
|
@ -0,0 +1,405 @@
|
|||
/* Automatically generated by wasm2c */
|
||||
#ifndef CLIENT_H_GENERATED_
|
||||
#define CLIENT_H_GENERATED_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "wasm-rt.h"
|
||||
|
||||
/* TODO(binji): only use stdint.h types in header */
|
||||
#ifndef WASM_RT_CORE_TYPES_DEFINED
|
||||
#define WASM_RT_CORE_TYPES_DEFINED
|
||||
typedef uint8_t u8;
|
||||
typedef int8_t s8;
|
||||
typedef uint16_t u16;
|
||||
typedef int16_t s16;
|
||||
typedef uint32_t u32;
|
||||
typedef int32_t s32;
|
||||
typedef uint64_t u64;
|
||||
typedef int64_t s64;
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* import: 'env' '_abort' */
|
||||
extern void (*Z_envZ__abort)(void);
|
||||
/* import: 'env' '__emval_decref' */
|
||||
extern void (*Z_envZ___emval_decref)(u32);
|
||||
/* import: 'env' '__emval_new_cstring' */
|
||||
extern u32 (*Z_envZ___emval_new_cstring)(u32);
|
||||
/* import: 'env' '_glActiveTexture' */
|
||||
extern void (*Z_envZ__glActiveTexture)(u32);
|
||||
/* import: 'env' '_glBindTexture' */
|
||||
extern void (*Z_envZ__glBindTexture)(u32, u32);
|
||||
/* import: 'env' '_glVertexAttribPointer' */
|
||||
extern void (*Z_envZ__glVertexAttribPointer)(u32, u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_glDisableVertexAttribArray' */
|
||||
extern void (*Z_envZ__glDisableVertexAttribArray)(u32);
|
||||
/* import: 'env' '__emval_set_property' */
|
||||
extern void (*Z_envZ___emval_set_property)(u32, u32, u32);
|
||||
/* import: 'env' '__emval_get_property' */
|
||||
extern u32 (*Z_envZ___emval_get_property)(u32, u32);
|
||||
/* import: 'env' '_glUniformMatrix4fv' */
|
||||
extern void (*Z_envZ__glUniformMatrix4fv)(u32, u32, u32, u32);
|
||||
/* import: 'env' '__emval_get_method_caller' */
|
||||
extern u32 (*Z_envZ___emval_get_method_caller)(u32, u32);
|
||||
/* import: 'env' '__emval_take_value' */
|
||||
extern u32 (*Z_envZ___emval_take_value)(u32, u32);
|
||||
/* import: 'env' '_glDisable' */
|
||||
extern void (*Z_envZ__glDisable)(u32);
|
||||
/* import: 'env' '_glBindBuffer' */
|
||||
extern void (*Z_envZ__glBindBuffer)(u32, u32);
|
||||
/* import: 'env' '__emval_run_destructors' */
|
||||
extern void (*Z_envZ___emval_run_destructors)(u32);
|
||||
/* import: 'env' '_glUniform1f' */
|
||||
extern void (*Z_envZ__glUniform1f)(u32, f32);
|
||||
/* import: 'env' '_glEnable' */
|
||||
extern void (*Z_envZ__glEnable)(u32);
|
||||
/* import: 'env' '__emval_get_global' */
|
||||
extern u32 (*Z_envZ___emval_get_global)(u32);
|
||||
/* import: 'env' '_glTexParameteri' */
|
||||
extern void (*Z_envZ__glTexParameteri)(u32, u32, u32);
|
||||
/* import: 'env' '__emval_call_void_method' */
|
||||
extern void (*Z_envZ___emval_call_void_method)(u32, u32, u32, u32);
|
||||
/* import: 'env' '_alSourcef' */
|
||||
extern void (*Z_envZ__alSourcef)(u32, u32, f32);
|
||||
/* import: 'env' '_glUseProgram' */
|
||||
extern void (*Z_envZ__glUseProgram)(u32);
|
||||
/* import: 'env' '_glEnableVertexAttribArray' */
|
||||
extern void (*Z_envZ__glEnableVertexAttribArray)(u32);
|
||||
/* import: 'env' '_alSourcei' */
|
||||
extern void (*Z_envZ__alSourcei)(u32, u32, u32);
|
||||
/* import: 'env' '__emval_as' */
|
||||
extern f64 (*Z_envZ___emval_as)(u32, u32, u32);
|
||||
/* import: 'env' '_glDrawArrays' */
|
||||
extern void (*Z_envZ__glDrawArrays)(u32, u32, u32);
|
||||
/* import: 'env' '_glDepthMask' */
|
||||
extern void (*Z_envZ__glDepthMask)(u32);
|
||||
/* import: 'env' '_glBlendFunc' */
|
||||
extern void (*Z_envZ__glBlendFunc)(u32, u32);
|
||||
/* import: 'env' '_glBindFramebuffer' */
|
||||
extern void (*Z_envZ__glBindFramebuffer)(u32, u32);
|
||||
/* import: 'env' '_glDrawElements' */
|
||||
extern void (*Z_envZ__glDrawElements)(u32, u32, u32, u32);
|
||||
/* import: 'env' '__emval_incref' */
|
||||
extern void (*Z_envZ___emval_incref)(u32);
|
||||
/* import: 'env' '_alSourceStop' */
|
||||
extern void (*Z_envZ__alSourceStop)(u32);
|
||||
/* import: 'env' '_glGetUniformLocation' */
|
||||
extern u32 (*Z_envZ__glGetUniformLocation)(u32, u32);
|
||||
/* import: 'env' '__emval_call_method' */
|
||||
extern f64 (*Z_envZ___emval_call_method)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_glUniform3fv' */
|
||||
extern void (*Z_envZ__glUniform3fv)(u32, u32, u32);
|
||||
/* import: 'env' '__embind_register_memory_view' */
|
||||
extern void (*Z_envZ___embind_register_memory_view)(u32, u32, u32);
|
||||
/* import: 'env' '_glViewport' */
|
||||
extern void (*Z_envZ__glViewport)(u32, u32, u32, u32);
|
||||
/* import: 'env' '_glTexImage2D' */
|
||||
extern void (*Z_envZ__glTexImage2D)(u32, u32, u32, u32, u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_glGetError' */
|
||||
extern u32 (*Z_envZ__glGetError)(void);
|
||||
/* import: 'env' '_glDeleteFramebuffers' */
|
||||
extern void (*Z_envZ__glDeleteFramebuffers)(u32, u32);
|
||||
/* import: 'env' '_alGetSourcei' */
|
||||
extern void (*Z_envZ__alGetSourcei)(u32, u32, u32);
|
||||
/* import: 'env' '_glColorMask' */
|
||||
extern void (*Z_envZ__glColorMask)(u32, u32, u32, u32);
|
||||
/* import: 'env' '__embind_register_function' */
|
||||
extern void (*Z_envZ___embind_register_function)(u32, u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_alDeleteSources' */
|
||||
extern void (*Z_envZ__alDeleteSources)(u32, u32);
|
||||
/* import: 'env' '_glGenTextures' */
|
||||
extern void (*Z_envZ__glGenTextures)(u32, u32);
|
||||
/* import: 'env' '_glDeleteBuffers' */
|
||||
extern void (*Z_envZ__glDeleteBuffers)(u32, u32);
|
||||
/* import: 'env' '_glBufferData' */
|
||||
extern void (*Z_envZ__glBufferData)(u32, u32, u32, u32);
|
||||
/* import: 'env' '_glGenBuffers' */
|
||||
extern void (*Z_envZ__glGenBuffers)(u32, u32);
|
||||
/* import: 'env' '_glScissor' */
|
||||
extern void (*Z_envZ__glScissor)(u32, u32, u32, u32);
|
||||
/* import: 'env' '_glStencilMask' */
|
||||
extern void (*Z_envZ__glStencilMask)(u32);
|
||||
/* import: 'env' '__embind_register_integer' */
|
||||
extern void (*Z_envZ___embind_register_integer)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_alSource3f' */
|
||||
extern void (*Z_envZ__alSource3f)(u32, u32, f32, f32, f32);
|
||||
/* import: 'env' '__emval_get_module_property' */
|
||||
extern u32 (*Z_envZ___emval_get_module_property)(u32);
|
||||
/* import: 'env' '_glFramebufferTexture2D' */
|
||||
extern void (*Z_envZ__glFramebufferTexture2D)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_glUniform2f' */
|
||||
extern void (*Z_envZ__glUniform2f)(u32, f32, f32);
|
||||
/* import: 'env' '_glUniform2fv' */
|
||||
extern void (*Z_envZ__glUniform2fv)(u32, u32, u32);
|
||||
/* import: 'env' '_glFrontFace' */
|
||||
extern void (*Z_envZ__glFrontFace)(u32);
|
||||
/* import: 'env' '_glGenFramebuffers' */
|
||||
extern void (*Z_envZ__glGenFramebuffers)(u32, u32);
|
||||
/* import: 'env' '__emval_typeof' */
|
||||
extern u32 (*Z_envZ___emval_typeof)(u32);
|
||||
/* import: 'env' '_emscripten_vibrate' */
|
||||
extern u32 (*Z_envZ__emscripten_vibrate)(u32);
|
||||
/* import: 'env' '_glUniform1i' */
|
||||
extern void (*Z_envZ__glUniform1i)(u32, u32);
|
||||
/* import: 'env' '_glGetProgramiv' */
|
||||
extern void (*Z_envZ__glGetProgramiv)(u32, u32, u32);
|
||||
/* import: 'env' '_glCheckFramebufferStatus' */
|
||||
extern u32 (*Z_envZ__glCheckFramebufferStatus)(u32);
|
||||
/* import: 'env' '_glClear' */
|
||||
extern void (*Z_envZ__glClear)(u32);
|
||||
/* import: 'env' '_glStencilFunc' */
|
||||
extern void (*Z_envZ__glStencilFunc)(u32, u32, u32);
|
||||
/* import: 'env' '_glGetIntegerv' */
|
||||
extern void (*Z_envZ__glGetIntegerv)(u32, u32);
|
||||
/* import: 'env' '_emscripten_exit_fullscreen' */
|
||||
extern u32 (*Z_envZ__emscripten_exit_fullscreen)(void);
|
||||
/* import: 'env' '_emscripten_request_fullscreen' */
|
||||
extern u32 (*Z_envZ__emscripten_request_fullscreen)(u32, u32);
|
||||
/* import: 'env' '_emscripten_performance_now' */
|
||||
extern f64 (*Z_envZ__emscripten_performance_now)(void);
|
||||
/* import: 'env' '_emscripten_cancel_main_loop' */
|
||||
extern void (*Z_envZ__emscripten_cancel_main_loop)(void);
|
||||
/* import: 'env' '_emscripten_set_main_loop' */
|
||||
extern void (*Z_envZ__emscripten_set_main_loop)(u32, u32, u32);
|
||||
/* import: 'env' '_glDetachShader' */
|
||||
extern void (*Z_envZ__glDetachShader)(u32, u32);
|
||||
/* import: 'env' '_emscripten_set_devicemotion_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_devicemotion_callback_on_thread)(u32, u32, u32, u32);
|
||||
/* import: 'env' '_glDeleteProgram' */
|
||||
extern void (*Z_envZ__glDeleteProgram)(u32);
|
||||
/* import: 'env' '__emval_new' */
|
||||
extern u32 (*Z_envZ___emval_new)(u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_beforeunload_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_beforeunload_callback_on_thread)(u32, u32, u32);
|
||||
/* import: 'env' '_glDeleteShader' */
|
||||
extern void (*Z_envZ__glDeleteShader)(u32);
|
||||
/* import: 'env' '_glDepthFunc' */
|
||||
extern void (*Z_envZ__glDepthFunc)(u32);
|
||||
/* import: 'env' '_emscripten_resize_heap' */
|
||||
extern u32 (*Z_envZ__emscripten_resize_heap)(u32);
|
||||
/* import: 'env' '__embind_register_std_wstring' */
|
||||
extern void (*Z_envZ___embind_register_std_wstring)(u32, u32, u32);
|
||||
/* import: 'env' '_strftime' */
|
||||
extern u32 (*Z_envZ__strftime)(u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_webglcontextrestored_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_webglcontextrestored_callback_on_thread)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_focusout_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_focusout_callback_on_thread)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_keyup_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_keyup_callback_on_thread)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_keydown_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_keydown_callback_on_thread)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_wheel_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_wheel_callback_on_thread)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_mouseleave_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_mouseleave_callback_on_thread)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_mousemove_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_mousemove_callback_on_thread)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_mouseup_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_mouseup_callback_on_thread)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_mousedown_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_mousedown_callback_on_thread)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_touchcancel_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_touchcancel_callback_on_thread)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_touchmove_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_touchmove_callback_on_thread)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_touchend_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_touchend_callback_on_thread)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_touchstart_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_touchstart_callback_on_thread)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_webgl_destroy_context' */
|
||||
extern u32 (*Z_envZ__emscripten_webgl_destroy_context)(u32);
|
||||
/* import: 'env' '_emscripten_set_orientationchange_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_orientationchange_callback_on_thread)(u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_resize_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_resize_callback_on_thread)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_visibilitychange_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_visibilitychange_callback_on_thread)(u32, u32, u32, u32);
|
||||
/* import: 'env' '_glClearColor' */
|
||||
extern void (*Z_envZ__glClearColor)(f32, f32, f32, f32);
|
||||
/* import: 'env' '_glGetProgramInfoLog' */
|
||||
extern void (*Z_envZ__glGetProgramInfoLog)(u32, u32, u32, u32);
|
||||
/* import: 'env' '_glLinkProgram' */
|
||||
extern void (*Z_envZ__glLinkProgram)(u32);
|
||||
/* import: 'env' '_glAttachShader' */
|
||||
extern void (*Z_envZ__glAttachShader)(u32, u32);
|
||||
/* import: 'env' '_glGetShaderiv' */
|
||||
extern void (*Z_envZ__glGetShaderiv)(u32, u32, u32);
|
||||
/* import: 'env' '_glLineWidth' */
|
||||
extern void (*Z_envZ__glLineWidth)(f32);
|
||||
/* import: 'env' '__emscripten_date_now' */
|
||||
extern f64 (*Z_envZ___emscripten_date_now)(void);
|
||||
/* import: 'env' '__embind_register_float' */
|
||||
extern void (*Z_envZ___embind_register_float)(u32, u32, u32);
|
||||
/* import: 'env' '__embind_register_std_string' */
|
||||
extern void (*Z_envZ___embind_register_std_string)(u32, u32);
|
||||
/* import: 'env' '_emscripten_async_wget_data' */
|
||||
extern void (*Z_envZ__emscripten_async_wget_data)(u32, u32, u32, u32);
|
||||
/* import: 'env' '_alSourcePlay' */
|
||||
extern void (*Z_envZ__alSourcePlay)(u32);
|
||||
/* import: 'env' '_alListenerfv' */
|
||||
extern void (*Z_envZ__alListenerfv)(u32, u32);
|
||||
/* import: 'env' '_alListener3f' */
|
||||
extern void (*Z_envZ__alListener3f)(u32, f32, f32, f32);
|
||||
/* import: 'env' '_emscripten_set_webglcontextlost_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_webglcontextlost_callback_on_thread)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_element_css_size' */
|
||||
extern u32 (*Z_envZ__emscripten_set_element_css_size)(u32, f64, f64);
|
||||
/* import: 'env' '_emscripten_set_canvas_element_size' */
|
||||
extern u32 (*Z_envZ__emscripten_set_canvas_element_size)(u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_webgl_make_context_current' */
|
||||
extern u32 (*Z_envZ__emscripten_webgl_make_context_current)(u32);
|
||||
/* import: 'env' '_emscripten_webgl_create_context' */
|
||||
extern u32 (*Z_envZ__emscripten_webgl_create_context)(u32, u32);
|
||||
/* import: 'env' '_emscripten_webgl_init_context_attributes' */
|
||||
extern void (*Z_envZ__emscripten_webgl_init_context_attributes)(u32);
|
||||
/* import: 'env' '_glUniform4f' */
|
||||
extern void (*Z_envZ__glUniform4f)(u32, f32, f32, f32, f32);
|
||||
/* import: 'env' '_glCompressedTexImage2D' */
|
||||
extern void (*Z_envZ__glCompressedTexImage2D)(u32, u32, u32, u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_glBindAttribLocation' */
|
||||
extern void (*Z_envZ__glBindAttribLocation)(u32, u32, u32);
|
||||
/* import: 'env' '_glGetActiveAttrib' */
|
||||
extern void (*Z_envZ__glGetActiveAttrib)(u32, u32, u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_get_orientation_status' */
|
||||
extern u32 (*Z_envZ__emscripten_get_orientation_status)(u32);
|
||||
/* import: 'env' '_glCreateProgram' */
|
||||
extern u32 (*Z_envZ__glCreateProgram)(void);
|
||||
/* import: 'env' '_glGetShaderInfoLog' */
|
||||
extern void (*Z_envZ__glGetShaderInfoLog)(u32, u32, u32, u32);
|
||||
/* import: 'env' '_glCompileShader' */
|
||||
extern void (*Z_envZ__glCompileShader)(u32);
|
||||
/* import: 'env' '_glShaderSource' */
|
||||
extern void (*Z_envZ__glShaderSource)(u32, u32, u32, u32);
|
||||
/* import: 'env' '_glCreateShader' */
|
||||
extern u32 (*Z_envZ__glCreateShader)(u32);
|
||||
/* import: 'env' '_glCullFace' */
|
||||
extern void (*Z_envZ__glCullFace)(u32);
|
||||
/* import: 'env' '_emscripten_webgl_enable_extension' */
|
||||
extern u32 (*Z_envZ__emscripten_webgl_enable_extension)(u32, u32);
|
||||
/* import: 'env' '_glGetString' */
|
||||
extern u32 (*Z_envZ__glGetString)(u32);
|
||||
/* import: 'env' '_glStencilOp' */
|
||||
extern void (*Z_envZ__glStencilOp)(u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_set_fullscreenchange_callback_on_thread' */
|
||||
extern u32 (*Z_envZ__emscripten_set_fullscreenchange_callback_on_thread)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_glDeleteTextures' */
|
||||
extern void (*Z_envZ__glDeleteTextures)(u32, u32);
|
||||
/* import: 'env' '_fd_seek' */
|
||||
extern u32 (*Z_envZ__fd_seek)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '__embind_register_bigint' */
|
||||
extern void (*Z_envZ___embind_register_bigint)(u32, u32, u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_strftime_l' */
|
||||
extern u32 (*Z_envZ__strftime_l)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_environ_get' */
|
||||
extern u32 (*Z_envZ__environ_get)(u32, u32);
|
||||
/* import: 'env' '_environ_sizes_get' */
|
||||
extern u32 (*Z_envZ__environ_sizes_get)(u32, u32);
|
||||
/* import: 'env' '_fd_close' */
|
||||
extern u32 (*Z_envZ__fd_close)(u32);
|
||||
/* import: 'env' '_fd_write' */
|
||||
extern u32 (*Z_envZ__fd_write)(u32, u32, u32, u32);
|
||||
/* import: 'env' '_emscripten_memcpy_big' */
|
||||
extern void (*Z_envZ__emscripten_memcpy_big)(u32, u32, u32);
|
||||
/* import: 'env' '__emscripten_get_now_is_monotonic' */
|
||||
extern u32 (*Z_envZ___emscripten_get_now_is_monotonic)(void);
|
||||
/* import: 'env' '__gmtime_js' */
|
||||
extern void (*Z_envZ___gmtime_js)(u32, u32);
|
||||
/* import: 'env' '__localtime_js' */
|
||||
extern void (*Z_envZ___localtime_js)(u32, u32);
|
||||
/* import: 'env' '__mktime_js' */
|
||||
extern u32 (*Z_envZ___mktime_js)(u32);
|
||||
/* import: 'env' '__tzset_js' */
|
||||
extern void (*Z_envZ___tzset_js)(u32, u32, u32);
|
||||
/* import: 'env' '_glCopyTexSubImage2D' */
|
||||
extern void (*Z_envZ__glCopyTexSubImage2D)(u32, u32, u32, u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '__embind_register_emval' */
|
||||
extern void (*Z_envZ___embind_register_emval)(u32, u32);
|
||||
/* import: 'env' '__embind_register_bool' */
|
||||
extern void (*Z_envZ___embind_register_bool)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '__embind_register_void' */
|
||||
extern void (*Z_envZ___embind_register_void)(u32, u32);
|
||||
/* import: 'env' '_emscripten_log' */
|
||||
extern void (*Z_envZ__emscripten_log)(u32, u32, u32);
|
||||
/* import: 'env' '_alDeleteBuffers' */
|
||||
extern void (*Z_envZ__alDeleteBuffers)(u32, u32);
|
||||
/* import: 'env' '_alBufferData' */
|
||||
extern void (*Z_envZ__alBufferData)(u32, u32, u32, u32, u32);
|
||||
/* import: 'env' '_alGenBuffers' */
|
||||
extern void (*Z_envZ__alGenBuffers)(u32, u32);
|
||||
/* import: 'env' '_alGetEnumValue' */
|
||||
extern u32 (*Z_envZ__alGetEnumValue)(u32);
|
||||
/* import: 'env' '_alcCloseDevice' */
|
||||
extern u32 (*Z_envZ__alcCloseDevice)(u32);
|
||||
/* import: 'env' '_alcDestroyContext' */
|
||||
extern void (*Z_envZ__alcDestroyContext)(u32);
|
||||
/* import: 'env' '_alGenSources' */
|
||||
extern void (*Z_envZ__alGenSources)(u32, u32);
|
||||
/* import: 'env' '_alListenerf' */
|
||||
extern void (*Z_envZ__alListenerf)(u32, f32);
|
||||
/* import: 'env' '_alcMakeContextCurrent' */
|
||||
extern u32 (*Z_envZ__alcMakeContextCurrent)(u32);
|
||||
/* import: 'env' '_alcCreateContext' */
|
||||
extern u32 (*Z_envZ__alcCreateContext)(u32, u32);
|
||||
/* import: 'env' '_alcOpenDevice' */
|
||||
extern u32 (*Z_envZ__alcOpenDevice)(u32);
|
||||
/* import: 'env' '_emscripten_get_fullscreen_status' */
|
||||
extern u32 (*Z_envZ__emscripten_get_fullscreen_status)(u32);
|
||||
/* import: 'env' '_emscripten_force_exit' */
|
||||
extern void (*Z_envZ__emscripten_force_exit)(u32);
|
||||
/* import: 'env' '_glTexSubImage2D' */
|
||||
extern void (*Z_envZ__glTexSubImage2D)(u32, u32, u32, u32, u32, u32, u32, u32, u32);
|
||||
void Z_client_init(void);
|
||||
void Z_client_free(void);
|
||||
|
||||
/* export: 'memory' */
|
||||
extern wasm_rt_memory_t (*Z_clientZ_memory);
|
||||
/* export: '___wasm_call_ctors' */
|
||||
extern void (*Z_clientZ____wasm_call_ctors)(void);
|
||||
/* export: '_malloc' */
|
||||
extern u32 (*Z_clientZ__malloc)(u32);
|
||||
/* export: '_free' */
|
||||
extern void (*Z_clientZ__free)(u32);
|
||||
/* export: '_main' */
|
||||
extern u32 (*Z_clientZ__main)(u32, u32);
|
||||
/* export: '___getTypeName' */
|
||||
extern u32 (*Z_clientZ____getTypeName)(u32);
|
||||
/* export: '__embind_initialize_bindings' */
|
||||
extern void (*Z_clientZ___embind_initialize_bindings)(void);
|
||||
/* export: 'table' */
|
||||
extern wasm_rt_table_t (*Z_clientZ_table);
|
||||
/* export: 'stackSave' */
|
||||
extern u32 (*Z_clientZ_stackSave)(void);
|
||||
/* export: 'stackRestore' */
|
||||
extern void (*Z_clientZ_stackRestore)(u32);
|
||||
/* export: 'stackAlloc' */
|
||||
extern u32 (*Z_clientZ_stackAlloc)(u32);
|
||||
/* export: 'dynCall_vij' */
|
||||
extern void (*Z_clientZ_dynCall_vij)(u32, u32, u32, u32);
|
||||
/* export: 'dynCall_ji' */
|
||||
extern u32 (*Z_clientZ_dynCall_ji)(u32, u32);
|
||||
/* export: 'dynCall_iiiijiii' */
|
||||
extern u32 (*Z_clientZ_dynCall_iiiijiii)(u32, u32, u32, u32, u32, u32, u32, u32, u32);
|
||||
/* export: 'dynCall_viijii' */
|
||||
extern void (*Z_clientZ_dynCall_viijii)(u32, u32, u32, u32, u32, u32, u32);
|
||||
/* export: 'dynCall_iiiiij' */
|
||||
extern u32 (*Z_clientZ_dynCall_iiiiij)(u32, u32, u32, u32, u32, u32, u32);
|
||||
/* export: 'dynCall_iiiiijj' */
|
||||
extern u32 (*Z_clientZ_dynCall_iiiiijj)(u32, u32, u32, u32, u32, u32, u32, u32, u32);
|
||||
/* export: 'dynCall_iiiiiijj' */
|
||||
extern u32 (*Z_clientZ_dynCall_iiiiiijj)(u32, u32, u32, u32, u32, u32, u32, u32, u32, u32);
|
||||
/* export: 'dynCall_jiji' */
|
||||
extern u32 (*Z_clientZ_dynCall_jiji)(u32, u32, u32, u32, u32);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CLIENT_H_GENERATED_ */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,8 @@
|
|||
add_library (
|
||||
wasm-rt
|
||||
"src/wasm-rt-impl.cpp"
|
||||
"src/wasm-rt-impl.h"
|
||||
"include/wasm-rt.h"
|
||||
)
|
||||
|
||||
target_include_directories(wasm-rt PUBLIC "include")
|
||||
|
|
@ -0,0 +1,297 @@
|
|||
/*
|
||||
* Copyright 2018 WebAssembly Community Group participants
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WASM_RT_H_
|
||||
#define WASM_RT_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef WASM_SYMBOL
|
||||
#define WASM_SYMBOL(module, method) \
|
||||
Z_ ## module ## Z_ ## method
|
||||
#endif
|
||||
|
||||
#ifndef WASM_IMPORT_IMPL
|
||||
#define WASM_IMPORT_IMPL(module, method) \
|
||||
decltype(WASM_SYMBOL(module, method)) WASM_SYMBOL(module, method)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) 0 // Compatibility with non-clang compilers.
|
||||
#endif
|
||||
|
||||
#if __has_builtin(__builtin_expect)
|
||||
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
#define LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
#else
|
||||
#define UNLIKELY(x) (x)
|
||||
#define LIKELY(x) (x)
|
||||
#endif
|
||||
|
||||
#if __has_builtin(__builtin_memcpy)
|
||||
#define wasm_rt_memcpy __builtin_memcpy
|
||||
#else
|
||||
#define wasm_rt_memcpy memcpy
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Enable memory checking via a signal handler via the following definition:
|
||||
*
|
||||
* #define WASM_RT_MEMCHECK_SIGNAL_HANDLER 1
|
||||
*
|
||||
* This is usually 10%-25% faster, but requires OS-specific support.
|
||||
*/
|
||||
|
||||
/** Check whether the signal handler is supported at all. */
|
||||
#if (defined(__linux__) || defined(__unix__) || defined(__APPLE__)) && \
|
||||
defined(__WORDSIZE) && __WORDSIZE == 64
|
||||
|
||||
/* If the signal handler is supported, then use it by default. */
|
||||
#ifndef WASM_RT_MEMCHECK_SIGNAL_HANDLER
|
||||
#define WASM_RT_MEMCHECK_SIGNAL_HANDLER 1
|
||||
#endif
|
||||
|
||||
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER
|
||||
#define WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX 1
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
/* The signal handler is not supported, error out if the user was trying to
|
||||
* enable it. */
|
||||
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER
|
||||
#error "Signal handler is not supported for this OS/Architecture!"
|
||||
#endif
|
||||
|
||||
#define WASM_RT_MEMCHECK_SIGNAL_HANDLER 0
|
||||
#define WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX 0
|
||||
|
||||
/**
|
||||
* When the signal handler is not used, stack depth is limited explicitly.
|
||||
* The maximum stack depth before trapping can be configured by defining
|
||||
* this symbol before including wasm-rt when building the generated c files,
|
||||
* for example:
|
||||
*
|
||||
* ```
|
||||
* cc -c -DWASM_RT_MAX_CALL_STACK_DEPTH=100 my_module.c -o my_module.o
|
||||
* ```
|
||||
*/
|
||||
#ifndef WASM_RT_MAX_CALL_STACK_DEPTH
|
||||
#define WASM_RT_MAX_CALL_STACK_DEPTH 500
|
||||
#endif
|
||||
|
||||
/** Current call stack depth. */
|
||||
extern uint32_t wasm_rt_call_stack_depth;
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define WASM_RT_NO_RETURN __declspec(noreturn)
|
||||
#else
|
||||
#define WASM_RT_NO_RETURN __attribute__((noreturn))
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
|
||||
#define WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 1
|
||||
#else
|
||||
#define WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 0
|
||||
#endif
|
||||
|
||||
/** Reason a trap occurred. Provide this to `wasm_rt_trap`. */
|
||||
typedef enum {
|
||||
WASM_RT_TRAP_NONE, /** No error. */
|
||||
WASM_RT_TRAP_OOB, /** Out-of-bounds access in linear memory. */
|
||||
WASM_RT_TRAP_INT_OVERFLOW, /** Integer overflow on divide or truncation. */
|
||||
WASM_RT_TRAP_DIV_BY_ZERO, /** Integer divide by zero. */
|
||||
WASM_RT_TRAP_INVALID_CONVERSION, /** Conversion from NaN to integer. */
|
||||
WASM_RT_TRAP_UNREACHABLE, /** Unreachable instruction executed. */
|
||||
WASM_RT_TRAP_CALL_INDIRECT, /** Invalid call_indirect, for any reason. */
|
||||
#if WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS
|
||||
WASM_RT_TRAP_EXHAUSTION = WASM_RT_TRAP_OOB,
|
||||
#else
|
||||
WASM_RT_TRAP_EXHAUSTION, /** Call stack exhausted. */
|
||||
#endif
|
||||
} wasm_rt_trap_t;
|
||||
|
||||
/** Value types. Used to define function signatures. */
|
||||
typedef enum {
|
||||
WASM_RT_I32,
|
||||
WASM_RT_I64,
|
||||
WASM_RT_F32,
|
||||
WASM_RT_F64,
|
||||
} wasm_rt_type_t;
|
||||
|
||||
/**
|
||||
* A function type for all `funcref` functions in a Table. All functions are
|
||||
* stored in this canonical form, but must be cast to their proper signature to
|
||||
* call.
|
||||
*/
|
||||
typedef void (*wasm_rt_funcref_t)(void);
|
||||
|
||||
/** A single element of a Table. */
|
||||
typedef struct {
|
||||
/** The index as returned from `wasm_rt_register_func_type`. */
|
||||
uint32_t func_type;
|
||||
/** The function. The embedder must know the actual C signature of the
|
||||
* function and cast to it before calling. */
|
||||
wasm_rt_funcref_t func;
|
||||
} wasm_rt_elem_t;
|
||||
|
||||
/** A Memory object. */
|
||||
typedef struct {
|
||||
/** The linear memory data, with a byte length of `size`. */
|
||||
uint8_t* data;
|
||||
/** The current and maximum page count for this Memory object. If there is no
|
||||
* maximum, `max_pages` is 0xffffffffu (i.e. UINT32_MAX). */
|
||||
uint32_t pages, max_pages;
|
||||
/** The current size of the linear memory, in bytes. */
|
||||
uint32_t size;
|
||||
} wasm_rt_memory_t;
|
||||
|
||||
/** A Table object. */
|
||||
typedef struct {
|
||||
/** The table element data, with an element count of `size`. */
|
||||
wasm_rt_elem_t* data;
|
||||
/** The maximum element count of this Table object. If there is no maximum,
|
||||
* `max_size` is 0xffffffffu (i.e. UINT32_MAX). */
|
||||
uint32_t max_size;
|
||||
/** The current element count of the table. */
|
||||
uint32_t size;
|
||||
} wasm_rt_table_t;
|
||||
|
||||
/** Initialize the runtime. */
|
||||
void wasm_rt_init(void);
|
||||
|
||||
/** Free the runtime's state. */
|
||||
void wasm_rt_free(void);
|
||||
|
||||
/**
|
||||
* Stop execution immediately and jump back to the call to `wasm_rt_try`.
|
||||
* The result of `wasm_rt_try` will be the provided trap reason.
|
||||
*
|
||||
* This is typically called by the generated code, and not the embedder.
|
||||
*/
|
||||
WASM_RT_NO_RETURN void wasm_rt_trap(wasm_rt_trap_t);
|
||||
|
||||
/**
|
||||
* Return a human readable error string based on a trap type.
|
||||
*/
|
||||
const char* wasm_rt_strerror(wasm_rt_trap_t trap);
|
||||
|
||||
/**
|
||||
* Register a function type with the given signature. The returned function
|
||||
* index is guaranteed to be the same for all calls with the same signature.
|
||||
* The following varargs must all be of type `wasm_rt_type_t`, first the
|
||||
* params` and then the `results`.
|
||||
*
|
||||
* ```
|
||||
* // Register (func (param i32 f32) (result i64)).
|
||||
* wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_I64);
|
||||
* => returns 1
|
||||
*
|
||||
* // Register (func (result i64)).
|
||||
* wasm_rt_register_func_type(0, 1, WASM_RT_I32);
|
||||
* => returns 2
|
||||
*
|
||||
* // Register (func (param i32 f32) (result i64)) again.
|
||||
* wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_I64);
|
||||
* => returns 1
|
||||
* ```
|
||||
*/
|
||||
uint32_t wasm_rt_register_func_type(uint32_t params, uint32_t results, ...);
|
||||
|
||||
/**
|
||||
* Initialize a Memory object with an initial page size of `initial_pages` and
|
||||
* a maximum page size of `max_pages`.
|
||||
*
|
||||
* ```
|
||||
* wasm_rt_memory_t my_memory;
|
||||
* // 1 initial page (65536 bytes), and a maximum of 2 pages.
|
||||
* wasm_rt_allocate_memory(&my_memory, 1, 2);
|
||||
* ```
|
||||
*/
|
||||
void wasm_rt_allocate_memory(wasm_rt_memory_t*,
|
||||
uint32_t initial_pages,
|
||||
uint32_t max_pages);
|
||||
|
||||
/**
|
||||
* Grow a Memory object by `pages`, and return the previous page count. If
|
||||
* this new page count is greater than the maximum page count, the grow fails
|
||||
* and 0xffffffffu (UINT32_MAX) is returned instead.
|
||||
*
|
||||
* ```
|
||||
* wasm_rt_memory_t my_memory;
|
||||
* ...
|
||||
* // Grow memory by 10 pages.
|
||||
* uint32_t old_page_size = wasm_rt_grow_memory(&my_memory, 10);
|
||||
* if (old_page_size == UINT32_MAX) {
|
||||
* // Failed to grow memory.
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
uint32_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint32_t pages);
|
||||
|
||||
/**
|
||||
* Free a Memory object.
|
||||
*/
|
||||
void wasm_rt_free_memory(wasm_rt_memory_t*);
|
||||
|
||||
/**
|
||||
* Initialize a Table object with an element count of `elements` and a maximum
|
||||
* page size of `max_elements`.
|
||||
*
|
||||
* ```
|
||||
* wasm_rt_table_t my_table;
|
||||
* // 5 elemnets and a maximum of 10 elements.
|
||||
* wasm_rt_allocate_table(&my_table, 5, 10);
|
||||
* ```
|
||||
*/
|
||||
void wasm_rt_allocate_table(wasm_rt_table_t*,
|
||||
uint32_t elements,
|
||||
uint32_t max_elements);
|
||||
|
||||
/**
|
||||
* Free a Table object.
|
||||
*/
|
||||
void wasm_rt_free_table(wasm_rt_table_t*);
|
||||
|
||||
#ifdef _WIN32
|
||||
float wasm_rt_truncf(float x);
|
||||
double wasm_rt_trunc(double x);
|
||||
float wasm_rt_nearbyintf(float x);
|
||||
double wasm_rt_nearbyint(double x);
|
||||
float wasm_rt_fabsf(float x);
|
||||
double wasm_rt_fabs(double x);
|
||||
#else
|
||||
#define wasm_rt_truncf(x) truncf(x)
|
||||
#define wasm_rt_trunc(x) trunc(x)
|
||||
#define wasm_rt_nearbyintf(x) nearbyintf(x)
|
||||
#define wasm_rt_nearbyint(x) nearbyint(x)
|
||||
#define wasm_rt_fabsf(x) fabsf(x)
|
||||
#define wasm_rt_fabs(x) fabs(x)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WASM_RT_H_ */
|
||||
|
|
@ -0,0 +1,402 @@
|
|||
/*
|
||||
* Copyright 2018 WebAssembly Community Group participants
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "wasm-rt-impl.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// is not set for emcc.
|
||||
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#define PAGE_SIZE 65536
|
||||
|
||||
typedef struct FuncType {
|
||||
wasm_rt_type_t* params;
|
||||
wasm_rt_type_t* results;
|
||||
uint32_t param_count;
|
||||
uint32_t result_count;
|
||||
} FuncType;
|
||||
|
||||
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER
|
||||
bool g_signal_handler_installed = false;
|
||||
char* g_alt_stack;
|
||||
#else
|
||||
uint32_t wasm_rt_call_stack_depth;
|
||||
uint32_t g_saved_call_stack_depth;
|
||||
#endif
|
||||
|
||||
jmp_buf g_jmp_buf;
|
||||
FuncType* g_func_types;
|
||||
uint32_t g_func_type_count;
|
||||
|
||||
void wasm_rt_trap(wasm_rt_trap_t code) {
|
||||
printf("WASM Runtime trapped!: %s\n", wasm_rt_strerror(code));
|
||||
|
||||
assert(code != WASM_RT_TRAP_NONE);
|
||||
|
||||
#if !WASM_RT_MEMCHECK_SIGNAL_HANDLER
|
||||
wasm_rt_call_stack_depth = g_saved_call_stack_depth;
|
||||
#endif
|
||||
WASM_RT_LONGJMP(g_jmp_buf, code);
|
||||
}
|
||||
|
||||
static bool func_types_are_equal(FuncType* a, FuncType* b) {
|
||||
if (a->param_count != b->param_count || a->result_count != b->result_count)
|
||||
return 0;
|
||||
uint32_t i;
|
||||
for (i = 0; i < a->param_count; ++i)
|
||||
if (a->params[i] != b->params[i])
|
||||
return 0;
|
||||
for (i = 0; i < a->result_count; ++i)
|
||||
if (a->results[i] != b->results[i])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t wasm_rt_register_func_type(uint32_t param_count,
|
||||
uint32_t result_count,
|
||||
...) {
|
||||
FuncType func_type;
|
||||
func_type.param_count = param_count;
|
||||
func_type.params = (wasm_rt_type_t*)malloc(param_count * sizeof(wasm_rt_type_t));
|
||||
func_type.result_count = result_count;
|
||||
func_type.results = (wasm_rt_type_t*)malloc(result_count * sizeof(wasm_rt_type_t));
|
||||
|
||||
va_list args;
|
||||
va_start(args, result_count);
|
||||
|
||||
uint32_t i;
|
||||
for (i = 0; i < param_count; ++i)
|
||||
func_type.params[i] = va_arg(args, wasm_rt_type_t);
|
||||
for (i = 0; i < result_count; ++i)
|
||||
func_type.results[i] = va_arg(args, wasm_rt_type_t);
|
||||
va_end(args);
|
||||
|
||||
for (i = 0; i < g_func_type_count; ++i) {
|
||||
if (func_types_are_equal(&g_func_types[i], &func_type)) {
|
||||
free(func_type.params);
|
||||
free(func_type.results);
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t idx = g_func_type_count++;
|
||||
g_func_types = (FuncType*)realloc(g_func_types, g_func_type_count * sizeof(FuncType));
|
||||
g_func_types[idx] = func_type;
|
||||
return idx + 1;
|
||||
}
|
||||
|
||||
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
|
||||
static void signal_handler(int sig, siginfo_t* si, void* unused) {
|
||||
if (si->si_code == SEGV_ACCERR) {
|
||||
wasm_rt_trap(WASM_RT_TRAP_OOB);
|
||||
} else {
|
||||
wasm_rt_trap(WASM_RT_TRAP_EXHAUSTION);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
static void* os_mmap(size_t size) {
|
||||
return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
|
||||
}
|
||||
|
||||
static int os_munmap(void* addr, size_t size) {
|
||||
BOOL succeeded = VirtualFree(addr, size, MEM_RELEASE);
|
||||
return succeeded ? 0 : -1;
|
||||
}
|
||||
|
||||
static int os_mprotect(void* addr, size_t size) {
|
||||
DWORD old;
|
||||
BOOL succeeded = VirtualProtect((LPVOID)addr, size, PAGE_READWRITE, &old);
|
||||
return succeeded ? 0 : -1;
|
||||
}
|
||||
|
||||
static void os_print_last_error(const char* msg) {
|
||||
DWORD errorMessageID = GetLastError();
|
||||
if (errorMessageID != 0) {
|
||||
LPSTR messageBuffer = 0;
|
||||
// The api creates the buffer that holds the message
|
||||
size_t size = FormatMessageA(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR)&messageBuffer, 0, NULL);
|
||||
(void)size;
|
||||
printf("%s. %s\n", msg, messageBuffer);
|
||||
LocalFree(messageBuffer);
|
||||
} else {
|
||||
printf("%s. No error code.\n", msg);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void* os_mmap(size_t size) {
|
||||
int map_prot = PROT_NONE;
|
||||
int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
|
||||
uint8_t* addr = (uint8_t*)mmap(NULL, size, map_prot, map_flags, -1, 0);
|
||||
if (addr == MAP_FAILED)
|
||||
return NULL;
|
||||
return addr;
|
||||
}
|
||||
|
||||
static int os_munmap(void* addr, size_t size) {
|
||||
return munmap(addr, size);
|
||||
}
|
||||
|
||||
static int os_mprotect(void* addr, size_t size) {
|
||||
return mprotect(addr, size, PROT_READ | PROT_WRITE);
|
||||
}
|
||||
|
||||
static void os_print_last_error(const char* msg) {
|
||||
perror(msg);
|
||||
}
|
||||
#endif
|
||||
|
||||
void wasm_rt_init(void) {
|
||||
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
|
||||
if (!g_signal_handler_installed) {
|
||||
g_signal_handler_installed = true;
|
||||
|
||||
/* Use alt stack to handle SIGSEGV from stack overflow */
|
||||
g_alt_stack = malloc(SIGSTKSZ);
|
||||
if (g_alt_stack == NULL) {
|
||||
perror("malloc failed");
|
||||
abort();
|
||||
}
|
||||
|
||||
stack_t ss;
|
||||
ss.ss_sp = g_alt_stack;
|
||||
ss.ss_flags = 0;
|
||||
ss.ss_size = SIGSTKSZ;
|
||||
if (sigaltstack(&ss, NULL) != 0) {
|
||||
perror("sigaltstack failed");
|
||||
abort();
|
||||
}
|
||||
|
||||
struct sigaction sa;
|
||||
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_sigaction = signal_handler;
|
||||
|
||||
/* Install SIGSEGV and SIGBUS handlers, since macOS seems to use SIGBUS. */
|
||||
if (sigaction(SIGSEGV, &sa, NULL) != 0 ||
|
||||
sigaction(SIGBUS, &sa, NULL) != 0) {
|
||||
perror("sigaction failed");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void wasm_rt_free(void) {
|
||||
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
|
||||
free(g_alt_stack);
|
||||
#endif
|
||||
}
|
||||
|
||||
void wasm_rt_allocate_memory(wasm_rt_memory_t* memory,
|
||||
uint32_t initial_pages,
|
||||
uint32_t max_pages) {
|
||||
uint32_t byte_length = initial_pages * PAGE_SIZE;
|
||||
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
|
||||
/* Reserve 8GiB. */
|
||||
void* addr = os_mmap(0x200000000ul);
|
||||
|
||||
if (addr == (void*)-1) {
|
||||
os_print_last_error("os_mmap failed.");
|
||||
abort();
|
||||
}
|
||||
int ret = os_mprotect(addr, byte_length);
|
||||
if (ret != 0) {
|
||||
os_print_last_error("os_mprotect failed.");
|
||||
abort();
|
||||
}
|
||||
memory->data = addr;
|
||||
#else
|
||||
memory->data = (uint8_t*)calloc(byte_length, 1);
|
||||
#endif
|
||||
memory->size = byte_length;
|
||||
memory->pages = initial_pages;
|
||||
memory->max_pages = max_pages;
|
||||
}
|
||||
|
||||
uint32_t wasm_rt_grow_memory(wasm_rt_memory_t* memory, uint32_t delta) {
|
||||
uint32_t old_pages = memory->pages;
|
||||
uint32_t new_pages = memory->pages + delta;
|
||||
if (new_pages == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (new_pages < old_pages || new_pages > memory->max_pages) {
|
||||
return (uint32_t)-1;
|
||||
}
|
||||
uint32_t old_size = old_pages * PAGE_SIZE;
|
||||
uint32_t new_size = new_pages * PAGE_SIZE;
|
||||
uint32_t delta_size = delta * PAGE_SIZE;
|
||||
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
|
||||
uint8_t* new_data = memory->data;
|
||||
int ret = os_mprotect(new_data + old_size, delta_size);
|
||||
if (ret != 0) {
|
||||
return (uint32_t)-1;
|
||||
}
|
||||
#else
|
||||
uint8_t* new_data = (uint8_t*)realloc(memory->data, new_size);
|
||||
if (new_data == NULL) {
|
||||
return (uint32_t)-1;
|
||||
}
|
||||
#if !WABT_BIG_ENDIAN
|
||||
memset(new_data + old_size, 0, delta_size);
|
||||
#endif
|
||||
#endif
|
||||
#if WABT_BIG_ENDIAN
|
||||
memmove(new_data + new_size - old_size, new_data, old_size);
|
||||
memset(new_data, 0, delta_size);
|
||||
#endif
|
||||
memory->pages = new_pages;
|
||||
memory->size = new_size;
|
||||
memory->data = new_data;
|
||||
return old_pages;
|
||||
}
|
||||
|
||||
void wasm_rt_free_memory(wasm_rt_memory_t* memory) {
|
||||
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
|
||||
os_munmap(memory->data, memory->size); // ignore error?
|
||||
#else
|
||||
free(memory->data);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static float quiet_nanf(float x) {
|
||||
uint32_t tmp;
|
||||
memcpy(&tmp, &x, 4);
|
||||
tmp |= 0x7fc00000lu;
|
||||
memcpy(&x, &tmp, 4);
|
||||
return x;
|
||||
}
|
||||
|
||||
static double quiet_nan(double x) {
|
||||
uint64_t tmp;
|
||||
memcpy(&tmp, &x, 8);
|
||||
tmp |= 0x7ff8000000000000llu;
|
||||
memcpy(&x, &tmp, 8);
|
||||
return x;
|
||||
}
|
||||
|
||||
double wasm_rt_trunc(double x) {
|
||||
if (isnan(x)) {
|
||||
return quiet_nan(x);
|
||||
}
|
||||
return trunc(x);
|
||||
}
|
||||
|
||||
float wasm_rt_truncf(float x) {
|
||||
if (isnan(x)) {
|
||||
return quiet_nanf(x);
|
||||
}
|
||||
return truncf(x);
|
||||
}
|
||||
|
||||
float wasm_rt_nearbyintf(float x) {
|
||||
if (isnan(x)) {
|
||||
return quiet_nanf(x);
|
||||
}
|
||||
return nearbyintf(x);
|
||||
}
|
||||
|
||||
double wasm_rt_nearbyint(double x) {
|
||||
if (isnan(x)) {
|
||||
return quiet_nan(x);
|
||||
}
|
||||
return nearbyint(x);
|
||||
}
|
||||
|
||||
float wasm_rt_fabsf(float x) {
|
||||
if (isnan(x)) {
|
||||
uint32_t tmp;
|
||||
memcpy(&tmp, &x, 4);
|
||||
tmp = tmp & ~(1 << 31);
|
||||
memcpy(&x, &tmp, 4);
|
||||
return x;
|
||||
}
|
||||
return fabsf(x);
|
||||
}
|
||||
|
||||
double wasm_rt_fabs(double x) {
|
||||
if (isnan(x)) {
|
||||
uint64_t tmp;
|
||||
memcpy(&tmp, &x, 8);
|
||||
tmp = tmp & ~(1ll << 63);
|
||||
memcpy(&x, &tmp, 8);
|
||||
return x;
|
||||
}
|
||||
return fabs(x);
|
||||
}
|
||||
#endif
|
||||
|
||||
void wasm_rt_allocate_table(wasm_rt_table_t* table,
|
||||
uint32_t elements,
|
||||
uint32_t max_elements) {
|
||||
table->size = elements;
|
||||
table->max_size = max_elements;
|
||||
table->data = (wasm_rt_elem_t*)calloc(table->size, sizeof(wasm_rt_elem_t));
|
||||
}
|
||||
|
||||
void wasm_rt_free_table(wasm_rt_table_t* table) {
|
||||
free(table->data);
|
||||
}
|
||||
|
||||
const char* wasm_rt_strerror(wasm_rt_trap_t trap) {
|
||||
switch (trap) {
|
||||
case WASM_RT_TRAP_NONE:
|
||||
return "No error";
|
||||
case WASM_RT_TRAP_OOB:
|
||||
#if WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS
|
||||
return "Out-of-bounds access in linear memory or call stack exhausted";
|
||||
#else
|
||||
return "Out-of-bounds access in linear memory";
|
||||
case WASM_RT_TRAP_EXHAUSTION:
|
||||
return "Call stack exhausted";
|
||||
#endif
|
||||
case WASM_RT_TRAP_INT_OVERFLOW:
|
||||
return "Integer overflow on divide or truncation";
|
||||
case WASM_RT_TRAP_DIV_BY_ZERO:
|
||||
return "Integer divide by zero";
|
||||
case WASM_RT_TRAP_INVALID_CONVERSION:
|
||||
return "Conversion from NaN to integer";
|
||||
case WASM_RT_TRAP_UNREACHABLE:
|
||||
return "Unreachable instruction executed";
|
||||
case WASM_RT_TRAP_CALL_INDIRECT:
|
||||
return "Invalid call_indirect";
|
||||
}
|
||||
return "invalid trap code";
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright 2018 WebAssembly Community Group participants
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WASM_RT_IMPL_H_
|
||||
#define WASM_RT_IMPL_H_
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "wasm-rt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** A setjmp buffer used for handling traps. */
|
||||
extern jmp_buf g_jmp_buf;
|
||||
|
||||
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
|
||||
#define WASM_RT_SETJMP(buf) sigsetjmp(buf, 1)
|
||||
#define WASM_RT_LONGJMP(buf, val) siglongjmp(buf, val)
|
||||
#else
|
||||
#define WASM_RT_SETJMP(buf) setjmp(buf)
|
||||
#define WASM_RT_LONGJMP(buf, val) longjmp(buf, val)
|
||||
/** Saved call stack depth that will be restored in case a trap occurs. */
|
||||
extern uint32_t g_saved_call_stack_depth;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Convenience macro to use before calling a wasm function. On first execution
|
||||
* it will return `WASM_RT_TRAP_NONE` (i.e. 0). If the function traps, it will
|
||||
* jump back and return the trap that occurred.
|
||||
*
|
||||
* ```
|
||||
* wasm_rt_trap_t code = wasm_rt_impl_try();
|
||||
* if (code != 0) {
|
||||
* printf("A trap occurred with code: %d\n", code);
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* // Call the potentially-trapping function.
|
||||
* my_wasm_func();
|
||||
* ```
|
||||
*/
|
||||
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
|
||||
#define wasm_rt_impl_try() WASM_RT_SETJMP(g_jmp_buf)
|
||||
#else
|
||||
#define wasm_rt_impl_try() \
|
||||
(g_saved_call_stack_depth = wasm_rt_call_stack_depth, \
|
||||
WASM_RT_SETJMP(g_jmp_buf))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WASM_RT_IMPL_H_ */
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
add_definitions(-std=c++14 -Os)
|
||||
|
||||
add_executable(
|
||||
fugg-client
|
||||
"src/main.cpp"
|
||||
"src/client.cpp"
|
||||
# Symbols that flyff-client imports.
|
||||
"src/interop/export/gl.cpp"
|
||||
"src/interop/export/al.cpp"
|
||||
"src/interop/export/callback.cpp"
|
||||
"src/interop/export/embind.cpp"
|
||||
"src/interop/export/env.cpp"
|
||||
"src/interop/export/platform.cpp"
|
||||
)
|
||||
|
||||
target_include_directories(fugg-client PUBLIC "include")
|
||||
target_link_libraries (fugg-client LINK_PUBLIC fugg-core flyff-client)
|
||||
|
||||
set_target_properties(
|
||||
fugg-client
|
||||
PROPERTIES LINK_FLAGS "\
|
||||
-lembind \
|
||||
-sINITIAL_MEMORY=2048MB \
|
||||
-fsanitize=undefined \
|
||||
-sASSERTIONS=1 \
|
||||
-sSAFE_HEAP=1 \
|
||||
-sDEMANGLE_SUPPORT=1 \
|
||||
-sEXPORTED_RUNTIME_METHODS=UTF8ToString,stringToUTF8 \
|
||||
-sMIN_WEBGL_VERSION=2 \
|
||||
-sMAX_WEBGL_VERSION=2"
|
||||
)
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
#include "client.h"
|
||||
|
||||
#include "interop/imports.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace fugg
|
||||
{
|
||||
// Emscripten runtime:
|
||||
// 1. Pre-run
|
||||
// 2. Init runtime
|
||||
// 3. Pre-main
|
||||
// 4. Call main
|
||||
// 5. Post-run
|
||||
|
||||
using namespace interop;
|
||||
|
||||
using wasm::kMemory;
|
||||
using wasm::kTable;
|
||||
|
||||
Client::Client() {
|
||||
// 1. Pre-run: There are no pre-runs in this binary.
|
||||
// 2. Init runtime: `___wasm_call_ctors` is added to on init runtime.
|
||||
(*import::__wasm_call_ctors)();
|
||||
}
|
||||
|
||||
Client& Client::instance() {
|
||||
static bool initialised = false;
|
||||
if(!initialised) {
|
||||
// Initialise the WebAssembly runtime.
|
||||
wasm_rt_init();
|
||||
// Initialise the client.
|
||||
import::init();
|
||||
// Only init the module once.
|
||||
initialised = true;
|
||||
}
|
||||
// Constructor will be called.
|
||||
static Client instance;
|
||||
// Whole module is initialised now.
|
||||
return instance;
|
||||
}
|
||||
|
||||
void Client::initialise() {
|
||||
|
||||
}
|
||||
|
||||
int Client::main() const {
|
||||
// 3. Pre-main: There are no pre-mains in this binary.
|
||||
// 4. Call main: `_main` is main in the binary.
|
||||
// TODO: Fix arguments.
|
||||
return (*import::_main)(0, 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#include "fugg.h"
|
||||
|
||||
namespace fugg {
|
||||
class Client {
|
||||
Client();
|
||||
|
||||
public:
|
||||
static Client& instance();
|
||||
|
||||
Client(Client const&) = delete;
|
||||
void operator=(Client const&) = delete;
|
||||
|
||||
void initialise();
|
||||
// Execute the `main` function of the flyff-client.
|
||||
int main() const;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,294 @@
|
|||
#include <wasm-rt.h>
|
||||
#include <client.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
|
||||
#include <fugg.h>
|
||||
|
||||
#define TRACE_AL_CALLS 0
|
||||
|
||||
/* import: 'a' 'u' */
|
||||
// "u": "_alSourcef",
|
||||
WASM_IMPORT_IMPL(env, _alSourcef) = [](u32 a, u32 b, f32 c) {
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alSourcef("
|
||||
<< a << ", "
|
||||
<< b << ", "
|
||||
<< c
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
alSourcef(a, b, c);
|
||||
};
|
||||
// "w": "_alSourcei",
|
||||
WASM_IMPORT_IMPL(env, _alSourcei) = [](u32 a, u32 b, u32 c) {
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alSourcei("
|
||||
<< a << ", "
|
||||
<< b << ", "
|
||||
<< c
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
alSourcei(a, b, c);
|
||||
};
|
||||
/* import: 'a' 'F' */
|
||||
/* _alSourceStop*/
|
||||
WASM_IMPORT_IMPL(env, _alSourceStop) = [](u32 a) {
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alSourceStop("
|
||||
<< a
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
alSourceStop(a);
|
||||
};
|
||||
// "L": "_alGetSourcei",
|
||||
WASM_IMPORT_IMPL(env, _alGetSourcei) = [](u32 a, u32 b, u32 c) {
|
||||
const auto& value = fugg::module_ptr<ALint>(c);
|
||||
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alGetSourcei("
|
||||
<< a << ", "
|
||||
<< b << ", "
|
||||
<< value
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
alGetSourcei(a, b, value);
|
||||
};
|
||||
/* import: 'a' 'Q' */
|
||||
// "Q": "_alDeleteSources"
|
||||
WASM_IMPORT_IMPL(env, _alDeleteSources) = [](u32 a, u32 b) {
|
||||
const auto& sources = fugg::module_ptr<const ALuint>(b);
|
||||
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alDeleteSources("
|
||||
<< a << ", "
|
||||
<< sources
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
alDeleteSources(a, sources);
|
||||
};
|
||||
/* _alSource3f */
|
||||
WASM_IMPORT_IMPL(env, _alSource3f) = [](u32 a, u32 b, f32 c, f32 d, f32 e) {
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alSource3f("
|
||||
<< a << ", "
|
||||
<< b << ", "
|
||||
<< c << ", "
|
||||
<< d << ", "
|
||||
<< e
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
alSource3f(a, b, c, d, e);
|
||||
};
|
||||
/* import: 'a' 'bb' */
|
||||
// "bb": "_alSourcePlay",
|
||||
WASM_IMPORT_IMPL(env, _alSourcePlay) = [](u32 a) {
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alSourcePlay("
|
||||
<< a
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
alSourcePlay(a);
|
||||
};
|
||||
/* import: 'a' 'cb' */
|
||||
// "cb": "_alListenerfv",
|
||||
WASM_IMPORT_IMPL(env, _alListenerfv) = [](u32 a, u32 b) {
|
||||
const auto& values = fugg::module_ptr<const ALfloat>(b);
|
||||
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alListenerfv("
|
||||
<< a << ", "
|
||||
<< values
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
alListenerfv(a, values);
|
||||
};
|
||||
/* import: 'a' 'db' */
|
||||
// "db": "_alListener3f",
|
||||
WASM_IMPORT_IMPL(env, _alListener3f) = [](u32 a, f32 b, f32 c, f32 d) {
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alListener3f("
|
||||
<< a << ", "
|
||||
<< b << ", "
|
||||
<< c << ", "
|
||||
<< d
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
alListener3f(a, b, c, d);
|
||||
};
|
||||
/* import: 'a' 'Sb' */
|
||||
/* _alDeleteBuffers */
|
||||
WASM_IMPORT_IMPL(env, _alDeleteBuffers) = [](u32 a, u32 b) {
|
||||
const auto& buffers = fugg::module_ptr<const ALuint>(b);
|
||||
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alDeleteBuffers("
|
||||
<< a << ", "
|
||||
<< buffers
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
alDeleteBuffers(a, buffers);
|
||||
};
|
||||
/* import: 'a' 'Tb' */
|
||||
/* _alBufferData */
|
||||
WASM_IMPORT_IMPL(env, _alBufferData) = [](u32 a, u32 b, u32 c, u32 d, u32 e) {
|
||||
const auto& data = fugg::module_ptr<const ALvoid>(c);
|
||||
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alBufferData("
|
||||
<< a << ", "
|
||||
<< b << ", "
|
||||
<< data << ", "
|
||||
<< d << ", "
|
||||
<< e
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
alBufferData(a, b, data, d, e);
|
||||
};
|
||||
/* import: 'a' 'Ub' */
|
||||
// "Ub": "_alGenBuffers",
|
||||
WASM_IMPORT_IMPL(env, _alGenBuffers) = [](u32 a, u32 b) {
|
||||
const auto& buffers = fugg::module_ptr<ALuint>(b);
|
||||
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alGenBuffers("
|
||||
<< a << ", "
|
||||
<< buffers
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
alGenBuffers(a, buffers);
|
||||
};
|
||||
/* import: 'a' 'Vb' */
|
||||
// "Vb": "_alGetEnumValue",
|
||||
WASM_IMPORT_IMPL(env, _alGetEnumValue) = [](u32 a) {
|
||||
const auto& ename = fugg::module_ptr<const ALchar>(a);
|
||||
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alGetEnumValue("
|
||||
<< ename
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
return static_cast<u32>(
|
||||
alGetEnumValue(ename)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 'Wb' */
|
||||
// "Wb": "_alcCloseDevice",
|
||||
WASM_IMPORT_IMPL(env, _alcCloseDevice) = [](u32 a) {
|
||||
// ALCdevice is not data, but an index.
|
||||
const auto& device = reinterpret_cast<ALCdevice*>(a);
|
||||
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alcCloseDevice("
|
||||
<< device
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
return static_cast<u32>(
|
||||
alcCloseDevice(device)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 'Yb' */
|
||||
// "Yb": "_alGenSources",
|
||||
WASM_IMPORT_IMPL(env, _alGenSources) = [](u32 a, u32 b) {
|
||||
const auto& sources = fugg::module_ptr<ALuint>(b);
|
||||
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alGenSources("
|
||||
<< a << ", "
|
||||
<< sources
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
alGenSources(a, sources);
|
||||
};
|
||||
/* import: 'a' 'Zb' */
|
||||
// "Zb": "_alListenerf",
|
||||
WASM_IMPORT_IMPL(env, _alListenerf) = [](u32 a, f32 b) {
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alListenerf("
|
||||
<< a << ", "
|
||||
<< b
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
alListenerf(a, b);
|
||||
};
|
||||
/* import: 'a' '_b' */
|
||||
// "_b": "_alcMakeContextCurrent",
|
||||
WASM_IMPORT_IMPL(env, _alcMakeContextCurrent) = [](u32 a) {
|
||||
// ALCcontext is not data, but an index.
|
||||
const auto& context = reinterpret_cast<ALCcontext*>(a);
|
||||
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alcMakeContextCurrent("
|
||||
<< context
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
return static_cast<u32>(
|
||||
alcMakeContextCurrent(context)
|
||||
);
|
||||
};
|
||||
/* import: 'a' '$b' */
|
||||
/* _alcCreateContext */
|
||||
WASM_IMPORT_IMPL(env, _alcCreateContext) = [](u32 a, u32 b) {
|
||||
// ALCdevice is not data, but an index.
|
||||
const auto& device = reinterpret_cast<ALCdevice*>(a);
|
||||
const auto& attr_list = fugg::module_ptr<const ALCint>(b);
|
||||
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alcCreateContext("
|
||||
<< device << ", "
|
||||
<< attr_list
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
return reinterpret_cast<u32>(
|
||||
alcCreateContext(device, attr_list)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 'Xb' */
|
||||
// "Xb": "_alcDestroyContext",
|
||||
WASM_IMPORT_IMPL(env, _alcDestroyContext) = [](u32 a) {
|
||||
// ALCcontext is not data, but an index.
|
||||
const auto& context = reinterpret_cast<ALCcontext*>(a);
|
||||
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alcDestroyContext("
|
||||
<< context
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
alcDestroyContext(context);
|
||||
};
|
||||
/* import: 'a' 'ac' */
|
||||
// "ac": "_alcOpenDevice",
|
||||
WASM_IMPORT_IMPL(env, _alcOpenDevice) = [](u32 a) {
|
||||
const auto& devicename = fugg::module_ptr<const ALchar>(a);
|
||||
|
||||
#if TRACE_AL_CALLS
|
||||
std::cout << "_alcOpenDevice("
|
||||
<< devicename
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
return reinterpret_cast<u32>(
|
||||
alcOpenDevice(devicename)
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,669 @@
|
|||
#include <emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
|
||||
#include <emscripten/val.h>
|
||||
|
||||
#include "fugg.h"
|
||||
|
||||
#define TRACE_CALLBACK_CALLS 0
|
||||
|
||||
u32 original_resize_callback = 0;
|
||||
/* import: 'a' 'Qa' */
|
||||
// "Qa": "_emscripten_set_resize_callback_on_thread",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_resize_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
// From https://emscripten.org/docs/api_reference/html5.h.html
|
||||
// For the resize callback, pass in target = EMSCRIPTEN_EVENT_TARGET_WINDOW to get resize events from the Window object.
|
||||
const auto& target =
|
||||
reinterpret_cast<void*>(a) <= EMSCRIPTEN_EVENT_TARGET_SCREEN ?
|
||||
reinterpret_cast<const char*>(a) : fugg::module_ptr<const char>(a);
|
||||
|
||||
const auto& user_data = fugg::module_ptr<void>(b);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_resize_callback_on_thread("
|
||||
// << target << ", "
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_ui_callback_func>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_resize_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenUiEvent* event, void* userData) {
|
||||
assert(original_resize_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_ui_callback_func>(original_resize_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenUiEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_resize_callback_on_thread(target, user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 original_devicemotion_callback = 0;
|
||||
/* import: 'a' 'sa' */
|
||||
// "sa": "_emscripten_set_devicemotion_callback_on_thread",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_devicemotion_callback_on_thread) = [](u32 a, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& user_data = fugg::module_ptr<void>(a);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_devicemotion_callback_on_thread("
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_devicemotion_callback_func>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_devicemotion_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenDeviceMotionEvent* event, void* userData) {
|
||||
assert(original_devicemotion_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_devicemotion_callback_func>(original_devicemotion_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenDeviceMotionEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_devicemotion_callback_on_thread(user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 original_beforeunload_callback = 0;
|
||||
/* import: 'a' 'va' */
|
||||
// "va": "_emscripten_set_beforeunload_callback_on_thread",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_beforeunload_callback_on_thread) = [](u32 a, u32 callback_, u32 target_thread) {
|
||||
const auto& user_data = fugg::module_ptr<void>(a);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_beforeunload_callback_on_thread("
|
||||
<< user_data << ", "
|
||||
<< emscripten_rt::fn<em_beforeunload_callback>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_beforeunload_callback = callback_;
|
||||
auto hook = [](int eventType, const void* event, void* userData) {
|
||||
assert(original_beforeunload_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_beforeunload_callback>(original_beforeunload_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const void*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_beforeunload_callback_on_thread(user_data, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 original_focusout_callback = 0;
|
||||
/* import: 'a' 'Ca' */
|
||||
/* _emscripten_set_focusout_callback_on_thread */
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_focusout_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& target = fugg::module_ptr<const char>(a);
|
||||
const auto& user_data = fugg::module_ptr<void>(b);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_focusout_callback_on_thread("
|
||||
<< target << ", "
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_focus_callback_func>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_focusout_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenFocusEvent* event, void* userData) {
|
||||
assert(original_focusout_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_focus_callback_func>(original_focusout_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenFocusEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_focusout_callback_on_thread(target, user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 original_keyup_callback = 0;
|
||||
/* import: 'a' 'Da' */
|
||||
/* _emscripten_set_keyup_callback_on_thread */
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_keyup_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& target = fugg::module_ptr<const char>(a);
|
||||
const auto& user_data = fugg::module_ptr<void>(b);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_keyup_callback_on_thread("
|
||||
<< target << ", "
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_key_callback_func>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_keyup_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenKeyboardEvent* event, void* userData) {
|
||||
assert(original_keyup_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_key_callback_func>(original_keyup_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenKeyboardEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_keyup_callback_on_thread(target, user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 original_keydown_callback = 0;
|
||||
/* import: 'a' 'Ea' */
|
||||
/* _emscripten_set_keydown_callback_on_thread */
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_keydown_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& target = fugg::module_ptr<const char>(a);
|
||||
const auto& user_data = fugg::module_ptr<void>(b);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_keydown_callback_on_thread("
|
||||
<< target << ", "
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_key_callback_func>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_keydown_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenKeyboardEvent* event, void* userData) {
|
||||
assert(original_keydown_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_key_callback_func>(original_keydown_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenKeyboardEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_keydown_callback_on_thread(target, user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
|
||||
u32 original_wheel_callback = 0;
|
||||
/* import: 'a' 'Fa' */
|
||||
/* _emscripten_set_wheel_callback_on_thread */
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_wheel_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& target = fugg::module_ptr<const char>(a);
|
||||
const auto& user_data = fugg::module_ptr<void>(b);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_wheel_callback_on_thread("
|
||||
<< target << ", "
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_wheel_callback_func>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_wheel_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenWheelEvent* event, void* userData) {
|
||||
assert(original_wheel_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_wheel_callback_func>(original_wheel_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenWheelEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_wheel_callback_on_thread(target, user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
|
||||
u32 original_mouseleave_callback = 0;
|
||||
/* import: 'a' 'Ga' */
|
||||
// "Ga": "_emscripten_set_mouseleave_callback_on_thread",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_mouseleave_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& target = fugg::module_ptr<const char>(a);
|
||||
const auto& user_data = fugg::module_ptr<void>(b);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_mouseleave_callback_on_thread("
|
||||
<< target << ", "
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_mouse_callback_func>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_mouseleave_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenMouseEvent* event, void* userData) {
|
||||
assert(original_mouseleave_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_mouse_callback_func>(original_mouseleave_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenMouseEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_mouseleave_callback_on_thread(target, user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 original_mousemove_callback = 0;
|
||||
/* import: 'a' 'Ha' */
|
||||
// "Ha": "_emscripten_set_mousemove_callback_on_thread",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_mousemove_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& target = fugg::module_ptr<const char>(a);
|
||||
const auto& user_data = fugg::module_ptr<void>(b);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_mousemove_callback_on_thread("
|
||||
<< target << ", "
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_mouse_callback_func>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_mousemove_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenMouseEvent* event, void* userData) {
|
||||
assert(original_mousemove_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_mouse_callback_func>(original_mousemove_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenMouseEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_mousemove_callback_on_thread(target, user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 original_mouseup_callback = 0;
|
||||
/* import: 'a' 'Ia' */
|
||||
// "Ia": "_emscripten_set_mouseup_callback_on_thread",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_mouseup_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& target = fugg::module_ptr<const char>(a);
|
||||
const auto& user_data = fugg::module_ptr<void>(b);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_mouseup_callback_on_thread("
|
||||
<< target << ", "
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_mouse_callback_func>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_mouseup_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenMouseEvent* event, void* userData) {
|
||||
assert(original_mouseup_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_mouse_callback_func>(original_mouseup_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenMouseEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_mouseup_callback_on_thread(target, user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 orignal_mousedown_callback = 0;
|
||||
/* import: 'a' 'Ja' */
|
||||
// "Ja": "_emscripten_set_mousedown_callback_on_thread",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_mousedown_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& target = fugg::module_ptr<const char>(a);
|
||||
const auto& user_data = fugg::module_ptr<void>(b);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_mousedown_callback_on_thread("
|
||||
<< target << ", "
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_mouse_callback_func>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
orignal_mousedown_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenMouseEvent* event, void* userData) {
|
||||
assert(orignal_mousedown_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_mouse_callback_func>(orignal_mousedown_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenMouseEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_mousedown_callback_on_thread(target, user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 original_touchcancel_callback = 0;
|
||||
/* import: 'a' 'Ka' */
|
||||
// "Ka": "_emscripten_set_touchcancel_callback_on_thread",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_touchcancel_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& target = fugg::module_ptr<const char>(a);
|
||||
const auto& user_data = fugg::module_ptr<void>(b);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_touchcancel_callback_on_thread("
|
||||
<< target << ", "
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_touch_callback_func>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_touchcancel_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenTouchEvent* event, void* userData) {
|
||||
assert(original_touchcancel_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_touch_callback_func>(original_touchcancel_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenTouchEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_touchcancel_callback_on_thread(target, user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 original_touchmove_callback = 0;
|
||||
/* import: 'a' 'La' */
|
||||
// "La": "_emscripten_set_touchmove_callback_on_thread",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_touchmove_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& target = fugg::module_ptr<const char>(a);
|
||||
const auto& user_data = fugg::module_ptr<void>(b);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_touchmove_callback_on_thread("
|
||||
<< target << ", "
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_touch_callback_func>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_touchmove_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenTouchEvent* event, void* userData) {
|
||||
assert(original_touchmove_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_touch_callback_func>(original_touchmove_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenTouchEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_touchmove_callback_on_thread(target, user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 original_touchend_callback = 0;
|
||||
/* import: 'a' 'Ma' */
|
||||
// "Ma": "_emscripten_set_touchend_callback_on_thread",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_touchend_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& target = fugg::module_ptr<const char>(a);
|
||||
const auto& user_data = fugg::module_ptr<void>(b);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_touchend_callback_on_thread("
|
||||
<< target << ", "
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_touch_callback_func>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_touchend_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenTouchEvent* event, void* userData) {
|
||||
assert(original_touchend_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_touch_callback_func>(original_touchend_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenTouchEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_touchend_callback_on_thread(target, user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 original_touchstart_callback = 0;
|
||||
/* import: 'a' 'Na' */
|
||||
// "Na": "_emscripten_set_touchstart_callback_on_thread",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_touchstart_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& target = fugg::module_ptr<const char>(a);
|
||||
const auto& user_data = fugg::module_ptr<void>(b);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_touchstart_callback_on_thread("
|
||||
<< target << ", "
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_touch_callback_func>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_touchstart_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenTouchEvent* event, void* userData) {
|
||||
assert(original_touchstart_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_touch_callback_func>(original_touchstart_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenTouchEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_touchstart_callback_on_thread(target, user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 original_orientationchange_callback = 0;
|
||||
/* import: 'a' 'Pa' */
|
||||
// "Pa": "_emscripten_set_orientationchange_callback_on_thread",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_orientationchange_callback_on_thread) = [](u32 a, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& user_data = fugg::module_ptr<void>(a);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_orientationchange_callback_on_thread("
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_orientationchange_callback_func>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_orientationchange_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenOrientationChangeEvent* event, void* userData) {
|
||||
assert(original_orientationchange_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_orientationchange_callback_func>(original_orientationchange_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenOrientationChangeEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_orientationchange_callback_on_thread(user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 original_visibilitychange_callback = 0;
|
||||
/* import: 'a' 'Ra' */
|
||||
// "Ra": "_emscripten_set_visibilitychange_callback_on_thread",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_visibilitychange_callback_on_thread) = [](u32 a, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& user_data = fugg::module_ptr<void>(a);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_visibilitychange_callback_on_thread("
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_visibilitychange_callback_func>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_visibilitychange_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenVisibilityChangeEvent* event, void* userData) {
|
||||
assert(original_visibilitychange_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_visibilitychange_callback_func>(original_visibilitychange_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenVisibilityChangeEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_visibilitychange_callback_on_thread(user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 original_webglcontextrestored_callback = 0;
|
||||
/* import: 'a' 'Ba' */
|
||||
/* _emscripten_set_webglcontextrestored_callback_on_thread */
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_webglcontextrestored_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& target = fugg::module_ptr<const char>(a);
|
||||
const auto& user_data = fugg::module_ptr<void>(b);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_webglcontextrestored_callback_on_thread("
|
||||
<< target << ", "
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_webgl_context_callback>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_webglcontextrestored_callback = callback_;
|
||||
auto hook = [](int eventType, const void* event, void* userData) {
|
||||
assert(original_webglcontextrestored_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_webgl_context_callback>(original_webglcontextrestored_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const void*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_webglcontextrestored_callback_on_thread(target, user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 original_webglcontextlost_callback = 0;
|
||||
/* import: 'a' 'eb' */
|
||||
// "eb": "_emscripten_set_webglcontextlost_callback_on_thread",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_webglcontextlost_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& target = fugg::module_ptr<const char>(a);
|
||||
const auto& user_data = fugg::module_ptr<void>(b);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_webglcontextlost_callback_on_thread("
|
||||
<< target << ", "
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_webgl_context_callback>(callback_) << ", "
|
||||
<< target_thread << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_webglcontextlost_callback = callback_;
|
||||
auto hook = [](int eventType, const void* event, void* userData) {
|
||||
assert(original_webglcontextlost_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_webgl_context_callback>(original_webglcontextlost_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const void*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_webglcontextlost_callback_on_thread(target, user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
u32 original_fullscreenchange_callback = 0;
|
||||
/* import: 'a' 'yb' */
|
||||
// "yb": "_emscripten_set_fullscreenchange_callback_on_thread",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_fullscreenchange_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
|
||||
const auto& target = fugg::module_ptr<const char>(a);
|
||||
const auto& user_data = fugg::module_ptr<void>(b);
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_fullscreenchange_callback_on_thread("
|
||||
<< target << ", "
|
||||
<< user_data << ", "
|
||||
<< use_capture << ", "
|
||||
<< emscripten_rt::fn<em_fullscreenchange_callback_func>(callback_) << ", "
|
||||
<< target_thread << ", "
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
original_fullscreenchange_callback = callback_;
|
||||
auto hook = [](int eventType, const EmscriptenFullscreenChangeEvent* event, void* userData) {
|
||||
assert(original_fullscreenchange_callback);
|
||||
|
||||
const auto& callback = fugg::function_ref<em_fullscreenchange_callback_func>(original_fullscreenchange_callback);
|
||||
|
||||
return callback(
|
||||
eventType,
|
||||
reinterpret_cast<const EmscriptenFullscreenChangeEvent*>(fugg::app_ptr(event)),
|
||||
reinterpret_cast<void*>(fugg::app_ptr(userData))
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_fullscreenchange_callback_on_thread(target, user_data, use_capture, hook, target_thread)
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,586 @@
|
|||
#include <wasm-rt.h>
|
||||
#include <client.h>
|
||||
#include <fugg.h>
|
||||
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/bind.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "embind.h"
|
||||
|
||||
|
||||
#define TRACE_EM_CALLS 0
|
||||
|
||||
namespace fugg {
|
||||
namespace embind {
|
||||
std::map<TypeID, const TypeInfo *const> kTypeMap = { };
|
||||
std::map<std::string, const FunctionEntry *const> kFunctionMap = { };
|
||||
std::map<emscripten::internal::EM_METHOD_CALLER, MethodCaller*> kMethodCallers = { };
|
||||
}
|
||||
}
|
||||
|
||||
using namespace fugg::embind;
|
||||
|
||||
|
||||
GenericWireType to_wasm_wire_type(
|
||||
const TypeID& type,
|
||||
const GenericWireType& val
|
||||
) {
|
||||
auto type_info = kTypeMap.at(type);
|
||||
|
||||
switch(type_info->type) {
|
||||
case Type::Void:
|
||||
case Type::Bool:
|
||||
case Type::Integer:
|
||||
case Type::Float:
|
||||
case Type::Emval:
|
||||
// Do nothing.
|
||||
return val;
|
||||
|
||||
case Type::String: {
|
||||
struct WireData {
|
||||
size_t length;
|
||||
char data[1];
|
||||
};
|
||||
|
||||
auto pointee = reinterpret_cast<WireData*>(
|
||||
static_cast<uintptr_t>(val)
|
||||
);
|
||||
|
||||
return static_cast<emscripten::internal::EM_GENERIC_WIRE_TYPE>(
|
||||
fugg::app_ptr(pointee)
|
||||
);
|
||||
} break;
|
||||
|
||||
case Type::MemoryView: {
|
||||
// TOOD:
|
||||
assert(0);
|
||||
} break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void* from_wasm_wire_type(
|
||||
const size_t arg_count,
|
||||
const TypeID* types_,
|
||||
void* args_
|
||||
) {
|
||||
auto args = reinterpret_cast<emscripten::internal::GenericWireType*>(args_);
|
||||
|
||||
for(auto i = 0; i < arg_count; i++) {
|
||||
const auto& type_info = kTypeMap[types_[i]];
|
||||
auto val = &args[i];
|
||||
|
||||
switch(type_info->type) {
|
||||
case Type::Void:
|
||||
case Type::Bool:
|
||||
case Type::Integer:
|
||||
case Type::Float:
|
||||
case Type::Emval:
|
||||
// Do nothing.
|
||||
break;
|
||||
|
||||
case Type::String: {
|
||||
// Offset the pointer.
|
||||
val->w[0].p = fugg::wasm::kMemory.address_of(val->w[0].p);
|
||||
} break;
|
||||
|
||||
case Type::MemoryView: {
|
||||
struct WireData {
|
||||
const size_t length;
|
||||
void* data;
|
||||
};
|
||||
|
||||
auto data = reinterpret_cast<WireData*>(val);
|
||||
data->data = fugg::module_ptr(data->data);
|
||||
} break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/* import: 'a' 'b' */
|
||||
/* __emval_decref */
|
||||
WASM_IMPORT_IMPL(env, __emval_decref) = [](u32 a) {
|
||||
emscripten::internal::_emval_decref(
|
||||
reinterpret_cast<emscripten::EM_VAL>(a)
|
||||
);
|
||||
};
|
||||
|
||||
// void (*Z_aZ_b)(u32) = [](u32 a) {
|
||||
// emscripten::internal::_emval_decref(
|
||||
// reinterpret_cast<emscripten::EM_VAL>(a)
|
||||
// );
|
||||
// };
|
||||
/* import: 'a' 'c' */
|
||||
/* __emval_new_cstring */
|
||||
WASM_IMPORT_IMPL(env, __emval_new_cstring) = [](u32 value_) {
|
||||
const auto& value = fugg::module_ptr<const char>(value_);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_emval_new_cstring("
|
||||
<< value
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
// Returns a handle, so no interop required.
|
||||
return reinterpret_cast<u32>(
|
||||
emscripten::internal::_emval_new_cstring(value)
|
||||
);
|
||||
};
|
||||
/* __emval_set_property */
|
||||
WASM_IMPORT_IMPL(env, __emval_set_property) = [](u32 a, u32 b, u32 c) {
|
||||
emscripten::internal::_emval_set_property(
|
||||
reinterpret_cast<emscripten::EM_VAL>(a),
|
||||
reinterpret_cast<emscripten::EM_VAL>(b),
|
||||
reinterpret_cast<emscripten::EM_VAL>(c)
|
||||
);
|
||||
};
|
||||
/* __emval_get_property */
|
||||
WASM_IMPORT_IMPL(env, __emval_get_property) = [](u32 a, u32 b) {
|
||||
return reinterpret_cast<u32>(
|
||||
emscripten::internal::_emval_get_property(
|
||||
reinterpret_cast<emscripten::EM_VAL>(a),
|
||||
reinterpret_cast<emscripten::EM_VAL>(b)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
/* import: 'a' 'k' */
|
||||
/* __emval_get_method_caller */
|
||||
WASM_IMPORT_IMPL(env, __emval_get_method_caller) = [](u32 argCount_, u32 argTypes_) {
|
||||
const auto& arg_count = argCount_;
|
||||
const auto& arg_types = fugg::ptr_array<TypeID>(argTypes_, argCount_);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_emval_get_method_caller("
|
||||
<< arg_count << ", "
|
||||
<< arg_types << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
const auto& method_caller = emscripten::internal::_emval_get_method_caller(arg_count, arg_types);
|
||||
if(!kMethodCallers.count(method_caller)) {
|
||||
const auto& return_type = arg_types[0];
|
||||
|
||||
kMethodCallers.emplace(method_caller, new MethodCaller {
|
||||
.return_type = return_type,
|
||||
// First argument is return type, so reduce argument count by 1
|
||||
.arg_count = arg_count - 1,
|
||||
.arg_types = &arg_types[1]
|
||||
});
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "Added method caller with id " << reinterpret_cast<void*>(method_caller)
|
||||
<< " -> " << kTypeMap[return_type]->name << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
return reinterpret_cast<u32>(method_caller);
|
||||
};
|
||||
/* import: 'a' 'l' */
|
||||
/* __emval_take_value */
|
||||
WASM_IMPORT_IMPL(env, __emval_take_value) = [](u32 type_, u32 argv_) {
|
||||
TypeID type = fugg::module_ptr<TypeID>(type_);
|
||||
auto argv = fugg::module_ptr<void>(argv_);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_emval_take_value("
|
||||
<< type << ", "
|
||||
<< argv << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
return reinterpret_cast<u32>(
|
||||
emscripten::internal::_emval_take_value(
|
||||
type,
|
||||
// EM_VAR_ARGS calls `readValueFromPointer` so interop is required.
|
||||
// emscripten/val.h:396: Constructing array of size 1.
|
||||
from_wasm_wire_type(1, &type, argv)
|
||||
)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 'o' */
|
||||
/* __emval_run_destructors */
|
||||
WASM_IMPORT_IMPL(env, __emval_run_destructors) = [](u32 a) {
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_emval_run_destructors("
|
||||
<< reinterpret_cast<void*>(a) << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
emscripten::internal::_emval_run_destructors(
|
||||
// EM_DESTRUCTORS is a handle, so no interop required.
|
||||
reinterpret_cast<Destructors>(a)
|
||||
);
|
||||
};
|
||||
/* __emval_get_global */
|
||||
WASM_IMPORT_IMPL(env, __emval_get_global) = [](u32 name_) {
|
||||
const auto& name = fugg::module_ptr<const char>(name_);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_emval_get_global("
|
||||
<< name
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
// This should be fine because the return value of _emval_get_global is just some number, not a real address.
|
||||
return reinterpret_cast<u32>(
|
||||
emscripten::internal::_emval_get_global(name)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 't' */
|
||||
/* __emval_call_void_method */
|
||||
WASM_IMPORT_IMPL(env, __emval_call_void_method) = [](u32 caller_, u32 handle_, u32 methodName_, u32 argv_) {
|
||||
// EM_METHOD_CALLER is used as an index, so no interop is required.
|
||||
const auto& caller = reinterpret_cast<emscripten::internal::EM_METHOD_CALLER>(caller_);
|
||||
const auto& handle = reinterpret_cast<Value>(handle_);
|
||||
const auto& method_name = fugg::module_ptr<const char>(methodName_);
|
||||
const auto& argv = fugg::module_ptr<void>(argv_);
|
||||
|
||||
const auto& method_caller = kMethodCallers[caller];
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_emval_call_void_method("
|
||||
<< caller << ", "
|
||||
<< handle << ", "
|
||||
<< method_name << ", "
|
||||
<< argv << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
emscripten::internal::_emval_call_void_method(
|
||||
caller,
|
||||
handle,
|
||||
method_name,
|
||||
from_wasm_wire_type(method_caller->arg_count, method_caller->arg_types, argv)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 'y' */
|
||||
/* __emval_as */
|
||||
WASM_IMPORT_IMPL(env, __emval_as) = [](u32 a, u32 b, u32 c) {
|
||||
// EM_VAL is just a number of the handle, so no interop required.
|
||||
const auto& value = reinterpret_cast<emscripten::EM_VAL>(a);
|
||||
|
||||
const auto& return_type = fugg::module_ptr<TypeID>(b);
|
||||
const auto& destructors = fugg::module_ptr<emscripten::internal::EM_DESTRUCTORS>(c);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_emval_as("
|
||||
<< value << ", "
|
||||
<< return_type << " (" << kTypeMap[return_type]->name << ")" << ", "
|
||||
<< destructors
|
||||
<< std::endl;
|
||||
#endif
|
||||
|
||||
return to_wasm_wire_type(
|
||||
return_type,
|
||||
emscripten::internal::_emval_as(value, return_type, destructors)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 'E' */
|
||||
/* __emval_incref */
|
||||
WASM_IMPORT_IMPL(env, __emval_incref) = [](u32 a) {
|
||||
emscripten::internal::_emval_incref(
|
||||
reinterpret_cast<emscripten::EM_VAL>(a)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 'H' */
|
||||
/* __emval_call_method */
|
||||
WASM_IMPORT_IMPL(env, __emval_call_method) = [](u32 a, u32 b, u32 c, u32 d, u32 argv_) {
|
||||
const auto& caller = reinterpret_cast<emscripten::internal::EM_METHOD_CALLER>(a);
|
||||
const auto& handle = reinterpret_cast<emscripten::EM_VAL>(b);
|
||||
const auto& method_name = fugg::module_ptr<const char>(c);
|
||||
const auto& destructors = fugg::module_ptr<emscripten::internal::EM_DESTRUCTORS>(d);
|
||||
|
||||
const auto& method_caller = kMethodCallers.at(caller);
|
||||
const auto& argv = fugg::module_ptr<void>(argv_);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_emval_call_method("
|
||||
<< caller << ", "
|
||||
<< handle << ", "
|
||||
<< method_name << ", "
|
||||
<< destructors << ", "
|
||||
<< argv << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
auto result = emscripten::internal::_emval_call_method(
|
||||
caller,
|
||||
handle,
|
||||
method_name,
|
||||
destructors,
|
||||
from_wasm_wire_type(method_caller->arg_count, method_caller->arg_types, argv)
|
||||
);
|
||||
|
||||
return to_wasm_wire_type(
|
||||
method_caller->return_type,
|
||||
result
|
||||
);
|
||||
};
|
||||
/* __emval_get_module_property */
|
||||
WASM_IMPORT_IMPL(env, __emval_get_module_property) = [](u32 a) {
|
||||
const auto& name = fugg::module_ptr<const char>(a);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_emval_get_module_property(" << name << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
return reinterpret_cast<u32>(
|
||||
emscripten::internal::_emval_get_module_property(name)
|
||||
);
|
||||
};
|
||||
/* __emval_typeof */
|
||||
WASM_IMPORT_IMPL(env, __emval_typeof) = [](u32 a) {
|
||||
return reinterpret_cast<u32>(
|
||||
emscripten::internal::_emval_typeof(
|
||||
reinterpret_cast<emscripten::EM_VAL>(a)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
/* __embind_register_function */
|
||||
WASM_IMPORT_IMPL(env, __embind_register_function) = [](u32 a, u32 arg_count, u32 c, u32 d, u32 invoker_, u32 function_) {
|
||||
const auto& name = fugg::module_ptr<const char>(a);
|
||||
// This is an array, but not an array of pointers.
|
||||
const auto& arg_types = fugg::module_ptr<emscripten::internal::TYPEID>(c);
|
||||
const auto& signature = fugg::module_ptr<const char>(d);
|
||||
// The invoker seems to convert the types received by the function.
|
||||
const auto& invoker = fugg::function_ref<emscripten::internal::GenericFunction>(invoker_);
|
||||
const auto& function = fugg::function_ref<emscripten::internal::GenericFunction>(function_);
|
||||
|
||||
kFunctionMap.emplace(name, new FunctionEntry {
|
||||
.invoker = invoker_,
|
||||
.fn = function_
|
||||
});
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_embind_register_function("
|
||||
<< name << ", "
|
||||
<< arg_count << ", "
|
||||
<< arg_types << ", "
|
||||
<< signature << ", "
|
||||
<< invoker << ", "
|
||||
<< function
|
||||
<< ")" << std::endl;
|
||||
#endif
|
||||
|
||||
// if(std::string(name) != "platform_text_edited") {
|
||||
// emscripten::internal::_embind_register_function(name, arg_count, arg_types, signature, invoker, function);
|
||||
// } else {
|
||||
std::cout << "Skipping registration of " << static_cast<const char*>(name)
|
||||
<< " with " << arg_count << " arguments." << std::endl;
|
||||
// }
|
||||
};
|
||||
/* import: 'a' 'ua' */
|
||||
/* __emval_new */
|
||||
WASM_IMPORT_IMPL(env, __emval_new) = [](u32 a, u32 arg_count, u32 arg_types_, u32 argv_) {
|
||||
auto value = reinterpret_cast<emscripten::EM_VAL>(a);
|
||||
// To prevent double converting pointers in the arg_type array, create a new
|
||||
// array.
|
||||
auto test_arg_types = new void*[arg_count];
|
||||
|
||||
using TypeID = void*;
|
||||
auto arg_types = fugg::module_ptr<TypeID>(arg_types_);
|
||||
for(int i = 0; i < arg_count; i++)
|
||||
test_arg_types[i] = fugg::module_ptr(arg_types[i]);
|
||||
|
||||
auto argv = fugg::module_ptr<void>(argv_);
|
||||
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_emval_new("
|
||||
<< value << ", "
|
||||
<< arg_count << ", "
|
||||
<< arg_types << "(raw: " << reinterpret_cast<void*>(arg_types_) << "), "
|
||||
<< argv << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
return reinterpret_cast<u32>(
|
||||
emscripten::internal::_emval_new(
|
||||
value,
|
||||
arg_count,
|
||||
test_arg_types,
|
||||
from_wasm_wire_type(arg_count, test_arg_types, argv)
|
||||
)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 'ya' */
|
||||
// "ya": "_emscripten_resize_heap",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_resize_heap) = [](u32 a) {
|
||||
printf("Flyff apparantly wants to resize the heap!");
|
||||
|
||||
// Original code calls `abortOnMemoryGrowth()`
|
||||
return static_cast<u32>(0);
|
||||
};
|
||||
/* import: 'a' 'za' */
|
||||
/* __embind_register_std_wstring */
|
||||
WASM_IMPORT_IMPL(env, __embind_register_std_wstring) = [](u32 a, u32 char_size, u32 c) {
|
||||
const auto& string_type = fugg::module_ptr<emscripten::internal::TYPEID>(a);
|
||||
const auto& name = fugg::module_ptr<const char>(c);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_embind_register_std_wstring("
|
||||
<< string_type << ", "
|
||||
<< char_size << ", "
|
||||
<< name << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
kTypeMap.emplace(string_type, new TypeInfo {
|
||||
.name = std::string(name),
|
||||
.type = Type::WideString
|
||||
});
|
||||
|
||||
emscripten::internal::_embind_register_std_wstring(string_type, char_size, name);
|
||||
};
|
||||
/* import: 'a' '_a' */
|
||||
/* __embind_register_float */
|
||||
WASM_IMPORT_IMPL(env, __embind_register_float) = [](u32 a, u32 b, u32 size) {
|
||||
const auto& float_type = fugg::module_ptr<emscripten::internal::TYPEID>(a);
|
||||
const auto& name = fugg::module_ptr<const char>(b);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_embind_register_float("
|
||||
<< float_type << ", "
|
||||
<< name << ", "
|
||||
<< size << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
kTypeMap.emplace(float_type, new TypeInfo {
|
||||
.name = std::string(name),
|
||||
.type = Type::Float
|
||||
});
|
||||
|
||||
emscripten::internal::_embind_register_float(float_type, name, size);
|
||||
};
|
||||
/* import: 'a' '$a' */
|
||||
/* __embind_register_std_string */
|
||||
WASM_IMPORT_IMPL(env, __embind_register_std_string) = [](u32 a, u32 b) {
|
||||
const auto& string_type = fugg::module_ptr<emscripten::internal::TYPEID>(a);
|
||||
const auto& name = fugg::module_ptr<const char>(b);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_embind_register_std_string("
|
||||
<< string_type << ", "
|
||||
<< name << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
kTypeMap.emplace(string_type, new TypeInfo {
|
||||
.name = std::string(name),
|
||||
.type = Type::String
|
||||
});
|
||||
|
||||
emscripten::internal::_embind_register_std_string(string_type, name);
|
||||
};
|
||||
/* import: 'a' 'Bb' */
|
||||
/* __embind_register_bigint */
|
||||
WASM_IMPORT_IMPL(env, __embind_register_bigint) = [](u32 registerType, u32 name_, u32 size, u32 min_range, u32 max_range, u32 f, u32 g) {
|
||||
// Does nothing in JS.
|
||||
};
|
||||
/* import: 'a' 'Ob' */
|
||||
/* __embind_register_emval */
|
||||
WASM_IMPORT_IMPL(env, __embind_register_emval) = [](u32 a, u32 b) {
|
||||
const auto& emval_type = fugg::module_ptr<emscripten::internal::TYPEID>(a);
|
||||
const auto& name = fugg::module_ptr<const char>(b);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_embind_register_emval("
|
||||
<< emval_type << ", "
|
||||
<< name << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
kTypeMap.emplace(emval_type, new TypeInfo {
|
||||
.name = std::string(name),
|
||||
.type = Type::Emval
|
||||
});
|
||||
|
||||
emscripten::internal::_embind_register_emval(emval_type, name);
|
||||
};
|
||||
/* import: 'a' 'Pb' */
|
||||
/* __embind_register_bool */
|
||||
WASM_IMPORT_IMPL(env, __embind_register_bool) = [](u32 a, u32 b, u32 size, u32 true_value, u32 false_value) {
|
||||
const auto& bool_type = fugg::module_ptr<emscripten::internal::TYPEID>(a);
|
||||
const auto& name = fugg::module_ptr<const char>(b);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_embind_register_bool("
|
||||
<< bool_type << ", "
|
||||
<< name << ", "
|
||||
<< size << ", "
|
||||
<< true_value << ", "
|
||||
<< false_value << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
kTypeMap.emplace(bool_type, new TypeInfo {
|
||||
.name = std::string(name),
|
||||
.type = Type::Bool
|
||||
});
|
||||
|
||||
emscripten::internal::_embind_register_bool(bool_type, name, size, true_value, false_value);
|
||||
};
|
||||
/* import: 'a' 'Qb' */
|
||||
/* __embind_register_void */
|
||||
WASM_IMPORT_IMPL(env, __embind_register_void) = [](u32 a, u32 b) {
|
||||
const auto& void_type = fugg::module_ptr<emscripten::internal::TYPEID>(a);
|
||||
const auto& name = fugg::module_ptr<const char>(b);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_embind_register_void("
|
||||
<< void_type << ", "
|
||||
<< name << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
kTypeMap.emplace(void_type, new TypeInfo {
|
||||
.name = std::string(name),
|
||||
.type = Type::Void
|
||||
});
|
||||
|
||||
emscripten::internal::_embind_register_void(void_type, name);
|
||||
};
|
||||
|
||||
/* import: 'a' 'J' */
|
||||
/* __embind_register_memory_view */
|
||||
WASM_IMPORT_IMPL(env, __embind_register_memory_view) = [](u32 a, u32 b, u32 c) {
|
||||
const auto& memory_view_type = fugg::module_ptr<emscripten::internal::TYPEID>(a);
|
||||
const auto& typed_array_index = b;
|
||||
const auto& name = fugg::module_ptr<const char>(c);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_embind_register_memory_view("
|
||||
<< memory_view_type << ", "
|
||||
<< typed_array_index << ", "
|
||||
<< name << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
kTypeMap.emplace(memory_view_type, new TypeInfo {
|
||||
.name = std::string(name),
|
||||
.type = Type::MemoryView
|
||||
});
|
||||
|
||||
emscripten::internal::_embind_register_memory_view(memory_view_type, typed_array_index, name);
|
||||
};
|
||||
/* __embind_register_integer */
|
||||
WASM_IMPORT_IMPL(env, __embind_register_integer) = [](u32 integer_type_, u32 name_, u32 size, u32 min_range, u32 max_range) {
|
||||
const auto& integer_type = fugg::module_ptr<TypeID>(integer_type_);
|
||||
const auto& name = fugg::module_ptr<const char>(name_);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_embind_register_integer("
|
||||
<< integer_type << ", "
|
||||
<< name << ", "
|
||||
<< size << ", "
|
||||
<< min_range << ", "
|
||||
<< max_range << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
kTypeMap.emplace(integer_type, new TypeInfo {
|
||||
.name = std::string(name),
|
||||
.type = Type::Integer
|
||||
});
|
||||
|
||||
emscripten::internal::_embind_register_integer(integer_type, name, size, min_range, max_range);
|
||||
};
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
#include <emscripten.h>
|
||||
#include <emscripten/bind.h>
|
||||
|
||||
|
||||
namespace fugg {
|
||||
namespace embind {
|
||||
using TypeID = emscripten::internal::TYPEID;
|
||||
using GenericWireType = emscripten::internal::EM_GENERIC_WIRE_TYPE;
|
||||
using VariableArguments = emscripten::internal::GenericWireType*;
|
||||
using Value = emscripten::EM_VAL;
|
||||
using Destructors = emscripten::internal::EM_DESTRUCTORS;
|
||||
|
||||
enum class Type {
|
||||
// Primitives
|
||||
Void,
|
||||
Bool,
|
||||
Integer,
|
||||
Float,
|
||||
Emval,
|
||||
// Complex
|
||||
String,
|
||||
WideString,
|
||||
MemoryView,
|
||||
};
|
||||
|
||||
struct TypeInfo {
|
||||
std::string name;
|
||||
Type type;
|
||||
};
|
||||
|
||||
|
||||
struct FunctionEntry {
|
||||
uintptr_t invoker;
|
||||
uintptr_t fn;
|
||||
};
|
||||
|
||||
struct MethodCaller {
|
||||
const emscripten::internal::TYPEID return_type;
|
||||
const unsigned int arg_count;
|
||||
const emscripten::internal::TYPEID* arg_types;
|
||||
};
|
||||
|
||||
extern std::map<TypeID, const TypeInfo *const> kTypeMap;
|
||||
extern std::map<std::string, const FunctionEntry *const> kFunctionMap;
|
||||
extern std::map<emscripten::internal::EM_METHOD_CALLER, MethodCaller*> kMethodCallers;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
#include <wasm-rt.h>
|
||||
#include <client.h>
|
||||
#include <fugg.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
/* import: 'a' 'qa' */
|
||||
// "qa": "_emscripten_set_main_loop",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_main_loop) = [](u32 a, u32 fps, u32 simulate_infinite_loop) {
|
||||
static u32 original_main_loop = 0;
|
||||
|
||||
auto main_loop_override = []() {
|
||||
// std::cout << "This is fugg main loop being called! Calling original loop... at " << reinterpret_cast<void*>(original_main_loop) << std::endl;
|
||||
|
||||
const auto& func = fugg::function_ref<em_callback_func>(original_main_loop);
|
||||
func();
|
||||
};
|
||||
|
||||
original_main_loop = a;
|
||||
|
||||
#if TRACE_CALLBACK_CALLS
|
||||
std::cout << "_emscripten_set_main_loop("
|
||||
<< func << " (" << reinterpret_cast<void*>(a) << "), "
|
||||
<< fps << ", "
|
||||
<< simulate_infinite_loop << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
|
||||
emscripten_set_main_loop(main_loop_override, fps, simulate_infinite_loop);
|
||||
};
|
||||
/* import: 'a' 'pa' */
|
||||
// "pa": "_emscripten_cancel_main_loop",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_cancel_main_loop) = []() {
|
||||
emscripten_cancel_main_loop();
|
||||
};
|
||||
|
||||
/* import: 'a' 'ab' */
|
||||
// "ab": "_emscripten_async_wget_data",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_async_wget_data) = [](u32 url_, u32 arg_, u32 onload_, u32 onerror_) {
|
||||
// This function is only called by the flyff runtime, so we introduce
|
||||
// stubs to refer the onload and onerror on to actual flyff functions.
|
||||
// See `onload_stub` and `onerror_stub`.
|
||||
|
||||
struct wget_data {
|
||||
u32 onload;
|
||||
u32 onerror;
|
||||
u32 original_arg;
|
||||
};
|
||||
|
||||
auto onload_stub = [](void* arg_, void *data_, int size) {
|
||||
const auto& interop_data = reinterpret_cast<wget_data*>(arg_);
|
||||
|
||||
const auto& onload = fugg::function_ref<em_async_wget_onload_func>(interop_data->onload);
|
||||
// This pointer can stay unchanged, it came from inside and is going inside.
|
||||
const auto& arg = reinterpret_cast<void*>(interop_data->original_arg);
|
||||
const auto& data = reinterpret_cast<void*>(fugg::app_ptr(data_));
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "onload_stub: Calling function at " << reinterpret_cast<void*>(onload) << "("
|
||||
<< arg << ", "
|
||||
<< data << ", "
|
||||
<< size << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
onload(arg, data, size);
|
||||
|
||||
delete interop_data;
|
||||
};
|
||||
|
||||
auto onerror_stub = [](void* arg_) {
|
||||
const auto& interop_data = reinterpret_cast<wget_data*>(arg_);
|
||||
|
||||
const auto& onerror = fugg::function_ref<em_arg_callback_func>(interop_data->onerror);
|
||||
const auto& arg = reinterpret_cast<void*>(interop_data->original_arg);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "onerror_stub: Calling function at " << reinterpret_cast<void*>(onerror) << "("
|
||||
<< arg << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
onerror(arg);
|
||||
|
||||
delete interop_data;
|
||||
};
|
||||
|
||||
const auto& url = fugg::module_ptr<const char>(url_);
|
||||
|
||||
const auto data = new wget_data {
|
||||
.onload = onload_,
|
||||
.onerror = onerror_,
|
||||
.original_arg = arg_
|
||||
};
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_emscripten_async_wget_data("
|
||||
<< url << ", "
|
||||
<< arg_ << ", "
|
||||
<< reinterpret_cast<void*>(onload_) << ", "
|
||||
<< reinterpret_cast<void*>(onerror_) << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
std::cout << "Client: Downloading " << static_cast<const char*>(url) << std::endl;
|
||||
|
||||
// This function can allocate, which will call the Flyff runtime allocate.
|
||||
emscripten_async_wget_data(url, data, onload_stub, onerror_stub);
|
||||
};
|
||||
/* import: 'a' 'fb' */
|
||||
// "fb": "_emscripten_set_element_css_size",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_element_css_size) = [](u32 target_, f64 width, f64 height) {
|
||||
const auto& target = fugg::module_ptr<const char>(target_);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_emscripten_set_element_css_size("
|
||||
<< target << ", "
|
||||
<< width << ", "
|
||||
<< height << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_element_css_size(target, width, height)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 'gb' */
|
||||
// "gb": "_emscripten_set_canvas_element_size",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_set_canvas_element_size) = [](u32 target_, u32 width, u32 height) {
|
||||
const auto& target = fugg::module_ptr<const char>(target_);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_emscripten_set_canvas_element_size("
|
||||
<< target << ", "
|
||||
<< width << ", "
|
||||
<< height << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_set_canvas_element_size(target, width, height)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 'ob' */
|
||||
// "ob": "_emscripten_get_orientation_status",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_get_orientation_status) = [](u32 a) {
|
||||
return static_cast<u32>(
|
||||
emscripten_get_orientation_status(
|
||||
fugg::module_ptr<EmscriptenOrientationChangeEvent>(a)
|
||||
)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 'Ab' */
|
||||
/* _fd_seek */
|
||||
WASM_IMPORT_IMPL(env, _fd_seek) = [](u32 a, u32 b, u32 c, u32 d, u32 e) {
|
||||
// For some reason, it only returns 70.
|
||||
return static_cast<u32>(70);
|
||||
};
|
||||
|
||||
WASM_IMPORT_IMPL(env, _abort) = [](void) {
|
||||
puts("abort() called!");
|
||||
assert(0);
|
||||
};
|
||||
|
||||
// "la": "_emscripten_exit_fullscreen",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_exit_fullscreen) = []() {
|
||||
return static_cast<u32>(
|
||||
emscripten_exit_fullscreen()
|
||||
);
|
||||
};
|
||||
// "ma": "_emscripten_request_fullscreen",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_request_fullscreen) = [](u32 a, u32 b) {
|
||||
return static_cast<u32>(
|
||||
emscripten_request_fullscreen(
|
||||
reinterpret_cast<const char*>(a),
|
||||
b
|
||||
)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 'oa' */
|
||||
// "oa": "_emscripten_performance_now",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_performance_now) = []() {
|
||||
return emscripten_performance_now();
|
||||
};
|
||||
/* import: 'a' 'Za' */
|
||||
/* __emscripten_date_now */
|
||||
WASM_IMPORT_IMPL(env, __emscripten_date_now) = []() {
|
||||
return emscripten_get_now();
|
||||
};
|
||||
// "da": "_emscripten_vibrate",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_vibrate) = [](u32 a) {
|
||||
return static_cast<u32>(
|
||||
emscripten_vibrate(a)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 'Aa' */
|
||||
/* _strftime */
|
||||
WASM_IMPORT_IMPL(env, _strftime) = [](u32 a, u32 b, u32 c, u32 d) {
|
||||
return static_cast<u32>(
|
||||
strftime(
|
||||
fugg::module_ptr<char>(a),
|
||||
b,
|
||||
fugg::module_ptr<char>(c),
|
||||
fugg::module_ptr<const tm>(d)
|
||||
)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 'Oa' */
|
||||
// "Oa": "_emscripten_webgl_destroy_context",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_webgl_destroy_context) = [](u32 a) {
|
||||
return static_cast<u32>(
|
||||
emscripten_webgl_destroy_context(a)
|
||||
);
|
||||
};
|
||||
|
||||
/* import: 'a' 'Cb' */
|
||||
/* _strftime_l */
|
||||
WASM_IMPORT_IMPL(env, _strftime_l) = [](u32 a, u32 b, u32 c, u32 d, u32 e) {
|
||||
return static_cast<u32>(
|
||||
strftime_l(
|
||||
reinterpret_cast<char*>(a),
|
||||
b,
|
||||
reinterpret_cast<char*>(c),
|
||||
reinterpret_cast<const tm*>(d),
|
||||
reinterpret_cast<locale_t>(e)
|
||||
)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 'Db' */
|
||||
/* _environ_get */
|
||||
WASM_IMPORT_IMPL(env, _environ_get) = [](u32 a, u32 b) {
|
||||
puts("_environ_get");
|
||||
// FIXME:
|
||||
return static_cast<u32>(0);
|
||||
};
|
||||
/* import: 'a' 'Eb' */
|
||||
/* _environ_sizes_get */
|
||||
WASM_IMPORT_IMPL(env, _environ_sizes_get) = [](u32, u32) {
|
||||
puts("_environ_sizes_get");
|
||||
// FIXME:
|
||||
return static_cast<u32>(0);
|
||||
};
|
||||
/* import: 'a' 'Fb' */
|
||||
/* _fd_close */
|
||||
WASM_IMPORT_IMPL(env, _fd_close) = [](u32 a) {
|
||||
// For some reason returns 52...
|
||||
return static_cast<u32>(52);
|
||||
};
|
||||
/* import: 'a' 'Gb' */
|
||||
/* _fd_write */
|
||||
WASM_IMPORT_IMPL(env, _fd_write) = [](u32 a, u32 b, u32 c, u32 d) {
|
||||
puts("fd_write");
|
||||
// FIXME:
|
||||
return static_cast<u32>(0);
|
||||
};
|
||||
|
||||
/* import: 'a' 'Hb' */
|
||||
// "Hb": "_emscripten_memcpy_big",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_memcpy_big) = [](u32 dest_, u32 src_, u32 length) {
|
||||
// WASM runtime calls this, so no need to change the pointers since it's "internal".
|
||||
// Right?
|
||||
const auto& dest = fugg::module_ptr<void>(dest_);
|
||||
const auto& src = fugg::module_ptr<void>(src_);
|
||||
|
||||
#if TRACE_ALLOC
|
||||
std::cout << "_emscripten_memcpy_big("
|
||||
<< dest << ", "
|
||||
<< src << ", "
|
||||
<< length << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
wasm_rt_memcpy(dest, src, length);
|
||||
};
|
||||
/* import: 'a' 'Ib' */
|
||||
/* __emscripten_get_now_is_monotonic */
|
||||
WASM_IMPORT_IMPL(env, __emscripten_get_now_is_monotonic) = []() {
|
||||
return static_cast<u32>(true);
|
||||
};
|
||||
/* import: 'a' 'Jb' */
|
||||
/* __gmtime_js */
|
||||
WASM_IMPORT_IMPL(env, __gmtime_js) = [](u32 a, u32 b) {
|
||||
// FIXME:
|
||||
// puts("__gmtime_js is not implemented yet.");
|
||||
};
|
||||
/* import: 'a' 'Kb' */
|
||||
/* __localtime_js */
|
||||
WASM_IMPORT_IMPL(env, __localtime_js) = [](u32 a, u32 b) {
|
||||
// FIXME:
|
||||
// puts("__localtime_js is not implemented yet.");
|
||||
};
|
||||
/* import: 'a' 'Lb' */
|
||||
/* __mktime_js */
|
||||
WASM_IMPORT_IMPL(env, __mktime_js) = [](u32 a) {
|
||||
// FIXME:
|
||||
// puts("__mktime_js is not implemented yet.");
|
||||
|
||||
return static_cast<u32>(0);
|
||||
};
|
||||
/* import: 'a' 'Mb' */
|
||||
/* __tzset_js */
|
||||
WASM_IMPORT_IMPL(env, __tzset_js) = [](u32 a, u32 b, u32 c) {
|
||||
// FIXME:
|
||||
// puts("__tzset_js is not implemented yet.");
|
||||
|
||||
};
|
||||
|
||||
/* import: 'a' 'Rb' */
|
||||
// "Rb": "_emscripten_log",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_log) = [](u32 flags, u32 b, u32 c) {
|
||||
const auto& format = fugg::module_ptr<const char>(b);
|
||||
|
||||
emscripten_log(flags, format, c);
|
||||
};
|
||||
/* import: 'a' 'bc' */
|
||||
// "bc": "_emscripten_get_fullscreen_status",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_get_fullscreen_status) = [](u32 a) {
|
||||
const auto& fullscreen_status = fugg::module_ptr<EmscriptenFullscreenChangeEvent>(a);
|
||||
|
||||
#if TRACE_EM_CALLS
|
||||
std::cout << "_emscripten_get_fullscreen_status("
|
||||
<< fullscreen_status << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
return static_cast<u32>(
|
||||
emscripten_get_fullscreen_status(fullscreen_status)
|
||||
);
|
||||
};
|
||||
/* import: 'a' 'cc' */
|
||||
// "cc": "_emscripten_force_exit",
|
||||
WASM_IMPORT_IMPL(env, _emscripten_force_exit) = [](u32 a) {
|
||||
emscripten_force_exit(a);
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,112 @@
|
|||
#include <wasm-rt.h>
|
||||
#include <client.h>
|
||||
#include <fugg.h>
|
||||
|
||||
#include <emscripten/bind.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "embind.h"
|
||||
|
||||
void platform_text_edited_hook(u32 ptr, u32 selection_start, u32 selection_end) {
|
||||
// Emscripten doesn't understand sending pointers, so we have to receive an int.
|
||||
|
||||
auto text = reinterpret_cast<const char*>(fugg::app_ptr(ptr));
|
||||
|
||||
using PlatformTextEditedFn = void (*)(const char*, u32, u32);
|
||||
const auto& platform_text_edited = fugg::function_ref<PlatformTextEditedFn>(
|
||||
fugg::embind::kFunctionMap["platform_text_edited"]->fn
|
||||
);
|
||||
|
||||
platform_text_edited(
|
||||
text, selection_start, selection_end
|
||||
);
|
||||
}
|
||||
|
||||
void platform_got_devicemotion_permission_hook() {
|
||||
using PlatformGotDeviceMotionPermissionFn = void (*)(void);
|
||||
auto platform_got_devicemotion_permission = fugg::function_ref<PlatformGotDeviceMotionPermissionFn>(
|
||||
fugg::embind::kFunctionMap["platform_got_devicemotion_permission"]->fn
|
||||
);
|
||||
|
||||
platform_got_devicemotion_permission();
|
||||
}
|
||||
|
||||
void platform_captcha_completed_hook(std::string token) {
|
||||
struct WireType {
|
||||
size_t length;
|
||||
char data[1];
|
||||
};
|
||||
|
||||
WireType* wt = (WireType*)malloc(sizeof(size_t) + token.length());
|
||||
wt->length = token.length();
|
||||
memcpy(wt->data, token.data(), token.length());
|
||||
|
||||
using PlatformCaptchaCompletedFn = void (*)(std::string);
|
||||
using PlatformCaptchaCompletedInvoker = void (*)(PlatformCaptchaCompletedFn, WireType*);
|
||||
// Don't transform this, as it will be passed to a function inside the runtime (the invoker).
|
||||
auto platform_captcha_completed = reinterpret_cast<PlatformCaptchaCompletedFn>(
|
||||
fugg::embind::kFunctionMap["platform_captcha_completed"]->fn
|
||||
);
|
||||
// Do transform this, as it's being called from outside.
|
||||
auto platform_captcha_completed_invoker = fugg::function_ref<PlatformCaptchaCompletedInvoker>(
|
||||
fugg::embind::kFunctionMap["platform_captcha_completed"]->invoker
|
||||
);
|
||||
|
||||
platform_captcha_completed_invoker(
|
||||
platform_captcha_completed,
|
||||
reinterpret_cast<WireType*>(fugg::app_ptr(wt))
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
using PlatformWebsocketFn = void (*)(emscripten::val event);
|
||||
|
||||
void platform_websocket_open_hook(emscripten::val event) {
|
||||
// std::cout << "platform_websocket_open_hook:" << std::endl;// event=" << event << std::endl;
|
||||
|
||||
const auto& platform_websocket_open = fugg::function_ref<PlatformWebsocketFn>(
|
||||
fugg::embind::kFunctionMap["platform_websocket_open"]->fn
|
||||
);
|
||||
|
||||
platform_websocket_open(event);
|
||||
}
|
||||
|
||||
void platform_websocket_close_hook(emscripten::val event) {
|
||||
// std::cout << "platform_websocket_close_hook:" << std::endl;// code=" << code << std::endl;
|
||||
|
||||
const auto& platform_websocket_close = fugg::function_ref<PlatformWebsocketFn>(
|
||||
fugg::embind::kFunctionMap["platform_websocket_close"]->fn
|
||||
);
|
||||
|
||||
platform_websocket_close(event);
|
||||
}
|
||||
|
||||
void platform_websocket_message_hook(emscripten::val event) {
|
||||
// std::cout << "platform_websocket_message: Got " << event["data"]["byteLength"].as<unsigned long>() << " bytes" << std::endl;
|
||||
|
||||
struct Test {
|
||||
emscripten::EM_VAL handle;
|
||||
};
|
||||
|
||||
auto test = new Test { event.as_handle() };
|
||||
|
||||
using PlatformWebsocketFn = void (*)(Test* event);
|
||||
|
||||
const auto& platform_websocket_message = fugg::function_ref<PlatformWebsocketFn>(
|
||||
fugg::embind::kFunctionMap["platform_websocket_message"]->fn
|
||||
);
|
||||
|
||||
platform_websocket_message(reinterpret_cast<Test*>(fugg::app_ptr(test)));
|
||||
|
||||
delete test;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_BINDINGS(my_module) {
|
||||
emscripten::function("platform_text_edited", &platform_text_edited_hook);
|
||||
emscripten::function("platform_got_devicemotion_permission", &platform_got_devicemotion_permission_hook);
|
||||
emscripten::function("platform_captcha_completed", &platform_captcha_completed_hook);
|
||||
emscripten::function("platform_websocket_open", &platform_websocket_open_hook);
|
||||
emscripten::function("platform_websocket_close", &platform_websocket_close_hook);
|
||||
emscripten::function("platform_websocket_message", &platform_websocket_message_hook);
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#include <wasm-rt.h>
|
||||
#include <client.h>
|
||||
|
||||
namespace fugg {
|
||||
namespace interop {
|
||||
namespace import {
|
||||
static const auto& init = &Z_client_init;
|
||||
|
||||
static const auto& __wasm_call_ctors = &Z_clientZ____wasm_call_ctors;
|
||||
static const auto& _main = &Z_clientZ__main;
|
||||
|
||||
|
||||
static const auto& _malloc = &Z_clientZ__malloc;
|
||||
static const auto& _free = &Z_clientZ__free;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
#include "fugg.h"
|
||||
#include "client.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <emscripten/heap.h>
|
||||
#include "interop/imports.h"
|
||||
|
||||
void *malloc (size_t __size) {
|
||||
using namespace fugg::interop;
|
||||
// This malloc is always called from the runtime.
|
||||
|
||||
if((*import::_malloc) != nullptr) {
|
||||
// Since this malloc is always called from the interop, we need to
|
||||
// transform it to point to the actual address where the WASM runtime memory
|
||||
// resides.
|
||||
|
||||
const auto& ptr = fugg::module_ptr<void>(
|
||||
(*import::_malloc)(__size)
|
||||
);
|
||||
|
||||
#if TRACE_ALLOC
|
||||
std::cout << "FLYFF: Allocated " << __size << " bytes at " << ptr << std::endl;
|
||||
#endif
|
||||
|
||||
return ptr;
|
||||
} else {
|
||||
auto ptr = emscripten_builtin_malloc(__size);
|
||||
|
||||
#if TRACE_ALLOC
|
||||
std::cout << "FUGG: Allocated " << __size << " bytes at " << ptr << std::endl;
|
||||
#endif
|
||||
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void free (void *__ptr) {
|
||||
using namespace fugg::interop;
|
||||
// printf("Trying to free ptr %p\n", __ptr);
|
||||
|
||||
if((*import::_free) != nullptr) {
|
||||
auto ptr = fugg::app_ptr(__ptr);
|
||||
|
||||
(*import::_free)(ptr);
|
||||
|
||||
#if TRACE_ALLOC
|
||||
std::cout << "FLYFF: Free'd pointer at " << ptr << std::endl;
|
||||
#endif
|
||||
} else {
|
||||
emscripten_builtin_free(__ptr);
|
||||
|
||||
#if TRACE_ALLOC
|
||||
printf("FUGG: Free'd pointer at %p\n", __ptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "Hello world from fugg!" << std::endl;
|
||||
std::cout << "Initialising runtime... ";
|
||||
|
||||
auto& client = fugg::Client::instance();
|
||||
client.initialise();
|
||||
|
||||
std::cout << "Ok!" << std::endl;
|
||||
|
||||
std::cout << "Starting Flyff..." << std::endl;
|
||||
return client.main();
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
add_library (
|
||||
fugg-core
|
||||
"include/fugg.h"
|
||||
)
|
||||
|
||||
target_include_directories(fugg-core PUBLIC "include")
|
||||
target_link_libraries (fugg-core LINK_PUBLIC flyff-client)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
|
||||
#include "../src/memory.h"
|
||||
#include "../src/table.h"
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
#pragma once
|
||||
|
||||
#include <client.h>
|
||||
#include <wasm-rt.h>
|
||||
|
||||
namespace fugg {
|
||||
namespace wasm {
|
||||
class Memory {
|
||||
wasm_rt_memory_t** memory;
|
||||
|
||||
public:
|
||||
explicit Memory(wasm_rt_memory_t** memory) : memory(memory) { }
|
||||
|
||||
uintptr_t address_of(uintptr_t offset) const {
|
||||
if(offset != NULL)
|
||||
return reinterpret_cast<uintptr_t>(&(*memory)->data[offset]);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uintptr_t start() {
|
||||
return reinterpret_cast<uintptr_t>(
|
||||
(*memory)->data
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
static auto kMemory = Memory { &Z_clientZ_memory };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T* module_ptr(uintptr_t address) {
|
||||
return reinterpret_cast<T*>(
|
||||
wasm::kMemory.address_of(address)
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T* module_ptr(T* &address) {
|
||||
return module_ptr<T>(reinterpret_cast<uintptr_t>(address));
|
||||
}
|
||||
|
||||
static uintptr_t app_ptr(uintptr_t offset) {
|
||||
if(offset != NULL)
|
||||
return offset - wasm::kMemory.start();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uintptr_t app_ptr(const void* offset) {
|
||||
return app_ptr(reinterpret_cast<uintptr_t>(offset));
|
||||
}
|
||||
|
||||
|
||||
// Value does not have to be offset.
|
||||
template<typename T>
|
||||
class Value {
|
||||
T value;
|
||||
|
||||
public:
|
||||
explicit Value(const T& value) : value(value) { }
|
||||
|
||||
Value<T>& operator=(T value) {
|
||||
this->value = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator T() const {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
// Modifies the array to let the pointers be accessible from outside the WASM runtime
|
||||
template<typename T>
|
||||
static T* ptr_array(uintptr_t address, size_t length) {
|
||||
auto src = reinterpret_cast<uintptr_t*>(
|
||||
wasm::kMemory.address_of(address)
|
||||
);
|
||||
|
||||
for(unsigned int i = 0; i < length; i++) {
|
||||
src[i] = wasm::kMemory.address_of(src[i]);
|
||||
}
|
||||
|
||||
return reinterpret_cast<T*>(src);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <client.h>
|
||||
#include <wasm-rt.h>
|
||||
|
||||
namespace fugg {
|
||||
namespace wasm
|
||||
{
|
||||
class Table {
|
||||
wasm_rt_table_t** table;
|
||||
|
||||
public:
|
||||
explicit Table(wasm_rt_table_t** table) : table(table) { }
|
||||
|
||||
wasm_rt_elem_t* element(uintptr_t address) const {
|
||||
return &(*table)->data[address];
|
||||
}
|
||||
};
|
||||
|
||||
static auto kTable = Table { &Z_clientZ_table };
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
static T function_ref(uintptr_t address) {
|
||||
const auto& element = wasm::kTable.element(address);
|
||||
|
||||
return reinterpret_cast<T>(element->func);
|
||||
}
|
||||
}
|
||||
Reference in New Issue