Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@
# executable
/GPMD85emu

# WebAssembly & Emscripten
*.wasm
/storage
/GPMD85emu.js
/GPMD85emu.data

# autoconf
/autom4te.cache
/autoscan.log
Expand Down
30 changes: 29 additions & 1 deletion GPMD85emu.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* GPMD85emu.cpp: Initialization and main program loop.
Copyright (c) 2011-2024 Martin Borik <mborik@users.sourceforge.net>
Copyright (c) 2011-2025 Martin Borik <mborik@users.sourceforge.net>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand All @@ -21,6 +21,18 @@
//-----------------------------------------------------------------------------
int main(int argc, char** argv)
{
#ifdef __EMSCRIPTEN__
#define PATH_WEBHOME "/home/web_user"
#define PATH_STORAGE "/storage"
PathUserHome = strdup(PATH_WEBHOME);
PathApplication = strdup(PATH_STORAGE);
PathResources = (char *) malloc(strlen(PATH_STORAGE) + 1);
PathAppConfig = (char *) malloc(strlen(PATH_WEBHOME) + 1);
strcpy(PathResources, PATH_STORAGE);
strcpy(PathAppConfig, PATH_WEBHOME);

EmResetBlocking();
#else
if (!ParseOptions(&argc, &argv))
return EXIT_FAILURE;
else if (argv_config.version) {
Expand All @@ -36,6 +48,7 @@ int main(int argc, char** argv)
PathAppConfig = (char *) malloc(strlen(PathUserHome) + 16);
strcpy(PathResources, DIR_RESOURCES);
sprintf(PathAppConfig, "%s%c.%s", PathUserHome, DIR_DELIMITER, PACKAGE_TARNAME);
#endif

debug("", "Resource path: %s", PathResources);
debug(NULL, "Application path: %s", PathApplication);
Expand Down Expand Up @@ -126,7 +139,18 @@ int main(int argc, char** argv)
debug("", "Starting main CPU %dHz loop", CPU_FRAMES_PER_SEC);

while (Emulator->isActive) {
#ifdef __EMSCRIPTEN__
if (!EmCheckBlocking())
continue;

EmRegisterMainLoop([&] {
if (!Emulator->isActive) {
EmExitMainLoop();
return;
}
#else
nextTick = SDL_GetTicks() + CPU_TIMER_INTERVAL;
#endif

while (SDL_PollEvent(&event)) {
switch (event.type) {
Expand Down Expand Up @@ -214,8 +238,12 @@ int main(int argc, char** argv)

Emulator->CpuTimerCallback();

#ifdef __EMSCRIPTEN__
});
#else
while (SDL_GetTicks() < nextTick)
SDL_Delay(1);
#endif
}

SDL_GetWindowPosition(gdc.window,
Expand Down
42 changes: 32 additions & 10 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[
]])], [clang=yes], [clang=no])
AC_MSG_RESULT([$clang])

# Add an additional flag if using Emscripten
AC_MSG_CHECKING([if compiling with Emscripten])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[
#ifndef __EMSCRIPTEN__
not emscripten
#endif
]])], [emscripten=yes], [emscripten=no])
AM_CONDITIONAL([EMSCRIPTEN], [test "x$emscripten" = "xyes"])
AC_MSG_RESULT([$emscripten])

