platform_wasm.c (4991B)
1 #include <limits.h> 2 #include <stdalign.h> 3 #include <stdbool.h> 4 #include <stddef.h> 5 #include <stdint.h> 6 7 #define static_assert _Static_assert 8 9 // Begin terrible libc substitutions 10 // TODO: make this libc replacement not shitty 11 #define assert(x) (void)0 12 13 int32_t printf(const char *format, ...) 14 { 15 // lol 16 return 0; 17 } 18 19 // looooooooooool 20 #define exit(status) (void)0 21 22 void *memset(void *s, int32_t c, size_t n) 23 { 24 uint8_t *p = s; 25 while(n > 0) 26 { 27 *p = (uint8_t)c; 28 p++; 29 n--; 30 } 31 return s; 32 } 33 34 // TODO: assert no overlap 35 void *memcpy(void *dst, const void *src, size_t n) 36 { 37 uint8_t *destination = (uint8_t *)dst; 38 uint8_t *source = (uint8_t *)src; 39 40 while (n--) 41 { 42 *destination = *source; 43 destination++; 44 source++; 45 } 46 47 return dst; 48 } 49 50 // TODO: actually implement 51 void *memmove(void *dst, const void *src, size_t n) 52 { 53 return memcpy(dst, src, n); 54 } 55 56 static_assert(__has_builtin(__builtin_sqrtf), "No builtin sqrtf builtin"); 57 #define sqrtf(x) __builtin_sqrtf((x)) 58 59 float js_cosf(float); 60 float js_fabsf(float); 61 float js_powf(float, float); 62 float js_sinf(float); 63 float js_tanf(float); 64 float js_cosf(float); 65 66 float cosf(float x) { 67 return js_cosf(x); 68 } 69 70 float fabsf(float x) { 71 return js_fabsf(x); 72 } 73 74 float powf(float x, float y) { 75 return js_powf(x, y); 76 } 77 78 float sinf(float x) { 79 return js_sinf(x); 80 } 81 82 float tanf(float x) { 83 return js_tanf(x); 84 } 85 // End terrible libc substitutions 86 87 #include "platform_info.h" 88 89 #include "game.c" 90 #include "platform.h" 91 #include "platform_wasm.h" 92 93 // wasm-ld memory layout: 94 // a b 95 // data | stack | heap 96 // a = __data_end 97 // b = __heap_base 98 extern u8 __heap_base; 99 extern u8 __data_end; 100 101 // There's no standardized, nondeprecated way to get a numeric ID of a keyboard 102 // key, so I guess we have to do that ourselves. 103 enum WasmKey { 104 WASM_KEY_LEFT, 105 WASM_KEY_RIGHT, 106 WASM_KEY_UP, 107 WASM_KEY_DOWN, 108 WASM_KEY_S, 109 WASM_KEY_F11, 110 }; 111 112 // TODO: map this in a nicer way 113 global_variable int platform_input_map[NUM_GAME_BUTTONS] = { 114 [BTN_LEFT] = WASM_KEY_LEFT, 115 [BTN_RIGHT] = WASM_KEY_RIGHT, 116 [BTN_UP] = WASM_KEY_UP, 117 [BTN_DOWN] = WASM_KEY_DOWN, 118 [BTN_JUMP] = WASM_KEY_S, 119 [BTN_DEBUG_FLOAT] = WASM_KEY_F11, 120 }; 121 122 global_variable struct GameMemory game_memory = {0}; 123 global_variable struct GameInput game_input = {0}; 124 global_variable i32 g_width = PLATFORM_SCR_WIDTH; 125 global_variable i32 g_height = PLATFORM_SCR_HEIGHT; 126 global_variable u32 previous_time = 0; 127 128 i32 str_length(const char *str) 129 { 130 i32 i = 0; 131 while(str[i] != '\0') 132 { 133 i++; 134 } 135 return i; 136 } 137 138 int wasm_print(const char *format, ...) 139 { 140 i32 len = str_length(format); 141 js_print((i32)format, len); 142 return 0; 143 } 144 145 bool init(i32 num_wasm_memory_pages) 146 { 147 bool init_successful = true; 148 game_memory = (struct GameMemory) { 149 // NOTE(amin): each wasm memory page is 64KiB 150 .buffer_size = num_wasm_memory_pages * KIBIBYTES(64), 151 .platform = { 152 &wasm_read_entire_file, 153 &wasm_memory_free, 154 }, 155 .buffer = &__heap_base, 156 }; 157 if (!game_memory.buffer) 158 { 159 wasm_print("Game memory allocation failed\n"); 160 init_successful = false; 161 } 162 game_init(&game_memory, (v2u) {g_width, g_height}); 163 return init_successful; 164 } 165 166 void render(f64 current_time) 167 { 168 game_input.dt = current_time - previous_time; 169 previous_time = current_time; 170 game_update_and_render(&game_memory, &game_input, (v2u) {g_width, g_height}); 171 } 172 173 void window_resize(int w, int h) 174 { 175 g_width = w; 176 g_height = h; 177 } 178 179 void key_callback(enum WasmKey key, bool key_action_is_pressed) 180 { 181 enum GameButton game_button = NULL_GAME_BUTTON; 182 // TODO: Determine the button in a nicer way 183 for (enum GameButton b = 0; b < NUM_GAME_BUTTONS; b++) 184 { 185 if (platform_input_map[b] == key) 186 { 187 game_button = b; 188 } 189 } 190 if (game_button != NULL_GAME_BUTTON) 191 { 192 if (key_action_is_pressed) 193 { 194 game_input.button_states |= (1 << game_button); 195 } 196 else 197 { 198 game_input.button_states &= ~(1 << game_button); 199 } 200 } 201 } 202 203 PLATFORM_MEMORY_FREE(wasm_memory_free) 204 { 205 // do nothing 206 } 207 208 PLATFORM_READ_ENTIRE_FILE(wasm_read_entire_file) 209 { 210 i32 num_bytes_in_file = js_get_file_size((i32)file_path, str_length(file_path)); 211 212 if (out_num_bytes) 213 { 214 *out_num_bytes = num_bytes_in_file; 215 } 216 217 size_t fail_reversion_marker = mem_st_get_marker(a); 218 u8 *buf = mem_st_alloc_buffer(a, u8, num_bytes_in_file + 1); 219 assert(buf); 220 221 bool success = js_read_entire_file((i32)file_path, str_length(file_path), buf); 222 if (success) 223 { 224 buf[num_bytes_in_file] = '\0'; 225 wasm_print("Succeeded in reading file."); 226 } 227 else 228 { 229 mem_st_free_to_marker(a, fail_reversion_marker); 230 buf = NULL; 231 wasm_print("Failed to read file."); 232 } 233 return buf; 234 }