diff --git a/Makefile b/Makefile index 3302df2..67ea6c6 100644 --- a/Makefile +++ b/Makefile @@ -58,6 +58,7 @@ endif # --- EMSCRIPTEN-SPECIFIC --- ifeq ($(PLATFORM), emscripten) + PLATFORM_CFLAGS += -s USE_SDL=2 LDFLAGS += -s USE_SDL=2\ -s ASYNCIFY \ -s ALLOW_MEMORY_GROWTH=1 \ diff --git a/src/arch/emscripten/devices.c b/src/arch/emscripten/devices.c index 4d667b1..56d2754 100644 --- a/src/arch/emscripten/devices.c +++ b/src/arch/emscripten/devices.c @@ -60,32 +60,7 @@ i32 screen_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size) { memcpy(&info[8], &screen->height, sizeof(u32)); memcpy(&info[12], &screen->buffer_size, sizeof(u32)); screen->screen_buffer = (u8*)(buffer + 16); - - screen->window = - SDL_CreateWindow("Reality Engine VM", SDL_WINDOWPOS_CENTERED, - SDL_WINDOWPOS_CENTERED, screen->width, screen->height, - SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI); - - if (!screen->window) { - return -1; - } - - screen->renderer = - SDL_CreateRenderer(screen->window, -1, SDL_RENDERER_ACCELERATED); - if (!screen->renderer) { - return -1; - } - - screen->texture = SDL_CreateTexture(screen->renderer, SDL_PIXELFORMAT_RGB332, - SDL_TEXTUREACCESS_STREAMING, - screen->width, screen->height); - - if (!screen->texture) { - fprintf(stderr, "SDL_CreateTexture failed: %s\n", SDL_GetError()); - return -1; - } - - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); + return 0; } diff --git a/src/arch/emscripten/main.c b/src/arch/emscripten/main.c index e22622c..4c43664 100644 --- a/src/arch/emscripten/main.c +++ b/src/arch/emscripten/main.c @@ -33,59 +33,106 @@ static ScreenDeviceData screen_data = {0}; static MouseDeviceData mouse_data = {0}; static ConsoleDeviceData console_data = {0}; +static bool display_size_changed = false; + +// The callback: +static EM_BOOL on_web_display_size_changed( int event_type, + const EmscriptenUiEvent *event, void *user_data ) +{ + display_size_changed = 1; // custom global flag + return 0; +} + +void scale_mouse_pos(u32 mouse_x, u32 mouse_y, u32 *vm_x, u32 *vm_y) { + int win_w, win_h; + SDL_GetWindowSize(screen_data.window, &win_w, &win_h); + + f32 scale_x = (f32)win_w / screen_data.width; + f32 scale_y = (f32)win_h / screen_data.height; + f32 scale = SDL_min(scale_x, scale_y); + + u32 dst_w = (u32)(screen_data.width * scale); + u32 dst_h = (u32)(screen_data.height * scale); + u32 dst_x = (win_w - dst_w) / 2; + u32 dst_y = (win_h - dst_h) / 2; + + f32 rel_x = (f32)(mouse_x - dst_x); + f32 rel_y = (f32)(mouse_y - dst_y); + + *vm_x = (u32)((rel_x / (f32)dst_w) * screen_data.width); + *vm_y = (u32)((rel_y / (f32)dst_h) * screen_data.height); + + if (*vm_x >= screen_data.width) *vm_x = screen_data.width - 1; + if (*vm_y >= screen_data.height) *vm_y = screen_data.height - 1; +} + void mainloop() { SDL_Event event; SDL_PumpEvents(); - while (SDL_PollEvent(&event)) { - switch (event.type) { - // Mouse events - case SDL_MOUSEMOTION: - mouse_data.x = event.motion.x; - mouse_data.y = event.motion.y; - break; - - case SDL_MOUSEBUTTONDOWN: - if (event.button.button == SDL_BUTTON_LEFT) - mouse_data.btn1 = 1; - if (event.button.button == SDL_BUTTON_RIGHT) - mouse_data.btn2 = 1; - if (event.button.button == SDL_BUTTON_MIDDLE) - mouse_data.btn3 = 1; - if (event.button.button == SDL_BUTTON_X1) - mouse_data.btn4 = 1; - break; - - case SDL_MOUSEBUTTONUP: - if (event.button.button == SDL_BUTTON_LEFT) - mouse_data.btn1 = 0; - if (event.button.button == SDL_BUTTON_RIGHT) - mouse_data.btn2 = 0; - if (event.button.button == SDL_BUTTON_MIDDLE) - mouse_data.btn3 = 0; - if (event.button.button == SDL_BUTTON_X1) - mouse_data.btn4 = 0; - break; - - case SDL_FINGERMOTION: - case SDL_FINGERDOWN: - case SDL_FINGERUP: { - - float x = event.tfinger.x * 640; - float y = event.tfinger.y * 480; - - mouse_data.x = (int)x; - mouse_data.y = (int)y; - - if (event.tfinger.fingerId == 0) { - if (event.type == SDL_FINGERDOWN || event.type == SDL_FINGERMOTION) { - mouse_data.btn1 = 1; - } else if (event.type == SDL_FINGERUP) { - mouse_data.btn1 = 0; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_WINDOWEVENT:{ + switch (event.window.event) { + case SDL_WINDOWEVENT_RESIZED: + screen_data.update = true; + break; } + break; + } + case SDL_MOUSEMOTION: { + u32 vm_x, vm_y; + scale_mouse_pos(event.motion.x, event.motion.y, &vm_x, &vm_y); + mouse_data.x = vm_x; + mouse_data.y = vm_y; + break; + } + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: { + u32 vm_x, vm_y; + scale_mouse_pos(event.button.x, event.button.y, &vm_x, &vm_y); + + mouse_data.x = vm_x; + mouse_data.y = vm_y; + + bool pressed = (event.type == SDL_MOUSEBUTTONDOWN); + if (event.button.button == SDL_BUTTON_LEFT) mouse_data.btn1 = pressed; + if (event.button.button == SDL_BUTTON_RIGHT) mouse_data.btn2 = pressed; + if (event.button.button == SDL_BUTTON_MIDDLE) mouse_data.btn3 = pressed; + if (event.button.button == SDL_BUTTON_X1) mouse_data.btn4 = pressed; + break; + } + case SDL_FINGERMOTION: + case SDL_FINGERDOWN: + case SDL_FINGERUP: { + int win_w, win_h; + SDL_GetWindowSize(screen_data.window, &win_w, &win_h); + + u32 touch_pixel_x = (u32)(event.tfinger.x * win_w); + u32 touch_pixel_y = (u32)(event.tfinger.y * win_h); + + u32 vm_x, vm_y; + scale_mouse_pos(touch_pixel_x, touch_pixel_y, &vm_x, &vm_y); + + mouse_data.x = vm_x; + mouse_data.y = vm_y; + + if (event.tfinger.fingerId == 0) { + bool pressed = (event.type == SDL_FINGERDOWN || event.type == SDL_FINGERMOTION); + mouse_data.btn1 = pressed ? 1 : 0; + } + break; + } } - break; - } } + + // In the emscripten_set_main_loop() callback: + if (display_size_changed) + { + double w, h; + emscripten_get_element_css_size( "#canvas", &w, &h ); + SDL_SetWindowSize( screen_data.window, (int)w, (int) h ); + + display_size_changed = 0; } int cycles_this_frame = 0; @@ -100,8 +147,26 @@ void mainloop() { if (screen_data.update) { if (screen_data.renderer && screen_data.texture) { - SDL_RenderCopy(screen_data.renderer, screen_data.texture, NULL, NULL); - SDL_RenderPresent(screen_data.renderer); + // Clear and render + SDL_RenderClear(screen_data.renderer); + + int window_w, window_h; + SDL_GetWindowSize(screen_data.window, &window_w, &window_h); + + // Calculate aspect ratio preserving scaling + f32 scale_x = (f32)window_w / screen_data.width; + f32 scale_y = (f32)window_h / screen_data.height; + f32 scale = SDL_min(scale_x, scale_y); + + SDL_Rect dstrect = { + (i32)((window_w - screen_data.width * scale) / 2), + (i32)((window_h - screen_data.height * scale) / 2), + (i32)(screen_data.width * scale), + (i32)(screen_data.height * scale)}; + + SDL_RenderCopy(screen_data.renderer, screen_data.texture, NULL, + &dstrect); + SDL_RenderPresent(screen_data.renderer); } screen_data.update = false; } @@ -148,6 +213,7 @@ int main(int argc, char **argv) { return 1; } SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest"); #ifdef __EMSCRIPTEN__ emscripten_set_canvas_element_size("#canvas", 640, 480); @@ -160,9 +226,24 @@ int main(int argc, char **argv) { screen_data.width = 640; screen_data.height = 480; screen_data.buffer_size = screen_data.width * screen_data.height; - screen_data.window = NULL; - screen_data.renderer = NULL; - screen_data.texture = NULL; + screen_data.window = SDL_CreateWindow("Reality Engine VM", SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, 640, 480, + SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI); + + screen_data.renderer = + SDL_CreateRenderer(screen_data.window, -1, SDL_RENDERER_ACCELERATED); + if (!screen_data.renderer) { + return -1; + } + + screen_data.texture = SDL_CreateTexture(screen_data.renderer, SDL_PIXELFORMAT_RGB332, + SDL_TEXTUREACCESS_STREAMING, + screen_data.width, screen_data.height); + + if (!screen_data.texture) { + fprintf(stderr, "SDL_CreateTexture failed: %s\n", SDL_GetError()); + return -1; + } mouse_data.x = 0; mouse_data.y = 0; @@ -179,6 +260,11 @@ int main(int argc, char **argv) { vm_register_device(&vm, "/dev/term/0", "terminal", &console_data, &console_device_ops, 4); + emscripten_set_resize_callback( + EMSCRIPTEN_EVENT_TARGET_WINDOW, + 0, 0, on_web_display_size_changed + ); + emscripten_set_main_loop(mainloop, 0, 1); return 0; } diff --git a/src/arch/emscripten/shell_minimal.html b/src/arch/emscripten/shell_minimal.html index 8a8c6db..6e7fec8 100644 --- a/src/arch/emscripten/shell_minimal.html +++ b/src/arch/emscripten/shell_minimal.html @@ -208,8 +208,9 @@ Resize canvas Lock/hide mouse pointer - +