# Check if we have enabled debug mode:
AC_MSG_CHECKING([gpmd85emu: Debug mode])
AC_ARG_ENABLE([debug],
Expand Down Expand Up @@ -85,8 +95,18 @@ if test "x$softrender" = "xyes"; then
fi
AC_MSG_RESULT([${softrender}])

resDir_CFLAGS=" -DDIR_RESOURCES=\"\\\""$\{pkgdatadir}"\\\"\""
AC_SUBST(resDir_CFLAGS)
if test "x$emscripten" = "xyes"; then
AC_MSG_RESULT([override gpmd85emu: Software renderer... yes for Emscripten])
CXXFLAGS+=" -DSOFTRENDER -s USE_SDL=2"
CFLAGS+=" -DSOFTRENDER -s USE_SDL=2"
LDFLAGS+=" -Oz \
-s ENVIRONMENT=web \
-s ALLOW_MEMORY_GROWTH=1 \
-s OFFSCREEN_FRAMEBUFFER=1 \
--use-preload-plugins --preload-file ./storage"
EXEEXT=".js"
else
resDir_CFLAGS=" -DDIR_RESOURCES=\"\\\""$\{pkgdatadir}"\\\"\""

# Checks for libraries (with classic lib/header solution if pkg-config fail):
PKG_CHECK_MODULES([libSDL], [sdl2],, [
Expand All @@ -100,6 +120,15 @@ PKG_CHECK_MODULES([libSDL], [sdl2],, [
], AC_MSG_ERROR([SDL2 library not found]))
])

# NOTICE: In case of compile error with missing malloc() / realloc() functions,
# you can try to set enviroment variables 'ac_cv_func_malloc_0_nonnull'
# and 'ac_cv_func_realloc_0_nonnull' to 'yes' and reconfigure.
AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_FUNC_ERROR_AT_LINE
fi

AC_SUBST(resDir_CFLAGS)
AC_SUBST(CXXFLAGS)
AC_SUBST(CFLAGS)
AC_SUBST(DEBUG)
Expand All @@ -108,7 +137,7 @@ AC_SUBST(DEBUG)
AC_CHECK_HEADERS([\
stdio.h stdarg.h stddef.h stdint.h stdlib.h unistd.h \
inttypes.h memory.h string.h strings.h \
sys/syslimits.h \
sys/syslimits.h sys/stat.h sys/types.h \
])

AC_HEADER_STAT
Expand All @@ -118,13 +147,6 @@ AC_HEADER_STDBOOL
AC_C_BIGENDIAN
AC_C_INLINE

# NOTICE: In case of compile error with missing malloc() / realloc() functions,
# you can try to set enviroment variables 'ac_cv_func_malloc_0_nonnull'
# and 'ac_cv_func_realloc_0_nonnull' to 'yes' and reconfigure.
AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_FUNC_ERROR_AT_LINE

# Checks for standard library functions:
AC_CHECK_FUNCS([memset mkdir strstr strtol strcasecmp strrchr])

Expand Down
19 changes: 19 additions & 0 deletions globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,25 @@ enum TDebugListSource { MEM, HL, DE, BC, AF, SP, PC };
// screen offsets of top-left -> bottom-right corner
typedef struct TDrawRegion { WORD tl, br; } TDrawRegion;
//-----------------------------------------------------------------------------
#ifdef __EMSCRIPTEN__
// WebAssembly modifications using emscripten
#include <emscripten.h>
#include <functional>
static std::function<void()> EmMainLoopRef;
static std::function<bool()> EmCheckBlockingRef;
inline void EmMainLoopImpl() { EmMainLoopRef(); }
inline bool EmCheckBlocking() { return EmCheckBlockingRef(); }
inline void EmResetBlocking() { EmCheckBlockingRef = [] { return true; }; }
inline void EmSetBlocking(std::function<bool()> checker) {
EmCheckBlockingRef = checker;
}
inline void EmRegisterMainLoop(std::function<void()> loop) {
EmMainLoopRef = loop;
emscripten_set_main_loop(EmMainLoopImpl, CPU_TIMER_INTERVAL, true);
}
inline void EmExitMainLoop() { emscripten_cancel_main_loop(); }
#endif
//-----------------------------------------------------------------------------
static char msgbuffer[1024];
//-----------------------------------------------------------------------------
inline void error(const char *ns, const char *msg, ...)
Expand Down
14 changes: 14 additions & 0 deletions gui/CommonDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,14 @@ void UserInterface::AboutDialog()
DWORD nextTick;
SDL_Event event;

#ifdef __EMSCRIPTEN__
EmSetBlocking([&] { return (i == 0); });
EmExitMainLoop();
EmRegisterMainLoop([&] {
#else
while (i) {
nextTick = SDL_GetTicks() + CPU_TIMER_INTERVAL;
#endif

while (SDL_PollEvent(&event)) {
switch (event.type) {
Expand Down Expand Up @@ -149,9 +155,13 @@ void UserInterface::AboutDialog()
}
}

#ifdef __EMSCRIPTEN__
});
#else
while (SDL_GetTicks() < nextTick)
SDL_Delay(1);
}
#endif

defaultSurface = LockSurface(defaultTexture);

Expand All @@ -168,6 +178,10 @@ void UserInterface::AboutDialog()

SDL_Delay(GPU_TIMER_INTERVAL);
needRelease = true;

#ifdef __EMSCRIPTEN__
EmResetBlocking();
#endif
}
//-----------------------------------------------------------------------------
BYTE UserInterface::QueryDialog(const char *title, bool save)
Expand Down
4 changes: 4 additions & 0 deletions gui/UserInterfaceData.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,9 @@ static GUI_MENU_ENTRY gui_view_size_menu[] = {
{ MI_RADIO, "\a300%", "3", SDL_SCANCODE_3, NULL, ccb_view_size, dcb_view_size_state, true, false, DM_TRIPLESIZE },
{ MI_RADIO, "\a400%", "4", SDL_SCANCODE_4, NULL, ccb_view_size, dcb_view_size_state, true, false, DM_QUADRUPLESIZE },
{ MI_RADIO, "\a500%", "5", SDL_SCANCODE_5, NULL, ccb_view_size, dcb_view_size_state, true, false, DM_QUINTUPLESIZE },
#ifndef __EMSCRIPTEN__
{ MI_RADIO, "\aFULLSCREEN", "F", SDL_SCANCODE_F, NULL, ccb_view_size, dcb_view_size_state, true, false, DM_FULLSCREEN },
#endif
{ MENU_END }
};
static GUI_MENU_ENTRY gui_view_cmode_menu[] = {
Expand Down Expand Up @@ -421,7 +423,9 @@ static GUI_MENU_ENTRY UNUSED_VARIABLE gui_main_menu[] = {
{ MI_DIALOG, "P\aOKE", NULL, SDL_SCANCODE_O, NULL, NULL, NULL, false },
{ MI_SEPARATOR },
{ MI_DIALOG, "\aABOUT", "^F1", SDL_SCANCODE_A, NULL, ccb_about, NULL, true },
#ifndef __EMSCRIPTEN__
{ MI_STANDARD, "E\aXIT", "F4", SDL_SCANCODE_X, NULL, ccb_exit, NULL, true },
#endif
{ MENU_END }
};
//-----------------------------------------------------------------------------
Expand Down
9 changes: 9 additions & 0 deletions res/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ RES = \
icon.bmp \
statusbar.bmp

if EMSCRIPTEN
bin_SCRIPTS = .emcpy
CLEANFILES = $(bin_SCRIPTS)
.emcpy:
@echo "Copying resource files to WASM storage"
@cp $(RES) ../storage
@touch $@
endif

pkgdata_DATA = $(RES)

EXTRA_DIST = $(RES)
10 changes: 10 additions & 0 deletions rom/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ ROM = \
sach1.rmm \
wurmi.rmm

if EMSCRIPTEN
bin_SCRIPTS = .emcpy
CLEANFILES = $(bin_SCRIPTS)
.emcpy:
@echo "Copying ROM files to WASM storage/rom/"
@mkdir -p ../storage/rom
@cp $(ROM) ../storage/rom/
@touch $@
endif

pkgdata_DATA = $(ROM)

EXTRA_DIST = $(ROM) README.md
4 changes: 4 additions & 0 deletions src/Emulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -699,13 +699,15 @@ bool TEmulator::TestHotkeys()
Settings->Screen->halfPass = HP_OFF;
break;

#ifndef __EMSCRIPTEN__
case SDL_SCANCODE_F: // FULL-SCREEN
case SDL_SCANCODE_RETURN:
if (Settings->Screen->size == DM_FULLSCREEN)
ActionSizeChange((int) Settings->Screen->realsize);
else
ActionSizeChange(0);
return true;
#endif

case SDL_SCANCODE_M: // MONO/STANDARD MODES
if (video->GetColorProfile() == CP_STANDARD) {
Expand Down Expand Up @@ -760,9 +762,11 @@ bool TEmulator::TestHotkeys()
ActionPlayPause();
break;

#ifndef __EMSCRIPTEN__
case SDL_SCANCODE_F4: // EXIT
ActionExit();
break;
#endif

case SDL_SCANCODE_F5: // RESET
if (key & KM_SHIFT)
Expand Down
Empty file added storage/.gitkeep
Empty file.