Emscripten improvements (#17422)
This commit is contained in:
parent
104561e7aa
commit
ed1810de86
|
@ -196,6 +196,8 @@ retroarch.js
|
||||||
retroarch.js.mem
|
retroarch.js.mem
|
||||||
*.bc
|
*.bc
|
||||||
*.wasm
|
*.wasm
|
||||||
|
*.wasm.map
|
||||||
|
obj-emscripten/
|
||||||
|
|
||||||
# only ignore .js files in the repo root
|
# only ignore .js files in the repo root
|
||||||
/*.js
|
/*.js
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
- CHEEVOS: Include achievement state in netplay states
|
- CHEEVOS: Include achievement state in netplay states
|
||||||
- CLOUDSYNC: Fix Windows path issues
|
- CLOUDSYNC: Fix Windows path issues
|
||||||
- CLOUDSYNC: Workaround for duplicated requests bug
|
- CLOUDSYNC: Workaround for duplicated requests bug
|
||||||
|
- EMSCRIPTEN: Scale window to correct size
|
||||||
|
- EMSCRIPTEN: Additional platform functions
|
||||||
|
- EMSCRIPTEN/RWEBINPUT: Add touch input support
|
||||||
- GENERAL: Fix save state auto increment
|
- GENERAL: Fix save state auto increment
|
||||||
- GENERAL: Fix softpatching with periods/dots in the file name
|
- GENERAL: Fix softpatching with periods/dots in the file name
|
||||||
- GENERAL: Fix compilation with --enable-videocore
|
- GENERAL: Fix compilation with --enable-videocore
|
||||||
|
@ -34,6 +37,7 @@
|
||||||
- SAVESTATES: Reset state index when loading new content
|
- SAVESTATES: Reset state index when loading new content
|
||||||
- UWP: Fix slang shader compilation
|
- UWP: Fix slang shader compilation
|
||||||
- VIDEO: Enable BFI setting for mobile platforms (mind the warnings)
|
- VIDEO: Enable BFI setting for mobile platforms (mind the warnings)
|
||||||
|
- VIDEO/OpenGLES: Fix FP/sRGB FBO support
|
||||||
- VIDEO/SHADERS: Allow exact refresh rate sync with shader subframes
|
- VIDEO/SHADERS: Allow exact refresh rate sync with shader subframes
|
||||||
- WEBPLAYER: Update core list for 1.20.0
|
- WEBPLAYER: Update core list for 1.20.0
|
||||||
|
|
||||||
|
|
|
@ -1570,10 +1570,11 @@ ifeq ($(HAVE_GL_CONTEXT), 1)
|
||||||
DEF_FLAGS += $(OPENGLES_CFLAGS)
|
DEF_FLAGS += $(OPENGLES_CFLAGS)
|
||||||
ifeq ($(HAVE_OPENGLES3), 1)
|
ifeq ($(HAVE_OPENGLES3), 1)
|
||||||
DEFINES += -DHAVE_OPENGLES3
|
DEFINES += -DHAVE_OPENGLES3
|
||||||
|
OBJ += $(LIBRETRO_COMM_DIR)/glsym/glsym_es3.o
|
||||||
else
|
else
|
||||||
DEFINES += -DHAVE_OPENGLES2
|
DEFINES += -DHAVE_OPENGLES2
|
||||||
|
OBJ += $(LIBRETRO_COMM_DIR)/glsym/glsym_es2.o
|
||||||
endif
|
endif
|
||||||
OBJ += $(LIBRETRO_COMM_DIR)/glsym/glsym_es2.o
|
|
||||||
else
|
else
|
||||||
DEFINES += -DHAVE_GL_SYNC
|
DEFINES += -DHAVE_GL_SYNC
|
||||||
OBJ += $(LIBRETRO_COMM_DIR)/glsym/glsym_gl.o
|
OBJ += $(LIBRETRO_COMM_DIR)/glsym/glsym_gl.o
|
||||||
|
|
|
@ -25,7 +25,6 @@ HAVE_REWIND = 1
|
||||||
HAVE_AUDIOMIXER = 1
|
HAVE_AUDIOMIXER = 1
|
||||||
HAVE_CC_RESAMPLER = 1
|
HAVE_CC_RESAMPLER = 1
|
||||||
HAVE_EGL = 1
|
HAVE_EGL = 1
|
||||||
HAVE_OPENGLES = 1
|
|
||||||
HAVE_RJPEG = 0
|
HAVE_RJPEG = 0
|
||||||
HAVE_RPNG = 1
|
HAVE_RPNG = 1
|
||||||
HAVE_EMSCRIPTEN = 1
|
HAVE_EMSCRIPTEN = 1
|
||||||
|
@ -58,34 +57,49 @@ HAVE_CHD ?= 0
|
||||||
# You have been warned.
|
# You have been warned.
|
||||||
HAVE_RWEBAUDIO = 0
|
HAVE_RWEBAUDIO = 0
|
||||||
|
|
||||||
|
# help diagnose GL problems (can cause issues in normal operation)
|
||||||
|
GL_DEBUG ?= 0
|
||||||
|
|
||||||
|
# enable javascript filesystem tracking
|
||||||
|
FS_DEBUG = 1
|
||||||
|
|
||||||
|
HAVE_OPENGLES ?= 1
|
||||||
|
HAVE_OPENGLES3 ?= 0
|
||||||
|
|
||||||
ASYNC ?= 0
|
ASYNC ?= 0
|
||||||
ifeq ($(LIBRETRO), mupen64plus)
|
|
||||||
ASYNC = 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
LTO ?= 0
|
LTO ?= 0
|
||||||
ifeq ($(LIBRETRO), tyrquake)
|
|
||||||
LTO = 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
PTHREAD ?= 0
|
PTHREAD ?= 0
|
||||||
|
|
||||||
MEMORY ?= 134217728
|
STACK_SIZE ?= 4194304
|
||||||
|
INITIAL_HEAP ?= 134217728
|
||||||
|
|
||||||
PRECISE_F32 = 1
|
# 4194304 ----- 4 MiB (Stack: recommended)
|
||||||
|
# 8388608 ----- 8 MiB
|
||||||
|
# 16777216 ---- 16 MiB
|
||||||
|
# 33554432 ---- 32 MiB
|
||||||
|
# 67108864 ---- 64 MiB
|
||||||
|
# 134217728 --- 128 MiB (Heap: recommended) (Stack: recommended for some cores [mupen64plus_next])
|
||||||
|
# 268435456 --- 256 MiB (Heap: recommended for some cores [mupen64plus_next])
|
||||||
|
# 536870912 --- 512 MiB (Heap: needed for some cores [mednafen_psx(_hw)])
|
||||||
|
# 1073741824 -- 1 GiB
|
||||||
|
# 1610612736 -- 1.5 GiB
|
||||||
|
# 2147483648 -- 2 GiB
|
||||||
|
|
||||||
OBJDIR := obj-emscripten
|
OBJDIR := obj-emscripten
|
||||||
|
|
||||||
#if you compile with SDL2 flag add this Emscripten flag "-s USE_SDL=2" to LDFLAGS:
|
EXPORTED_FUNCTIONS = _main,_malloc,_free,_cmd_savefiles,_cmd_save_state,_cmd_load_state,_cmd_undo_save_state,_cmd_undo_load_state,_cmd_take_screenshot,\
|
||||||
|
_cmd_toggle_menu,_cmd_reload_config,_cmd_toggle_grab_mouse,_cmd_toggle_game_focus,_cmd_reset,_cmd_toggle_pause,_cmd_pause,_cmd_unpause,\
|
||||||
|
_cmd_set_volume,_cmd_set_shader,_cmd_cheat_set_code,_cmd_cheat_get_code,_cmd_cheat_toggle_index,_cmd_cheat_get_code_state,_cmd_cheat_realloc,\
|
||||||
|
_cmd_cheat_get_size,_cmd_cheat_apply_cheats
|
||||||
|
|
||||||
LIBS := -s USE_ZLIB=1
|
LIBS := -s USE_ZLIB=1
|
||||||
LDFLAGS := -L. --no-heap-copy -s $(LIBS) -s TOTAL_MEMORY=$(MEMORY) -s NO_EXIT_RUNTIME=0 -s FULL_ES2=1 \
|
LDFLAGS := -L. --no-heap-copy -s $(LIBS) -s STACK_SIZE=$(STACK_SIZE) -s INITIAL_MEMORY=$(INITIAL_HEAP) \
|
||||||
-s "EXPORTED_RUNTIME_METHODS=['callMain', 'FS', 'PATH', 'ERRNO_CODES']" \
|
-s EXPORTED_RUNTIME_METHODS=callMain,FS,PATH,ERRNO_CODES,stringToNewUTF8,UTF8ToString \
|
||||||
-s ALLOW_MEMORY_GROWTH=1 -s "EXPORTED_FUNCTIONS=['_main', '_malloc', '_cmd_savefiles', '_cmd_save_state', '_cmd_load_state', '_cmd_take_screenshot']" \
|
-s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_FUNCTIONS="$(EXPORTED_FUNCTIONS)" \
|
||||||
-s MODULARIZE=1 -s EXPORT_ES6=1 -s EXPORT_NAME="libretro_$(subst -,_,$(LIBRETRO))" \
|
-s MODULARIZE=1 -s EXPORT_ES6=1 -s EXPORT_NAME="libretro_$(subst -,_,$(LIBRETRO))" \
|
||||||
-s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 \
|
--extern-pre-js emscripten/pre.js \
|
||||||
--js-library emscripten/library_errno_codes.js \
|
--js-library emscripten/library_rwebcam.js \
|
||||||
--js-library emscripten/library_rwebcam.js
|
--js-library emscripten/library_platform_emscripten.js
|
||||||
|
|
||||||
ifeq ($(HAVE_RWEBAUDIO), 1)
|
ifeq ($(HAVE_RWEBAUDIO), 1)
|
||||||
LDFLAGS += --js-library emscripten/library_rwebaudio.js
|
LDFLAGS += --js-library emscripten/library_rwebaudio.js
|
||||||
|
@ -94,11 +108,11 @@ endif
|
||||||
ifeq ($(HAVE_AL), 1)
|
ifeq ($(HAVE_AL), 1)
|
||||||
LDFLAGS += -lopenal
|
LDFLAGS += -lopenal
|
||||||
DEFINES += -DHAVE_AL
|
DEFINES += -DHAVE_AL
|
||||||
ASYNC = 1
|
override ASYNC = 1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(PTHREAD), 0)
|
ifneq ($(PTHREAD), 0)
|
||||||
LDFLAGS += -s WASM_MEM_MAX=1073741824 -pthread -s PTHREAD_POOL_SIZE=$(PTHREAD)
|
LDFLAGS += -s MAXIMUM_MEMORY=1073741824 -pthread -s PTHREAD_POOL_SIZE=$(PTHREAD)
|
||||||
CFLAGS += -pthread
|
CFLAGS += -pthread
|
||||||
HAVE_THREADS=1
|
HAVE_THREADS=1
|
||||||
else
|
else
|
||||||
|
@ -108,10 +122,26 @@ endif
|
||||||
ifeq ($(ASYNC), 1)
|
ifeq ($(ASYNC), 1)
|
||||||
LDFLAGS += -s ASYNCIFY=$(ASYNC) -s ASYNCIFY_STACK_SIZE=8192
|
LDFLAGS += -s ASYNCIFY=$(ASYNC) -s ASYNCIFY_STACK_SIZE=8192
|
||||||
ifeq ($(DEBUG), 1)
|
ifeq ($(DEBUG), 1)
|
||||||
LDFLAGS += -s ASYNCIFY_DEBUG=1 # -s ASYNCIFY_ADVISE
|
LDFLAGS += -s ASYNCIFY_DEBUG=1 # -s ASYNCIFY_ADVISE
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HAVE_OPENGLES), 1)
|
||||||
|
ifeq ($(HAVE_OPENGLES3), 1)
|
||||||
|
LDFLAGS += -s FULL_ES3=1 -s MIN_WEBGL_VERSION=2 -s MAX_WEBGL_VERSION=2
|
||||||
|
else
|
||||||
|
LDFLAGS += -s FULL_ES2=1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(GL_DEBUG), 1)
|
||||||
|
LDFLAGS += -s GL_ASSERTIONS=1 -s GL_DEBUG=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(FS_DEBUG), 1)
|
||||||
|
LDFLAGS += -s FS_DEBUG=1
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(HAVE_SDL2), 1)
|
ifeq ($(HAVE_SDL2), 1)
|
||||||
LIBS += -s USE_SDL=2
|
LIBS += -s USE_SDL=2
|
||||||
DEFINES += -DHAVE_SDL2
|
DEFINES += -DHAVE_SDL2
|
||||||
|
@ -121,12 +151,14 @@ include Makefile.common
|
||||||
|
|
||||||
CFLAGS += $(DEF_FLAGS) -Ideps -Ideps/stb
|
CFLAGS += $(DEF_FLAGS) -Ideps -Ideps/stb
|
||||||
|
|
||||||
libretro :=
|
libretro =
|
||||||
|
libretro_new =
|
||||||
|
|
||||||
ifeq ($(HAVE_STATIC_DUMMY),1)
|
ifeq ($(HAVE_STATIC_DUMMY),1)
|
||||||
DEFINES += -DHAVE_STATIC_DUMMY
|
DEFINES += -DHAVE_STATIC_DUMMY
|
||||||
else
|
else
|
||||||
libretro += libretro_emscripten.bc
|
libretro = libretro_emscripten.bc
|
||||||
|
libretro_new = libretro_emscripten.a
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(V), 1)
|
ifneq ($(V), 1)
|
||||||
|
@ -135,22 +167,16 @@ endif
|
||||||
|
|
||||||
ifeq ($(DEBUG), 1)
|
ifeq ($(DEBUG), 1)
|
||||||
LDFLAGS += -O0 -g -gsource-map -s SAFE_HEAP=1 -s STACK_OVERFLOW_CHECK=2 -s ASSERTIONS=1
|
LDFLAGS += -O0 -g -gsource-map -s SAFE_HEAP=1 -s STACK_OVERFLOW_CHECK=2 -s ASSERTIONS=1
|
||||||
CFLAGS += -O0 -g -gsource-map -s SAFE_HEAP=1 -s SAFE_HEAP_LOG=1 -s STACK_OVERFLOW_CHECK=2 -s ASSERTIONS=1
|
CFLAGS += -O0 -g -gsource-map
|
||||||
else
|
else
|
||||||
LDFLAGS += -O3 -s WASM=1
|
LDFLAGS += -O3
|
||||||
# WARNING: some optimizations can break some cores (ex: LTO breaks tyrquake)
|
# WARNING: some optimizations can break some cores (ex: LTO breaks tyrquake)
|
||||||
LDFLAGS += -s PRECISE_F32=$(PRECISE_F32)
|
|
||||||
ifeq ($(LTO), 1)
|
ifeq ($(LTO), 1)
|
||||||
LDFLAGS += --llvm-lto 3
|
LDFLAGS += -flto
|
||||||
endif
|
endif
|
||||||
CFLAGS += -O3
|
CFLAGS += -O3
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# 128 * 1024, double the usual emscripten stack size
|
|
||||||
LDFLAGS += -s STACK_SIZE=131072
|
|
||||||
|
|
||||||
LDFLAGS += --extern-pre-js emscripten/pre.js
|
|
||||||
|
|
||||||
CFLAGS += -Wall -I. -Ilibretro-common/include -Ideps/7zip -std=gnu99
|
CFLAGS += -Wall -I. -Ilibretro-common/include -Ideps/7zip -std=gnu99
|
||||||
|
|
||||||
RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ))
|
RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ))
|
||||||
|
@ -158,8 +184,9 @@ RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ))
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
$(TARGET): $(RARCH_OBJ) $(libretro)
|
$(TARGET): $(RARCH_OBJ) $(libretro)
|
||||||
@$(if $(Q), $(shell echo echo LD $@),)
|
@$(if $(libretro), mv -f $(libretro) $(libretro_new),)
|
||||||
$(Q)$(LD) -o $@ $(RARCH_OBJ) $(libretro) $(LIBS) $(LDFLAGS)
|
@$(if $(Q), $(shell echo echo "LD $@ \<obj\> $(libretro_new) $(LIBS) $(LDFLAGS)"),)
|
||||||
|
$(Q)$(LD) -o $@ $(RARCH_OBJ) $(libretro_new) $(LIBS) $(LDFLAGS)
|
||||||
|
|
||||||
$(OBJDIR)/%.o: %.c
|
$(OBJDIR)/%.o: %.c
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
|
|
|
@ -122,11 +122,13 @@ void cheat_manager_apply_cheats(void)
|
||||||
void cheat_manager_set_code(unsigned i, const char *str)
|
void cheat_manager_set_code(unsigned i, const char *str)
|
||||||
{
|
{
|
||||||
cheat_manager_t *cheat_st = &cheat_manager_state;
|
cheat_manager_t *cheat_st = &cheat_manager_state;
|
||||||
if (!cheat_st->cheats)
|
if (!cheat_st->cheats || string_is_empty(str))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!string_is_empty(str))
|
if (cheat_st->cheats[i].code)
|
||||||
strcpy(cheat_st->cheats[i].code, str);
|
free(cheat_st->cheats[i].code);
|
||||||
|
|
||||||
|
cheat_st->cheats[i].code = strdup(str);
|
||||||
|
|
||||||
cheat_st->cheats[i].state = true;
|
cheat_st->cheats[i].state = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -260,6 +260,7 @@ enum event_command
|
||||||
CMD_EVENT_PRESENCE_UPDATE,
|
CMD_EVENT_PRESENCE_UPDATE,
|
||||||
CMD_EVENT_OVERLAY_NEXT,
|
CMD_EVENT_OVERLAY_NEXT,
|
||||||
CMD_EVENT_OSK_TOGGLE,
|
CMD_EVENT_OSK_TOGGLE,
|
||||||
|
CMD_EVENT_RELOAD_CONFIG,
|
||||||
#ifdef HAVE_MICROPHONE
|
#ifdef HAVE_MICROPHONE
|
||||||
/* Stops all enabled microphones. */
|
/* Stops all enabled microphones. */
|
||||||
CMD_EVENT_MICROPHONE_STOP,
|
CMD_EVENT_MICROPHONE_STOP,
|
||||||
|
|
|
@ -764,6 +764,9 @@
|
||||||
#define DEFAULT_MENU_TICKER_SPEED 2.0f
|
#define DEFAULT_MENU_TICKER_SPEED 2.0f
|
||||||
#define DEFAULT_MENU_TICKER_SMOOTH true
|
#define DEFAULT_MENU_TICKER_SMOOTH true
|
||||||
|
|
||||||
|
/* Don't skip rendering assets based on the absence of other assets */
|
||||||
|
#define DEFAULT_MENU_IGNORE_MISSING_ASSETS false
|
||||||
|
|
||||||
#if defined(HAVE_THREADS)
|
#if defined(HAVE_THREADS)
|
||||||
#define DEFAULT_MENU_SAVESTATE_RESUME true
|
#define DEFAULT_MENU_SAVESTATE_RESUME true
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -1933,6 +1933,7 @@ static struct config_bool_setting *populate_settings_bool(
|
||||||
SETTING_BOOL("menu_dynamic_wallpaper_enable", &settings->bools.menu_dynamic_wallpaper_enable, true, DEFAULT_MENU_DYNAMIC_WALLPAPER_ENABLE, false);
|
SETTING_BOOL("menu_dynamic_wallpaper_enable", &settings->bools.menu_dynamic_wallpaper_enable, true, DEFAULT_MENU_DYNAMIC_WALLPAPER_ENABLE, false);
|
||||||
SETTING_BOOL("menu_ticker_smooth", &settings->bools.menu_ticker_smooth, true, DEFAULT_MENU_TICKER_SMOOTH, false);
|
SETTING_BOOL("menu_ticker_smooth", &settings->bools.menu_ticker_smooth, true, DEFAULT_MENU_TICKER_SMOOTH, false);
|
||||||
SETTING_BOOL("menu_scroll_fast", &settings->bools.menu_scroll_fast, true, DEFAULT_MENU_SCROLL_FAST, false);
|
SETTING_BOOL("menu_scroll_fast", &settings->bools.menu_scroll_fast, true, DEFAULT_MENU_SCROLL_FAST, false);
|
||||||
|
SETTING_BOOL("menu_ignore_missing_assets", &settings->bools.menu_ignore_missing_assets, true, DEFAULT_MENU_IGNORE_MISSING_ASSETS, false);
|
||||||
|
|
||||||
SETTING_BOOL("settings_show_drivers", &settings->bools.settings_show_drivers, true, DEFAULT_SETTINGS_SHOW_DRIVERS, false);
|
SETTING_BOOL("settings_show_drivers", &settings->bools.settings_show_drivers, true, DEFAULT_SETTINGS_SHOW_DRIVERS, false);
|
||||||
SETTING_BOOL("settings_show_video", &settings->bools.settings_show_video, true, DEFAULT_SETTINGS_SHOW_VIDEO, false);
|
SETTING_BOOL("settings_show_video", &settings->bools.settings_show_video, true, DEFAULT_SETTINGS_SHOW_VIDEO, false);
|
||||||
|
|
|
@ -832,6 +832,7 @@ typedef struct settings
|
||||||
bool menu_disable_left_analog;
|
bool menu_disable_left_analog;
|
||||||
bool menu_disable_right_analog;
|
bool menu_disable_right_analog;
|
||||||
bool menu_ticker_smooth;
|
bool menu_ticker_smooth;
|
||||||
|
bool menu_ignore_missing_assets;
|
||||||
bool settings_show_drivers;
|
bool settings_show_drivers;
|
||||||
bool settings_show_video;
|
bool settings_show_video;
|
||||||
bool settings_show_audio;
|
bool settings_show_audio;
|
||||||
|
|
|
@ -61,6 +61,7 @@ mkdir -p ../pkg/${platform}/build/rom
|
||||||
# Emscripten
|
# Emscripten
|
||||||
elif [ $PLATFORM = "emscripten" ] ; then
|
elif [ $PLATFORM = "emscripten" ] ; then
|
||||||
platform=emscripten
|
platform=emscripten
|
||||||
|
# todo: change this to a
|
||||||
EXT=bc
|
EXT=bc
|
||||||
|
|
||||||
if [ -z "$EMSCRIPTEN" ] ; then
|
if [ -z "$EMSCRIPTEN" ] ; then
|
||||||
|
@ -199,15 +200,10 @@ for f in `ls -v *_${platform}.${EXT}`; do
|
||||||
|
|
||||||
echo Buildbot: building ${name} for ${platform}
|
echo Buildbot: building ${name} for ${platform}
|
||||||
name=`echo "$f" | sed "s/\(_libretro_${platform}\|\).${EXT}$//"`
|
name=`echo "$f" | sed "s/\(_libretro_${platform}\|\).${EXT}$//"`
|
||||||
async=0
|
|
||||||
pthread=${pthread:-0}
|
|
||||||
lto=0
|
lto=0
|
||||||
whole_archive=
|
whole_archive=
|
||||||
big_stack=
|
big_stack=
|
||||||
|
|
||||||
if [ $PLATFORM = "emscripten" ]; then
|
|
||||||
async=1 #emscripten needs async to sleep
|
|
||||||
fi
|
|
||||||
if [ $name = "nxengine" ] ; then
|
if [ $name = "nxengine" ] ; then
|
||||||
echo "Applying whole archive linking..."
|
echo "Applying whole archive linking..."
|
||||||
whole_archive="WHOLE_ARCHIVE_LINK=1"
|
whole_archive="WHOLE_ARCHIVE_LINK=1"
|
||||||
|
@ -215,10 +211,31 @@ for f in `ls -v *_${platform}.${EXT}`; do
|
||||||
echo "Applying big stack..."
|
echo "Applying big stack..."
|
||||||
lto=0
|
lto=0
|
||||||
big_stack="BIG_STACK=1"
|
big_stack="BIG_STACK=1"
|
||||||
elif [ $name = "mupen64plus" ] ; then
|
fi
|
||||||
async=1
|
if [ $PLATFORM = "emscripten" ]; then
|
||||||
elif [ $name = "dosbox" ] ; then
|
|
||||||
async=0
|
async=0
|
||||||
|
pthread=${pthread:-0}
|
||||||
|
gles3=0
|
||||||
|
stack_mem=4194304
|
||||||
|
heap_mem=134217728
|
||||||
|
if [ $name = "mupen64plus_next" ] ; then
|
||||||
|
gles3=1
|
||||||
|
async=1
|
||||||
|
stack_mem=134217728
|
||||||
|
heap_mem=268435456
|
||||||
|
elif [ $name = "parallel_n64" ] ; then
|
||||||
|
gles3=1
|
||||||
|
async=1
|
||||||
|
elif [ $name = "mednafen_psx" ] ; then
|
||||||
|
heap_mem=536870912
|
||||||
|
elif [ $name = "mednafen_psx_hw" ] ; then
|
||||||
|
gles3=1
|
||||||
|
heap_mem=536870912
|
||||||
|
elif [ $name = "dosbox" ] ; then
|
||||||
|
async=1
|
||||||
|
elif [ $name = "scummvm" ] ; then
|
||||||
|
async=1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
echo "-- Building core: $name --"
|
echo "-- Building core: $name --"
|
||||||
if [ $PLATFORM = "unix" ]; then
|
if [ $PLATFORM = "unix" ]; then
|
||||||
|
@ -227,15 +244,21 @@ for f in `ls -v *_${platform}.${EXT}`; do
|
||||||
cp -f "$f" ../libretro_${platform}.${EXT}
|
cp -f "$f" ../libretro_${platform}.${EXT}
|
||||||
fi
|
fi
|
||||||
echo NAME: $name
|
echo NAME: $name
|
||||||
echo ASYNC: $async
|
|
||||||
echo LTO: $lto
|
echo LTO: $lto
|
||||||
|
if [ $PLATFORM = "emscripten" ]; then
|
||||||
|
echo ASYNC: $async
|
||||||
|
echo PTHREAD: $pthread
|
||||||
|
echo GLES3: $gles3
|
||||||
|
echo STACK_MEMORY: $stack_mem
|
||||||
|
echo HEAP_MEMORY: $heap_mem
|
||||||
|
fi
|
||||||
|
|
||||||
# Do cleanup if this is a big stack core
|
# Do cleanup if this is a big stack core
|
||||||
if [ "$big_stack" = "BIG_STACK=1" ] ; then
|
if [ "$big_stack" = "BIG_STACK=1" ] ; then
|
||||||
if [ $MAKEFILE_GRIFFIN = "yes" ]; then
|
if [ $MAKEFILE_GRIFFIN = "yes" ]; then
|
||||||
make -C ../ -f Makefile.griffin platform=${platform} clean || exit 1
|
make -C ../ -f Makefile.griffin platform=${platform} clean || exit 1
|
||||||
elif [ $PLATFORM = "emscripten" ]; then
|
elif [ $PLATFORM = "emscripten" ]; then
|
||||||
make -C ../ -f Makefile.emscripten PTHREAD=$pthread ASYNC=$async LTO=$lto -j7 clean || exit 1
|
make -C ../ -f Makefile.emscripten PTHREAD=$pthread ASYNC=$async LTO=$lto HAVE_OPENGLES3=$gles3 -j7 clean || exit 1
|
||||||
elif [ $PLATFORM = "unix" ]; then
|
elif [ $PLATFORM = "unix" ]; then
|
||||||
make -C ../ -f Makefile LINK=g++ LTO=$lto -j7 clean || exit 1
|
make -C ../ -f Makefile LINK=g++ LTO=$lto -j7 clean || exit 1
|
||||||
else
|
else
|
||||||
|
@ -247,8 +270,8 @@ for f in `ls -v *_${platform}.${EXT}`; do
|
||||||
if [ $MAKEFILE_GRIFFIN = "yes" ]; then
|
if [ $MAKEFILE_GRIFFIN = "yes" ]; then
|
||||||
make -C ../ -f Makefile.griffin $OPTS platform=${platform} $whole_archive $big_stack -j3 || exit 1
|
make -C ../ -f Makefile.griffin $OPTS platform=${platform} $whole_archive $big_stack -j3 || exit 1
|
||||||
elif [ $PLATFORM = "emscripten" ]; then
|
elif [ $PLATFORM = "emscripten" ]; then
|
||||||
echo "BUILD COMMAND: make -C ../ -f Makefile.emscripten PTHREAD=$pthread ASYNC=$async LTO=$lto -j7 LIBRETRO=${name} TARGET=${name}_libretro.js"
|
echo "BUILD COMMAND: make -C ../ -f Makefile.emscripten PTHREAD=$pthread ASYNC=$async LTO=$lto HAVE_OPENGLES3=$gles3 STACK_SIZE=$stack_mem INITIAL_HEAP=$heap_mem -j7 LIBRETRO=${name} TARGET=${name}_libretro.js"
|
||||||
make -C ../ -f Makefile.emscripten $OPTS PTHREAD=$pthread ASYNC=$async LTO=$lto -j7 LIBRETRO=${name} TARGET=${name}_libretro.js || exit 1
|
make -C ../ -f Makefile.emscripten $OPTS PTHREAD=$pthread ASYNC=$async LTO=$lto HAVE_OPENGLES3=$gles3 STACK_SIZE=$stack_mem INITIAL_HEAP=$heap_mem -j7 LIBRETRO=${name} TARGET=${name}_libretro.js || exit 1
|
||||||
elif [ $PLATFORM = "unix" ]; then
|
elif [ $PLATFORM = "unix" ]; then
|
||||||
make -C ../ -f Makefile LINK=g++ $whole_archive $big_stack -j3 || exit 1
|
make -C ../ -f Makefile LINK=g++ $whole_archive $big_stack -j3 || exit 1
|
||||||
elif [ $PLATFORM = "ctr" ]; then
|
elif [ $PLATFORM = "ctr" ]; then
|
||||||
|
@ -318,6 +341,9 @@ for f in `ls -v *_${platform}.${EXT}`; do
|
||||||
if [ $pthread != 0 ] ; then
|
if [ $pthread != 0 ] ; then
|
||||||
mv -f ../${name}_libretro.worker.js ../pkg/emscripten/${name}_libretro.worker.js
|
mv -f ../${name}_libretro.worker.js ../pkg/emscripten/${name}_libretro.worker.js
|
||||||
fi
|
fi
|
||||||
|
if [ -f ../${name}_libretro.wasm.map ] ; then
|
||||||
|
mv -f ../${name}_libretro.wasm.map ../pkg/emscripten/${name}_libretro.wasm.map
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Do manual executable step
|
# Do manual executable step
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
//"use strict";
|
|
||||||
|
|
||||||
// HACK: This is a dummy library that forces ERRNO_CODES to be used, so it's not optimized away.
|
|
||||||
// Needed for BrowserFS.
|
|
||||||
|
|
||||||
var LibraryErrnoCodes = {
|
|
||||||
dummyErrnoCodes__deps: ['$ERRNO_CODES'],
|
|
||||||
dummyErrnoCodes: function() {
|
|
||||||
if (!ERRNO_CODES) {
|
|
||||||
console.error("ERRNO_CODES not imported!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
mergeInto(LibraryManager.library, LibraryErrnoCodes);
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
//"use strict";
|
||||||
|
|
||||||
|
var LibraryPlatformEmscripten = {
|
||||||
|
$RPE: {
|
||||||
|
powerState: {
|
||||||
|
supported: false,
|
||||||
|
dischargeTime: 0,
|
||||||
|
level: 0,
|
||||||
|
charging: false
|
||||||
|
},
|
||||||
|
powerStateChange: function(e) {
|
||||||
|
RPE.powerState.dischargeTime = Number.isFinite(e.target.dischargingTime) ? e.target.dischargingTime : 0x7FFFFFFF;
|
||||||
|
RPE.powerState.level = e.target.level;
|
||||||
|
RPE.powerState.charging = e.target.charging;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
PlatformEmscriptenWatchCanvasSize: function() {
|
||||||
|
RPE.observer = new ResizeObserver(function(e) {
|
||||||
|
var width, height;
|
||||||
|
var entry = e.find(i => i.target == Module.canvas);
|
||||||
|
if (!entry) return;
|
||||||
|
if (entry.devicePixelContentBoxSize) {
|
||||||
|
width = entry.devicePixelContentBoxSize[0].inlineSize;
|
||||||
|
height = entry.devicePixelContentBoxSize[0].blockSize;
|
||||||
|
} else {
|
||||||
|
width = Math.round(entry.contentRect.width * window.devicePixelRatio);
|
||||||
|
height = Math.round(entry.contentRect.height * window.devicePixelRatio);
|
||||||
|
}
|
||||||
|
Module.setCanvasSize(width, height);
|
||||||
|
Module.print("Setting real canvas size: " + width + " x " + height);
|
||||||
|
});
|
||||||
|
RPE.observer.observe(Module.canvas);
|
||||||
|
window.addEventListener("resize", function(e) {
|
||||||
|
RPE.observer.unobserve(Module.canvas);
|
||||||
|
RPE.observer.observe(Module.canvas);
|
||||||
|
}, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
PlatformEmscriptenPowerStateInit: function() {
|
||||||
|
if (!navigator.getBattery) return;
|
||||||
|
navigator.getBattery().then(function(battery) {
|
||||||
|
battery.addEventListener("chargingchange", RPE.powerStateChange);
|
||||||
|
battery.addEventListener("levelchange", RPE.powerStateChange);
|
||||||
|
RPE.powerStateChange({target: battery});
|
||||||
|
RPE.powerState.supported = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
PlatformEmscriptenPowerStateGetSupported: function() {
|
||||||
|
return RPE.powerState.supported;
|
||||||
|
},
|
||||||
|
|
||||||
|
PlatformEmscriptenPowerStateGetDischargeTime: function() {
|
||||||
|
return RPE.powerState.dischargeTime;
|
||||||
|
},
|
||||||
|
|
||||||
|
PlatformEmscriptenPowerStateGetLevel: function() {
|
||||||
|
return RPE.powerState.level;
|
||||||
|
},
|
||||||
|
|
||||||
|
PlatformEmscriptenPowerStateGetCharging: function() {
|
||||||
|
return RPE.powerState.charging;
|
||||||
|
},
|
||||||
|
|
||||||
|
PlatformEmscriptenGetTotalMem: function() {
|
||||||
|
if (!performance.memory) return 0;
|
||||||
|
return performance.memory.jsHeapSizeLimit || 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
PlatformEmscriptenGetFreeMem: function() {
|
||||||
|
if (!performance.memory) return 0;
|
||||||
|
return (performance.memory.jsHeapSizeLimit || 0) - (performance.memory.usedJSHeapSize || 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
autoAddDeps(LibraryPlatformEmscripten, '$RPE');
|
||||||
|
mergeInto(LibraryManager.library, LibraryPlatformEmscripten);
|
|
@ -17,18 +17,13 @@ var LibraryRWebCam = {
|
||||||
RWebCamInit__deps: ['malloc'],
|
RWebCamInit__deps: ['malloc'],
|
||||||
RWebCamInit: function(caps1, caps2, width, height) {
|
RWebCamInit: function(caps1, caps2, width, height) {
|
||||||
if (!navigator) return 0;
|
if (!navigator) return 0;
|
||||||
|
if (!navigator.mediaDevices.getUserMedia) return 0;
|
||||||
navigator.getMedia = navigator.getUserMedia ||
|
|
||||||
navigator.webkitGetUserMedia ||
|
|
||||||
navigator.mozGetUserMedia ||
|
|
||||||
navigator.msGetUserMedia;
|
|
||||||
|
|
||||||
if (!navigator.getMedia) return 0;
|
|
||||||
|
|
||||||
var c = ++RWC.counter;
|
var c = ++RWC.counter;
|
||||||
|
|
||||||
RWC.contexts[c] = [];
|
RWC.contexts[c] = [];
|
||||||
RWC.contexts[c].videoElement = document.createElement("video");
|
RWC.contexts[c].videoElement = document.createElement("video");
|
||||||
|
RWC.contexts[c].videoElement.classList.add("retroarchWebcamVideo");
|
||||||
if (width !== 0 && height !== 0) {
|
if (width !== 0 && height !== 0) {
|
||||||
RWC.contexts[c].videoElement.width = width;
|
RWC.contexts[c].videoElement.width = width;
|
||||||
RWC.contexts[c].videoElement.height = height;
|
RWC.contexts[c].videoElement.height = height;
|
||||||
|
@ -37,11 +32,11 @@ var LibraryRWebCam = {
|
||||||
RWC.contexts[c].glTex = caps1 & (1 << RWC.RETRO_CAMERA_BUFFER_OPENGL_TEXTURE);
|
RWC.contexts[c].glTex = caps1 & (1 << RWC.RETRO_CAMERA_BUFFER_OPENGL_TEXTURE);
|
||||||
RWC.contexts[c].rawFb = caps1 & (1 << RWC.RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER);
|
RWC.contexts[c].rawFb = caps1 & (1 << RWC.RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER);
|
||||||
|
|
||||||
navigator.getMedia({video: true, audio: false}, function(stream) {
|
navigator.mediaDevices.getUserMedia({video: true, audio: false}).then(function(stream) {
|
||||||
RWC.contexts[c].videoElement.autoplay = true;
|
RWC.contexts[c].videoElement.autoplay = true;
|
||||||
RWC.contexts[c].videoElement.src = URL.createObjectURL(stream);
|
RWC.contexts[c].videoElement.srcObject = stream;
|
||||||
RWC.contexts[c].runMode = 2;
|
RWC.contexts[c].runMode = 2;
|
||||||
}, function (err) {
|
}).catch(function (err) {
|
||||||
console.log("webcam request failed", err);
|
console.log("webcam request failed", err);
|
||||||
RWC.runMode = 0;
|
RWC.runMode = 0;
|
||||||
});
|
});
|
||||||
|
@ -53,7 +48,6 @@ var LibraryRWebCam = {
|
||||||
|
|
||||||
RWebCamFree: function(data) {
|
RWebCamFree: function(data) {
|
||||||
RWC.contexts[data].videoElement.pause();
|
RWC.contexts[data].videoElement.pause();
|
||||||
URL.revokeObjectURL(RWC.contexts[data].videoElement.src);
|
|
||||||
RWC.contexts[data].videoElement = null;
|
RWC.contexts[data].videoElement = null;
|
||||||
RWC.contexts[data] = null;
|
RWC.contexts[data] = null;
|
||||||
},
|
},
|
||||||
|
@ -81,6 +75,7 @@ var LibraryRWebCam = {
|
||||||
}
|
}
|
||||||
if (RWC.contexts[data].rawFb) {
|
if (RWC.contexts[data].rawFb) {
|
||||||
RWC.contexts[data].rawFbCanvas = document.createElement("canvas");
|
RWC.contexts[data].rawFbCanvas = document.createElement("canvas");
|
||||||
|
RWC.contexts[data].rawFbCanvas.classList.add("retroarchWebcamCanvas");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,9 +46,22 @@
|
||||||
#include "../../retroarch.h"
|
#include "../../retroarch.h"
|
||||||
#include "../../verbosity.h"
|
#include "../../verbosity.h"
|
||||||
#include "../../tasks/tasks_internal.h"
|
#include "../../tasks/tasks_internal.h"
|
||||||
|
#include "../../cheat_manager.h"
|
||||||
|
#include "../../audio/audio_driver.h"
|
||||||
|
|
||||||
void dummyErrnoCodes(void);
|
|
||||||
void emscripten_mainloop(void);
|
void emscripten_mainloop(void);
|
||||||
|
void PlatformEmscriptenWatchCanvasSize(void);
|
||||||
|
void PlatformEmscriptenPowerStateInit(void);
|
||||||
|
bool PlatformEmscriptenPowerStateGetSupported(void);
|
||||||
|
int PlatformEmscriptenPowerStateGetDischargeTime(void);
|
||||||
|
float PlatformEmscriptenPowerStateGetLevel(void);
|
||||||
|
bool PlatformEmscriptenPowerStateGetCharging(void);
|
||||||
|
uint64_t PlatformEmscriptenGetTotalMem(void);
|
||||||
|
uint64_t PlatformEmscriptenGetFreeMem(void);
|
||||||
|
|
||||||
|
//// begin exported functions
|
||||||
|
|
||||||
|
// saves and states
|
||||||
|
|
||||||
void cmd_savefiles(void)
|
void cmd_savefiles(void)
|
||||||
{
|
{
|
||||||
|
@ -65,11 +78,113 @@ void cmd_load_state(void)
|
||||||
command_event(CMD_EVENT_LOAD_STATE, NULL);
|
command_event(CMD_EVENT_LOAD_STATE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cmd_undo_save_state(void)
|
||||||
|
{
|
||||||
|
command_event(CMD_EVENT_UNDO_SAVE_STATE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_undo_load_state(void)
|
||||||
|
{
|
||||||
|
command_event(CMD_EVENT_UNDO_LOAD_STATE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// misc
|
||||||
|
|
||||||
void cmd_take_screenshot(void)
|
void cmd_take_screenshot(void)
|
||||||
{
|
{
|
||||||
command_event(CMD_EVENT_TAKE_SCREENSHOT, NULL);
|
command_event(CMD_EVENT_TAKE_SCREENSHOT, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cmd_toggle_menu(void)
|
||||||
|
{
|
||||||
|
command_event(CMD_EVENT_MENU_TOGGLE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_reload_config(void)
|
||||||
|
{
|
||||||
|
command_event(CMD_EVENT_RELOAD_CONFIG, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_toggle_grab_mouse(void)
|
||||||
|
{
|
||||||
|
command_event(CMD_EVENT_GRAB_MOUSE_TOGGLE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_toggle_game_focus(void)
|
||||||
|
{
|
||||||
|
command_event(CMD_EVENT_GAME_FOCUS_TOGGLE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_reset(void)
|
||||||
|
{
|
||||||
|
command_event(CMD_EVENT_RESET, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_toggle_pause(void)
|
||||||
|
{
|
||||||
|
command_event(CMD_EVENT_PAUSE_TOGGLE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_pause(void)
|
||||||
|
{
|
||||||
|
command_event(CMD_EVENT_PAUSE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_unpause(void)
|
||||||
|
{
|
||||||
|
command_event(CMD_EVENT_UNPAUSE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_set_volume(float volume) {
|
||||||
|
audio_set_float(AUDIO_ACTION_VOLUME_GAIN, volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
||||||
|
bool cmd_set_shader(const char *path)
|
||||||
|
{
|
||||||
|
return command_set_shader(NULL, path);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// cheats
|
||||||
|
|
||||||
|
void cmd_cheat_set_code(unsigned index, const char *str)
|
||||||
|
{
|
||||||
|
cheat_manager_set_code(index, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *cmd_cheat_get_code(unsigned index)
|
||||||
|
{
|
||||||
|
return cheat_manager_get_code(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_cheat_toggle_index(bool apply_cheats_after_toggle, unsigned index)
|
||||||
|
{
|
||||||
|
cheat_manager_toggle_index(apply_cheats_after_toggle, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cmd_cheat_get_code_state(unsigned index)
|
||||||
|
{
|
||||||
|
return cheat_manager_get_code_state(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cmd_cheat_realloc(unsigned new_size)
|
||||||
|
{
|
||||||
|
return cheat_manager_realloc(new_size, CHEAT_HANDLER_TYPE_EMU);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned cmd_cheat_get_size(void)
|
||||||
|
{
|
||||||
|
return cheat_manager_get_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_cheat_apply_cheats(void)
|
||||||
|
{
|
||||||
|
cheat_manager_apply_cheats();
|
||||||
|
}
|
||||||
|
|
||||||
|
//// end exported functions
|
||||||
|
|
||||||
static void frontend_emscripten_get_env(int *argc, char *argv[],
|
static void frontend_emscripten_get_env(int *argc, char *argv[],
|
||||||
void *args, void *params_data)
|
void *args, void *params_data)
|
||||||
{
|
{
|
||||||
|
@ -154,16 +269,45 @@ static void frontend_emscripten_get_env(int *argc, char *argv[],
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum frontend_powerstate frontend_emscripten_get_powerstate(int *seconds, int *percent)
|
||||||
|
{
|
||||||
|
enum frontend_powerstate ret = FRONTEND_POWERSTATE_NONE;
|
||||||
|
|
||||||
|
if (!PlatformEmscriptenPowerStateGetSupported())
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (!PlatformEmscriptenPowerStateGetCharging())
|
||||||
|
ret = FRONTEND_POWERSTATE_ON_POWER_SOURCE;
|
||||||
|
else if (PlatformEmscriptenPowerStateGetLevel() == 1)
|
||||||
|
ret = FRONTEND_POWERSTATE_CHARGED;
|
||||||
|
else
|
||||||
|
ret = FRONTEND_POWERSTATE_CHARGING;
|
||||||
|
|
||||||
|
*seconds = PlatformEmscriptenPowerStateGetDischargeTime();
|
||||||
|
*percent = (int)(PlatformEmscriptenPowerStateGetLevel() * 100);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t frontend_emscripten_get_total_mem(void)
|
||||||
|
{
|
||||||
|
return PlatformEmscriptenGetTotalMem();
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t frontend_emscripten_get_free_mem(void)
|
||||||
|
{
|
||||||
|
return PlatformEmscriptenGetFreeMem();
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
dummyErrnoCodes();
|
PlatformEmscriptenWatchCanvasSize();
|
||||||
|
PlatformEmscriptenPowerStateInit();
|
||||||
|
|
||||||
EM_ASM({
|
EM_ASM({
|
||||||
specialHTMLTargets["!canvas"] = Module.canvas;
|
specialHTMLTargets["!canvas"] = Module.canvas;
|
||||||
});
|
});
|
||||||
|
|
||||||
emscripten_set_canvas_element_size("!canvas", 800, 600);
|
|
||||||
emscripten_set_element_css_size("!canvas", 800.0, 600.0);
|
|
||||||
emscripten_set_main_loop(emscripten_mainloop, 0, 0);
|
emscripten_set_main_loop(emscripten_mainloop, 0, 0);
|
||||||
rarch_main(argc, argv, NULL);
|
rarch_main(argc, argv, NULL);
|
||||||
|
|
||||||
|
@ -171,39 +315,39 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
frontend_ctx_driver_t frontend_ctx_emscripten = {
|
frontend_ctx_driver_t frontend_ctx_emscripten = {
|
||||||
frontend_emscripten_get_env, /* environment_get */
|
frontend_emscripten_get_env, /* environment_get */
|
||||||
NULL, /* init */
|
NULL, /* init */
|
||||||
NULL, /* deinit */
|
NULL, /* deinit */
|
||||||
NULL, /* exitspawn */
|
NULL, /* exitspawn */
|
||||||
NULL, /* process_args */
|
NULL, /* process_args */
|
||||||
NULL, /* exec */
|
NULL, /* exec */
|
||||||
NULL, /* set_fork */
|
NULL, /* set_fork */
|
||||||
NULL, /* shutdown */
|
NULL, /* shutdown */
|
||||||
NULL, /* get_name */
|
NULL, /* get_name */
|
||||||
NULL, /* get_os */
|
NULL, /* get_os */
|
||||||
NULL, /* get_rating */
|
NULL, /* get_rating */
|
||||||
NULL, /* load_content */
|
NULL, /* load_content */
|
||||||
NULL, /* get_architecture */
|
NULL, /* get_architecture */
|
||||||
NULL, /* get_powerstate */
|
frontend_emscripten_get_powerstate, /* get_powerstate */
|
||||||
NULL, /* parse_drive_list */
|
NULL, /* parse_drive_list */
|
||||||
NULL, /* get_total_mem */
|
frontend_emscripten_get_total_mem, /* get_total_mem */
|
||||||
NULL, /* get_free_mem */
|
frontend_emscripten_get_free_mem, /* get_free_mem */
|
||||||
NULL, /* install_sighandlers */
|
NULL, /* install_sighandlers */
|
||||||
NULL, /* get_signal_handler_state */
|
NULL, /* get_signal_handler_state */
|
||||||
NULL, /* set_signal_handler_state */
|
NULL, /* set_signal_handler_state */
|
||||||
NULL, /* destroy_signal_handler_state */
|
NULL, /* destroy_signal_handler_state */
|
||||||
NULL, /* attach_console */
|
NULL, /* attach_console */
|
||||||
NULL, /* detach_console */
|
NULL, /* detach_console */
|
||||||
NULL, /* get_lakka_version */
|
NULL, /* get_lakka_version */
|
||||||
NULL, /* set_screen_brightness */
|
NULL, /* set_screen_brightness */
|
||||||
NULL, /* watch_path_for_changes */
|
NULL, /* watch_path_for_changes */
|
||||||
NULL, /* check_for_path_changes */
|
NULL, /* check_for_path_changes */
|
||||||
NULL, /* set_sustained_performance_mode */
|
NULL, /* set_sustained_performance_mode */
|
||||||
NULL, /* get_cpu_model_name */
|
NULL, /* get_cpu_model_name */
|
||||||
NULL, /* get_user_language */
|
NULL, /* get_user_language */
|
||||||
NULL, /* is_narrator_running */
|
NULL, /* is_narrator_running */
|
||||||
NULL, /* accessibility_speak */
|
NULL, /* accessibility_speak */
|
||||||
NULL, /* set_gamemode */
|
NULL, /* set_gamemode */
|
||||||
"emscripten", /* ident */
|
"emscripten", /* ident */
|
||||||
NULL /* get_video_driver */
|
NULL /* get_video_driver */
|
||||||
};
|
};
|
||||||
|
|
|
@ -185,9 +185,8 @@ enum gl2_renderchain_flags
|
||||||
{
|
{
|
||||||
GL2_CHAIN_FLAG_EGL_IMAGES = (1 << 0),
|
GL2_CHAIN_FLAG_EGL_IMAGES = (1 << 0),
|
||||||
GL2_CHAIN_FLAG_HAS_FP_FBO = (1 << 1),
|
GL2_CHAIN_FLAG_HAS_FP_FBO = (1 << 1),
|
||||||
GL2_CHAIN_FLAG_HAS_SRGB_FBO_GLES3 = (1 << 2),
|
GL2_CHAIN_FLAG_HAS_SRGB_FBO = (1 << 2),
|
||||||
GL2_CHAIN_FLAG_HAS_SRGB_FBO = (1 << 3),
|
GL2_CHAIN_FLAG_HW_RENDER_DEPTH_INIT = (1 << 3)
|
||||||
GL2_CHAIN_FLAG_HW_RENDER_DEPTH_INIT = (1 << 4)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct video_shader_ctx_scale
|
typedef struct video_shader_ctx_scale
|
||||||
|
@ -1616,9 +1615,7 @@ static void gl2_create_fbo_texture(gl2_t *gl,
|
||||||
if (video_ctx_scaling)
|
if (video_ctx_scaling)
|
||||||
video_smooth = false;
|
video_smooth = false;
|
||||||
#endif
|
#endif
|
||||||
#ifndef HAVE_OPENGLES
|
|
||||||
bool force_srgb_disable = settings->bools.video_force_srgb_disable;
|
bool force_srgb_disable = settings->bools.video_force_srgb_disable;
|
||||||
#endif
|
|
||||||
GLuint base_filt = video_smooth ? GL_LINEAR : GL_NEAREST;
|
GLuint base_filt = video_smooth ? GL_LINEAR : GL_NEAREST;
|
||||||
GLuint base_mip_filt = video_smooth ?
|
GLuint base_mip_filt = video_smooth ?
|
||||||
GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST;
|
GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST;
|
||||||
|
@ -1650,19 +1647,21 @@ static void gl2_create_fbo_texture(gl2_t *gl,
|
||||||
RARCH_ERR("[GL]: Floating-point FBO was requested, but is not supported. Falling back to UNORM. Result may band/clip/etc.!\n");
|
RARCH_ERR("[GL]: Floating-point FBO was requested, but is not supported. Falling back to UNORM. Result may band/clip/etc.!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(HAVE_OPENGLES2)
|
|
||||||
if ( fp_fbo
|
if ( fp_fbo
|
||||||
&& (chain->flags & GL2_CHAIN_FLAG_HAS_FP_FBO))
|
&& (chain->flags & GL2_CHAIN_FLAG_HAS_FP_FBO))
|
||||||
{
|
{
|
||||||
RARCH_LOG("[GL]: FBO pass #%d is floating-point.\n", i);
|
RARCH_LOG("[GL]: FBO pass #%d is floating-point.\n", i);
|
||||||
gl2_load_texture_image(GL_TEXTURE_2D, 0, GL_RGBA32F,
|
gl2_load_texture_image(GL_TEXTURE_2D, 0,
|
||||||
|
#ifdef HAVE_OPENGLES2
|
||||||
|
GL_RGBA,
|
||||||
|
#else
|
||||||
|
GL_RGBA32F,
|
||||||
|
#endif
|
||||||
gl->fbo_rect[i].width, gl->fbo_rect[i].height,
|
gl->fbo_rect[i].width, gl->fbo_rect[i].height,
|
||||||
0, GL_RGBA, GL_FLOAT, NULL);
|
0, GL_RGBA, GL_FLOAT, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
#ifndef HAVE_OPENGLES
|
|
||||||
bool srgb_fbo = (chain->fbo_scale[i].flags & FBO_SCALE_FLAG_SRGB_FBO) ? true : false;
|
bool srgb_fbo = (chain->fbo_scale[i].flags & FBO_SCALE_FLAG_SRGB_FBO) ? true : false;
|
||||||
|
|
||||||
if (!fp_fbo && srgb_fbo)
|
if (!fp_fbo && srgb_fbo)
|
||||||
|
@ -1678,27 +1677,23 @@ static void gl2_create_fbo_texture(gl2_t *gl,
|
||||||
&& (chain->flags & GL2_CHAIN_FLAG_HAS_SRGB_FBO))
|
&& (chain->flags & GL2_CHAIN_FLAG_HAS_SRGB_FBO))
|
||||||
{
|
{
|
||||||
RARCH_LOG("[GL]: FBO pass #%d is sRGB.\n", i);
|
RARCH_LOG("[GL]: FBO pass #%d is sRGB.\n", i);
|
||||||
|
gl2_load_texture_image(GL_TEXTURE_2D, 0,
|
||||||
#ifdef HAVE_OPENGLES2
|
#ifdef HAVE_OPENGLES2
|
||||||
/* EXT defines are same as core GLES3 defines,
|
GL_SRGB_ALPHA_EXT,
|
||||||
* but GLES3 variant requires different arguments. */
|
|
||||||
glTexImage2D(GL_TEXTURE_2D,
|
|
||||||
0, GL_SRGB_ALPHA_EXT,
|
|
||||||
gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0,
|
|
||||||
(chain->flags & GL2_CHAIN_FLAG_HAS_SRGB_FBO_GLES3)
|
|
||||||
? GL_RGBA
|
|
||||||
: GL_SRGB_ALPHA_EXT,
|
|
||||||
GL_UNSIGNED_BYTE, NULL);
|
|
||||||
#else
|
#else
|
||||||
gl2_load_texture_image(GL_TEXTURE_2D,
|
GL_SRGB8_ALPHA8,
|
||||||
0, GL_SRGB8_ALPHA8,
|
|
||||||
gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0,
|
|
||||||
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
||||||
#endif
|
#endif
|
||||||
|
gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0,
|
||||||
|
#ifdef HAVE_OPENGLES2
|
||||||
|
GL_SRGB_ALPHA_EXT,
|
||||||
|
#else
|
||||||
|
GL_RGBA,
|
||||||
|
#endif
|
||||||
|
GL_UNSIGNED_BYTE, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
#if defined(HAVE_OPENGLES2)
|
#if defined(HAVE_OPENGLES)
|
||||||
glTexImage2D(GL_TEXTURE_2D,
|
glTexImage2D(GL_TEXTURE_2D,
|
||||||
0, GL_RGBA,
|
0, GL_RGBA,
|
||||||
gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0,
|
gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0,
|
||||||
|
@ -2479,11 +2474,6 @@ static void gl2_renderchain_resolve_extensions(gl2_t *gl,
|
||||||
chain->flags |= GL2_CHAIN_FLAG_HAS_FP_FBO;
|
chain->flags |= GL2_CHAIN_FLAG_HAS_FP_FBO;
|
||||||
else
|
else
|
||||||
chain->flags &= ~GL2_CHAIN_FLAG_HAS_FP_FBO;
|
chain->flags &= ~GL2_CHAIN_FLAG_HAS_FP_FBO;
|
||||||
/* GLES3 has unpack_subimage and sRGB in core. */
|
|
||||||
if (gl_check_capability(GL_CAPS_SRGB_FBO_ES3))
|
|
||||||
chain->flags |= GL2_CHAIN_FLAG_HAS_SRGB_FBO_GLES3;
|
|
||||||
else
|
|
||||||
chain->flags &= ~GL2_CHAIN_FLAG_HAS_SRGB_FBO_GLES3;
|
|
||||||
|
|
||||||
if (!force_srgb_disable)
|
if (!force_srgb_disable)
|
||||||
{
|
{
|
||||||
|
@ -3892,7 +3882,6 @@ static bool gl2_resolve_extensions(gl2_t *gl, const char *context_ident, const v
|
||||||
RARCH_WARN("[GL]: GLES implementation does not have BGRA8888 extension.\n"
|
RARCH_WARN("[GL]: GLES implementation does not have BGRA8888 extension.\n"
|
||||||
"[GL]: 32-bit path will require conversion.\n");
|
"[GL]: 32-bit path will require conversion.\n");
|
||||||
}
|
}
|
||||||
/* TODO/FIXME - No extensions for float FBO currently. */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef GL_DEBUG
|
#ifdef GL_DEBUG
|
||||||
|
|
|
@ -38,8 +38,6 @@ typedef struct
|
||||||
#ifdef HAVE_EGL
|
#ifdef HAVE_EGL
|
||||||
egl_ctx_data_t egl;
|
egl_ctx_data_t egl;
|
||||||
#endif
|
#endif
|
||||||
int initial_width;
|
|
||||||
int initial_height;
|
|
||||||
unsigned fb_width;
|
unsigned fb_width;
|
||||||
unsigned fb_height;
|
unsigned fb_height;
|
||||||
} emscripten_ctx_data_t;
|
} emscripten_ctx_data_t;
|
||||||
|
@ -54,76 +52,29 @@ static void gfx_ctx_emscripten_swap_interval(void *data, int interval)
|
||||||
|
|
||||||
static void gfx_ctx_emscripten_get_canvas_size(int *width, int *height)
|
static void gfx_ctx_emscripten_get_canvas_size(int *width, int *height)
|
||||||
{
|
{
|
||||||
EmscriptenFullscreenChangeEvent fullscreen_status;
|
EMSCRIPTEN_RESULT r = emscripten_get_canvas_element_size("!canvas", width, height);
|
||||||
bool is_fullscreen = false;
|
|
||||||
EMSCRIPTEN_RESULT r = emscripten_get_fullscreen_status(&fullscreen_status);
|
|
||||||
|
|
||||||
if (r == EMSCRIPTEN_RESULT_SUCCESS)
|
if (r != EMSCRIPTEN_RESULT_SUCCESS)
|
||||||
{
|
{
|
||||||
if (fullscreen_status.isFullscreen)
|
*width = 800;
|
||||||
{
|
*height = 600;
|
||||||
is_fullscreen = true;
|
RARCH_ERR("[EMSCRIPTEN/EGL]: Could not get screen dimensions: %d\n",r);
|
||||||
*width = fullscreen_status.screenWidth;
|
|
||||||
*height = fullscreen_status.screenHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_fullscreen)
|
|
||||||
{
|
|
||||||
r = emscripten_get_canvas_element_size("!canvas", width, height);
|
|
||||||
|
|
||||||
if (r != EMSCRIPTEN_RESULT_SUCCESS)
|
|
||||||
{
|
|
||||||
*width = 800;
|
|
||||||
*height = 600;
|
|
||||||
RARCH_ERR("[EMSCRIPTEN/EGL]: Could not get screen dimensions: %d\n",r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_emscripten_check_window(void *data, bool *quit,
|
static void gfx_ctx_emscripten_check_window(void *data, bool *quit,
|
||||||
bool *resize, unsigned *width, unsigned *height)
|
bool *resize, unsigned *width, unsigned *height)
|
||||||
{
|
{
|
||||||
EMSCRIPTEN_RESULT r;
|
|
||||||
int input_width;
|
int input_width;
|
||||||
int input_height;
|
int input_height;
|
||||||
emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data;
|
emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data;
|
||||||
|
|
||||||
gfx_ctx_emscripten_get_canvas_size(&input_width, &input_height);
|
gfx_ctx_emscripten_get_canvas_size(&input_width, &input_height);
|
||||||
|
|
||||||
if (input_width == 0 || input_height == 0)
|
*width = emscripten->fb_width = (unsigned)input_width;
|
||||||
{
|
*height = emscripten->fb_height = (unsigned)input_height;
|
||||||
input_width = emscripten->initial_width;
|
*quit = false;
|
||||||
input_height = emscripten->initial_height;
|
*resize = false;
|
||||||
emscripten->fb_width = emscripten->fb_height = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*width = (unsigned)input_width;
|
|
||||||
*height = (unsigned)input_height;
|
|
||||||
*resize = false;
|
|
||||||
|
|
||||||
if ( (input_width != emscripten->fb_width)
|
|
||||||
|| (input_height != emscripten->fb_height))
|
|
||||||
{
|
|
||||||
r = emscripten_set_canvas_element_size("!canvas",
|
|
||||||
input_width, input_height);
|
|
||||||
|
|
||||||
if (r != EMSCRIPTEN_RESULT_SUCCESS)
|
|
||||||
RARCH_ERR("[EMSCRIPTEN/EGL]: error resizing canvas: %d\n", r);
|
|
||||||
|
|
||||||
/* fix Module.requestFullscreen messing with the canvas size */
|
|
||||||
r = emscripten_set_element_css_size("!canvas",
|
|
||||||
(double)input_width, (double)input_height);
|
|
||||||
|
|
||||||
if (r != EMSCRIPTEN_RESULT_SUCCESS)
|
|
||||||
RARCH_ERR("[EMSCRIPTEN/EGL]: error resizing canvas css: %d\n", r);
|
|
||||||
|
|
||||||
*resize = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
emscripten->fb_width = (unsigned)input_width;
|
|
||||||
emscripten->fb_height = (unsigned)input_height;
|
|
||||||
*quit = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_emscripten_swap_buffers(void *data)
|
static void gfx_ctx_emscripten_swap_buffers(void *data)
|
||||||
|
@ -148,6 +99,25 @@ static void gfx_ctx_emscripten_get_video_size(void *data,
|
||||||
*height = emscripten->fb_height;
|
*height = emscripten->fb_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool gfx_ctx_emscripten_get_metrics(void *data,
|
||||||
|
enum display_metric_types type, float *value)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
// there is no way to get the actual DPI in emscripten, so return a standard value instead.
|
||||||
|
// this is needed for menu touch/pointer swipe scrolling to work.
|
||||||
|
case DISPLAY_METRIC_DPI:
|
||||||
|
*value = 150.0f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
*value = 0.0f;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void gfx_ctx_emscripten_destroy(void *data)
|
static void gfx_ctx_emscripten_destroy(void *data)
|
||||||
{
|
{
|
||||||
emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data;
|
emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data;
|
||||||
|
@ -190,14 +160,6 @@ static void *gfx_ctx_emscripten_init(void *video_driver)
|
||||||
if (!emscripten)
|
if (!emscripten)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* TODO/FIXME - why is this conditional here - shouldn't these always
|
|
||||||
* be grabbed? */
|
|
||||||
if ( (emscripten->initial_width == 0)
|
|
||||||
|| (emscripten->initial_height == 0))
|
|
||||||
emscripten_get_canvas_element_size("!canvas",
|
|
||||||
&emscripten->initial_width,
|
|
||||||
&emscripten->initial_height);
|
|
||||||
|
|
||||||
#ifdef HAVE_EGL
|
#ifdef HAVE_EGL
|
||||||
if (g_egl_inited)
|
if (g_egl_inited)
|
||||||
{
|
{
|
||||||
|
@ -310,7 +272,7 @@ const gfx_ctx_driver_t gfx_ctx_emscripten = {
|
||||||
NULL, /* get_video_output_size */
|
NULL, /* get_video_output_size */
|
||||||
NULL, /* get_video_output_prev */
|
NULL, /* get_video_output_prev */
|
||||||
NULL, /* get_video_output_next */
|
NULL, /* get_video_output_next */
|
||||||
NULL, /* get_metrics */
|
gfx_ctx_emscripten_get_metrics,
|
||||||
gfx_ctx_emscripten_translate_aspect,
|
gfx_ctx_emscripten_translate_aspect,
|
||||||
NULL, /* update_title */
|
NULL, /* update_title */
|
||||||
gfx_ctx_emscripten_check_window,
|
gfx_ctx_emscripten_check_window,
|
||||||
|
|
|
@ -23,14 +23,18 @@
|
||||||
#include <encodings/crc32.h>
|
#include <encodings/crc32.h>
|
||||||
#include <encodings/utf.h>
|
#include <encodings/utf.h>
|
||||||
|
|
||||||
|
#include <emscripten/emscripten.h>
|
||||||
#include <emscripten/html5.h>
|
#include <emscripten/html5.h>
|
||||||
|
|
||||||
|
#include "../input_driver.h"
|
||||||
|
#include "../input_types.h"
|
||||||
#include "../input_keymaps.h"
|
#include "../input_keymaps.h"
|
||||||
|
|
||||||
#include "../../tasks/tasks_internal.h"
|
#include "../../tasks/tasks_internal.h"
|
||||||
#include "../../configuration.h"
|
#include "../../configuration.h"
|
||||||
#include "../../retroarch.h"
|
#include "../../retroarch.h"
|
||||||
#include "../../verbosity.h"
|
#include "../../verbosity.h"
|
||||||
|
#include "../../command.h"
|
||||||
|
|
||||||
/* https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button */
|
/* https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button */
|
||||||
#define RWEBINPUT_MOUSE_BTNL 0
|
#define RWEBINPUT_MOUSE_BTNL 0
|
||||||
|
@ -39,6 +43,8 @@
|
||||||
#define RWEBINPUT_MOUSE_BTN4 3
|
#define RWEBINPUT_MOUSE_BTN4 3
|
||||||
#define RWEBINPUT_MOUSE_BTN5 4
|
#define RWEBINPUT_MOUSE_BTN5 4
|
||||||
|
|
||||||
|
#define MAX_TOUCH 32
|
||||||
|
|
||||||
typedef struct rwebinput_key_to_code_map_entry
|
typedef struct rwebinput_key_to_code_map_entry
|
||||||
{
|
{
|
||||||
const char *key;
|
const char *key;
|
||||||
|
@ -58,26 +64,36 @@ typedef struct rwebinput_keyboard_event_queue
|
||||||
size_t max_size;
|
size_t max_size;
|
||||||
} rwebinput_keyboard_event_queue_t;
|
} rwebinput_keyboard_event_queue_t;
|
||||||
|
|
||||||
|
typedef struct rwebinput_pointer_states
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int id;
|
||||||
|
} rwebinput_pointer_state_t;
|
||||||
|
|
||||||
typedef struct rwebinput_mouse_states
|
typedef struct rwebinput_mouse_states
|
||||||
{
|
{
|
||||||
double pending_scroll_x;
|
double pending_scroll_x;
|
||||||
double pending_scroll_y;
|
double pending_scroll_y;
|
||||||
double scroll_x;
|
double scroll_x;
|
||||||
double scroll_y;
|
double scroll_y;
|
||||||
signed x;
|
int x;
|
||||||
signed y;
|
int y;
|
||||||
signed pending_delta_x;
|
int pending_delta_x;
|
||||||
signed pending_delta_y;
|
int pending_delta_y;
|
||||||
signed delta_x;
|
int delta_x;
|
||||||
signed delta_y;
|
int delta_y;
|
||||||
uint8_t buttons;
|
uint8_t buttons;
|
||||||
} rwebinput_mouse_state_t;
|
} rwebinput_mouse_state_t;
|
||||||
|
|
||||||
typedef struct rwebinput_input
|
typedef struct rwebinput_input
|
||||||
{
|
{
|
||||||
rwebinput_mouse_state_t mouse; /* double alignment */
|
rwebinput_mouse_state_t mouse; /* double alignment */
|
||||||
rwebinput_keyboard_event_queue_t keyboard; /* ptr alignment */
|
rwebinput_keyboard_event_queue_t keyboard; /* ptr alignment */
|
||||||
|
rwebinput_pointer_state_t pointer[MAX_TOUCH]; /* int alignment */
|
||||||
|
unsigned pointer_count;
|
||||||
bool keys[RETROK_LAST];
|
bool keys[RETROK_LAST];
|
||||||
|
bool pointerlock_active;
|
||||||
} rwebinput_input_t;
|
} rwebinput_input_t;
|
||||||
|
|
||||||
/* KeyboardEvent.keyCode has been deprecated for a while and doesn't have
|
/* KeyboardEvent.keyCode has been deprecated for a while and doesn't have
|
||||||
|
@ -255,11 +271,39 @@ static EM_BOOL rwebinput_mouse_cb(int event_type,
|
||||||
|
|
||||||
uint8_t mask = 1 << mouse_event->button;
|
uint8_t mask = 1 << mouse_event->button;
|
||||||
|
|
||||||
rwebinput->mouse.x = mouse_event->targetX;
|
// note: movementX/movementY are pre-scaled in chromium (but not firefox)
|
||||||
rwebinput->mouse.y = mouse_event->targetY;
|
// see https://github.com/w3c/pointerlock/issues/42
|
||||||
|
|
||||||
rwebinput->mouse.pending_delta_x += mouse_event->movementX;
|
rwebinput->mouse.pending_delta_x += mouse_event->movementX;
|
||||||
rwebinput->mouse.pending_delta_y += mouse_event->movementY;
|
rwebinput->mouse.pending_delta_y += mouse_event->movementY;
|
||||||
|
|
||||||
|
if (rwebinput->pointerlock_active)
|
||||||
|
{
|
||||||
|
unsigned video_width, video_height;
|
||||||
|
video_driver_get_size(&video_width, &video_height);
|
||||||
|
|
||||||
|
rwebinput->mouse.x += mouse_event->movementX;
|
||||||
|
rwebinput->mouse.y += mouse_event->movementY;
|
||||||
|
|
||||||
|
/* Clamp X */
|
||||||
|
if (rwebinput->mouse.x < 0)
|
||||||
|
rwebinput->mouse.x = 0;
|
||||||
|
if (rwebinput->mouse.x >= video_width)
|
||||||
|
rwebinput->mouse.x = (int)(video_width - 1);
|
||||||
|
|
||||||
|
/* Clamp Y */
|
||||||
|
if (rwebinput->mouse.y < 0)
|
||||||
|
rwebinput->mouse.y = 0;
|
||||||
|
if (rwebinput->mouse.y >= video_height)
|
||||||
|
rwebinput->mouse.y = (int)(video_height - 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double dpr = emscripten_get_device_pixel_ratio();
|
||||||
|
rwebinput->mouse.x = (int)(mouse_event->targetX * dpr);
|
||||||
|
rwebinput->mouse.y = (int)(mouse_event->targetY * dpr);
|
||||||
|
}
|
||||||
|
|
||||||
if (event_type == EMSCRIPTEN_EVENT_MOUSEDOWN)
|
if (event_type == EMSCRIPTEN_EVENT_MOUSEDOWN)
|
||||||
rwebinput->mouse.buttons |= mask;
|
rwebinput->mouse.buttons |= mask;
|
||||||
else if (event_type == EMSCRIPTEN_EVENT_MOUSEUP)
|
else if (event_type == EMSCRIPTEN_EVENT_MOUSEUP)
|
||||||
|
@ -273,8 +317,90 @@ static EM_BOOL rwebinput_wheel_cb(int event_type,
|
||||||
{
|
{
|
||||||
rwebinput_input_t *rwebinput = (rwebinput_input_t*)user_data;
|
rwebinput_input_t *rwebinput = (rwebinput_input_t*)user_data;
|
||||||
|
|
||||||
rwebinput->mouse.pending_scroll_x += wheel_event->deltaX;
|
double dpr = emscripten_get_device_pixel_ratio();
|
||||||
rwebinput->mouse.pending_scroll_y += wheel_event->deltaY;
|
rwebinput->mouse.pending_scroll_x += wheel_event->deltaX * dpr;
|
||||||
|
rwebinput->mouse.pending_scroll_y += wheel_event->deltaY * dpr;
|
||||||
|
|
||||||
|
return EM_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EM_BOOL rwebinput_touch_cb(int event_type,
|
||||||
|
const EmscriptenTouchEvent *touch_event, void *user_data)
|
||||||
|
{
|
||||||
|
rwebinput_input_t *rwebinput = (rwebinput_input_t*)user_data;
|
||||||
|
|
||||||
|
unsigned touches_max = MIN(touch_event->numTouches, MAX_TOUCH);
|
||||||
|
unsigned touches_released = 0;
|
||||||
|
|
||||||
|
switch (event_type)
|
||||||
|
{
|
||||||
|
case EMSCRIPTEN_EVENT_TOUCHSTART:
|
||||||
|
case EMSCRIPTEN_EVENT_TOUCHMOVE:
|
||||||
|
for (unsigned touch = 0; touch < touches_max; touch++)
|
||||||
|
{
|
||||||
|
if (!(touch_event->touches[touch].isChanged) && rwebinput->pointer[touch].id == touch_event->touches[touch].identifier)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
double dpr = emscripten_get_device_pixel_ratio();
|
||||||
|
rwebinput->pointer[touch].x = (int)(touch_event->touches[touch].targetX * dpr);
|
||||||
|
rwebinput->pointer[touch].y = (int)(touch_event->touches[touch].targetY * dpr);
|
||||||
|
rwebinput->pointer[touch].id = touch_event->touches[touch].identifier;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EMSCRIPTEN_EVENT_TOUCHEND:
|
||||||
|
case EMSCRIPTEN_EVENT_TOUCHCANCEL:
|
||||||
|
// note: touches_max/numTouches is out of date here - it uses the old value from before the release
|
||||||
|
// note 2: I'm unsure if multiple touches can trigger the same touchend anyway...
|
||||||
|
if (touches_max > 1)
|
||||||
|
{
|
||||||
|
for (unsigned touch_up = 0; touch_up < touches_max; touch_up++)
|
||||||
|
{
|
||||||
|
if (touch_event->touches[touch_up].isChanged)
|
||||||
|
{
|
||||||
|
memmove(rwebinput->pointer + touch_up - touches_released,
|
||||||
|
rwebinput->pointer + touch_up - touches_released + 1,
|
||||||
|
(touches_max - touch_up - 1) * sizeof(rwebinput_pointer_state_t));
|
||||||
|
touches_released++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
touches_released = 1;
|
||||||
|
|
||||||
|
if (touches_max > touches_released)
|
||||||
|
touches_max -= touches_released;
|
||||||
|
else
|
||||||
|
touches_max = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rwebinput->pointer_count = touches_max;
|
||||||
|
|
||||||
|
return EM_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EM_BOOL rwebinput_pointerlockchange_cb(int event_type,
|
||||||
|
const EmscriptenPointerlockChangeEvent *pointerlock_change_event, void *user_data)
|
||||||
|
{
|
||||||
|
rwebinput_input_t *rwebinput = (rwebinput_input_t*)user_data;
|
||||||
|
|
||||||
|
rwebinput->pointerlock_active = pointerlock_change_event->isActive;
|
||||||
|
|
||||||
|
if (!pointerlock_change_event->isActive)
|
||||||
|
{
|
||||||
|
input_driver_state_t *input_st = input_state_get_ptr();
|
||||||
|
|
||||||
|
if (input_st->game_focus_state.enabled)
|
||||||
|
{
|
||||||
|
enum input_game_focus_cmd_type game_focus_cmd = GAME_FOCUS_CMD_OFF;
|
||||||
|
command_event(CMD_EVENT_GAME_FOCUS_TOGGLE, &game_focus_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input_st->flags & INP_FLAG_GRAB_MOUSE_STATE)
|
||||||
|
{
|
||||||
|
command_event(CMD_EVENT_GRAB_MOUSE_TOGGLE, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return EM_TRUE;
|
return EM_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -350,6 +476,47 @@ static void *rwebinput_input_init(const char *joypad_driver)
|
||||||
"[EMSCRIPTEN/INPUT] failed to create wheel callback: %d\n", r);
|
"[EMSCRIPTEN/INPUT] failed to create wheel callback: %d\n", r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = emscripten_set_touchstart_callback("!canvas", rwebinput, false,
|
||||||
|
rwebinput_touch_cb);
|
||||||
|
if (r != EMSCRIPTEN_RESULT_SUCCESS)
|
||||||
|
{
|
||||||
|
RARCH_ERR(
|
||||||
|
"[EMSCRIPTEN/INPUT] failed to create touchstart callback: %d\n", r);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = emscripten_set_touchend_callback("!canvas", rwebinput, false,
|
||||||
|
rwebinput_touch_cb);
|
||||||
|
if (r != EMSCRIPTEN_RESULT_SUCCESS)
|
||||||
|
{
|
||||||
|
RARCH_ERR(
|
||||||
|
"[EMSCRIPTEN/INPUT] failed to create touchend callback: %d\n", r);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = emscripten_set_touchmove_callback("!canvas", rwebinput, false,
|
||||||
|
rwebinput_touch_cb);
|
||||||
|
if (r != EMSCRIPTEN_RESULT_SUCCESS)
|
||||||
|
{
|
||||||
|
RARCH_ERR(
|
||||||
|
"[EMSCRIPTEN/INPUT] failed to create touchmove callback: %d\n", r);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = emscripten_set_touchcancel_callback("!canvas", rwebinput, false,
|
||||||
|
rwebinput_touch_cb);
|
||||||
|
if (r != EMSCRIPTEN_RESULT_SUCCESS)
|
||||||
|
{
|
||||||
|
RARCH_ERR(
|
||||||
|
"[EMSCRIPTEN/INPUT] failed to create touchcancel callback: %d\n", r);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = emscripten_set_pointerlockchange_callback(
|
||||||
|
EMSCRIPTEN_EVENT_TARGET_DOCUMENT, rwebinput, false,
|
||||||
|
rwebinput_pointerlockchange_cb);
|
||||||
|
if (r != EMSCRIPTEN_RESULT_SUCCESS)
|
||||||
|
{
|
||||||
|
RARCH_ERR(
|
||||||
|
"[EMSCRIPTEN/INPUT] failed to create pointerlockchange callback: %d\n", r);
|
||||||
|
}
|
||||||
|
|
||||||
input_keymaps_init_keyboard_lut(rarch_key_map_rwebinput);
|
input_keymaps_init_keyboard_lut(rarch_key_map_rwebinput);
|
||||||
|
|
||||||
return rwebinput;
|
return rwebinput;
|
||||||
|
@ -505,24 +672,41 @@ static int16_t rwebinput_input_state(
|
||||||
return rwebinput_mouse_state(&rwebinput->mouse, id, device == RARCH_DEVICE_MOUSE_SCREEN);
|
return rwebinput_mouse_state(&rwebinput->mouse, id, device == RARCH_DEVICE_MOUSE_SCREEN);
|
||||||
case RETRO_DEVICE_POINTER:
|
case RETRO_DEVICE_POINTER:
|
||||||
case RARCH_DEVICE_POINTER_SCREEN:
|
case RARCH_DEVICE_POINTER_SCREEN:
|
||||||
if (idx == 0)
|
|
||||||
{
|
{
|
||||||
struct video_viewport vp = {0};
|
struct video_viewport vp = {0};
|
||||||
rwebinput_mouse_state_t
|
rwebinput_mouse_state_t
|
||||||
*mouse = &rwebinput->mouse;
|
*mouse = &rwebinput->mouse;
|
||||||
bool screen = device ==
|
bool pointer_down = false;
|
||||||
RARCH_DEVICE_POINTER_SCREEN;
|
unsigned pointer_count = rwebinput->pointer_count;
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
int16_t res_x = 0;
|
int16_t res_x = 0;
|
||||||
int16_t res_y = 0;
|
int16_t res_y = 0;
|
||||||
int16_t res_screen_x = 0;
|
int16_t res_screen_x = 0;
|
||||||
int16_t res_screen_y = 0;
|
int16_t res_screen_y = 0;
|
||||||
|
|
||||||
|
if (pointer_count && idx < pointer_count)
|
||||||
|
{
|
||||||
|
x = rwebinput->pointer[idx].x;
|
||||||
|
y = rwebinput->pointer[idx].y;
|
||||||
|
pointer_down = true;
|
||||||
|
}
|
||||||
|
else if (idx == 0)
|
||||||
|
{
|
||||||
|
x = mouse->x;
|
||||||
|
y = mouse->y;
|
||||||
|
pointer_down = !!(mouse->buttons & (1 << RWEBINPUT_MOUSE_BTNL));
|
||||||
|
pointer_count = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (!(video_driver_translate_coord_viewport_confined_wrap(
|
if (!(video_driver_translate_coord_viewport_confined_wrap(
|
||||||
&vp, mouse->x, mouse->y,
|
&vp, x, y,
|
||||||
&res_x, &res_y, &res_screen_x, &res_screen_y)))
|
&res_x, &res_y, &res_screen_x, &res_screen_y)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (screen)
|
if (device == RARCH_DEVICE_POINTER_SCREEN)
|
||||||
{
|
{
|
||||||
res_x = res_screen_x;
|
res_x = res_screen_x;
|
||||||
res_y = res_screen_y;
|
res_y = res_screen_y;
|
||||||
|
@ -535,7 +719,9 @@ static int16_t rwebinput_input_state(
|
||||||
case RETRO_DEVICE_ID_POINTER_Y:
|
case RETRO_DEVICE_ID_POINTER_Y:
|
||||||
return res_y;
|
return res_y;
|
||||||
case RETRO_DEVICE_ID_POINTER_PRESSED:
|
case RETRO_DEVICE_ID_POINTER_PRESSED:
|
||||||
return !!(mouse->buttons & (1 << RWEBINPUT_MOUSE_BTNL));
|
return (pointer_down && !input_driver_pointer_is_offscreen(res_x, res_y));
|
||||||
|
case RETRO_DEVICE_ID_POINTER_COUNT:
|
||||||
|
return pointer_count;
|
||||||
case RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN:
|
case RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN:
|
||||||
return input_driver_pointer_is_offscreen(res_x, res_y);
|
return input_driver_pointer_is_offscreen(res_x, res_y);
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -287,15 +287,12 @@ bool gl_check_capability(enum gl_capability_enum enum_idx)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GL_CAPS_FP_FBO:
|
case GL_CAPS_FP_FBO:
|
||||||
/* GLES - No extensions for float FBO currently. */
|
|
||||||
#ifndef HAVE_OPENGLES
|
|
||||||
if (gl_check_capability(GL_CAPS_FBO))
|
if (gl_check_capability(GL_CAPS_FBO))
|
||||||
{
|
{
|
||||||
/* Float FBO is core in 3.2. */
|
/* Float FBO is core in 3.2. */
|
||||||
if (gl_query_core_context_in_use() || gl_query_extension("ARB_texture_float"))
|
if (gl_query_core_context_in_use() || gl_query_extension("ARB_texture_float") || gl_query_extension("OES_texture_float_linear"))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
case GL_CAPS_BGRA8888:
|
case GL_CAPS_BGRA8888:
|
||||||
#ifdef HAVE_OPENGLES
|
#ifdef HAVE_OPENGLES
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
#include <psp2/kernel/threadmgr.h>
|
#include <psp2/kernel/threadmgr.h>
|
||||||
#elif defined(_3DS)
|
#elif defined(_3DS)
|
||||||
#include <3ds.h>
|
#include <3ds.h>
|
||||||
#elif defined(EMSCRIPTEN_FIXME)
|
#elif defined(EMSCRIPTEN)
|
||||||
#include <emscripten/emscripten.h>
|
#include <emscripten/emscripten.h>
|
||||||
#else
|
#else
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -100,7 +100,7 @@ static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)
|
||||||
#define retro_sleep(msec) (usleep(1000 * (msec)))
|
#define retro_sleep(msec) (usleep(1000 * (msec)))
|
||||||
#elif defined(WIIU)
|
#elif defined(WIIU)
|
||||||
#define retro_sleep(msec) (OSSleepTicks(ms_to_ticks((msec))))
|
#define retro_sleep(msec) (OSSleepTicks(ms_to_ticks((msec))))
|
||||||
#elif defined(EMSCRIPTEN_FIXME)
|
#elif defined(EMSCRIPTEN)
|
||||||
#define retro_sleep(msec) (emscripten_sleep(msec))
|
#define retro_sleep(msec) (emscripten_sleep(msec))
|
||||||
#else
|
#else
|
||||||
static INLINE void retro_sleep(unsigned msec)
|
static INLINE void retro_sleep(unsigned msec)
|
||||||
|
|
|
@ -452,7 +452,8 @@ enum ozone_handle_flags2
|
||||||
OZONE_FLAG2_RESET_DEPTH = (1 << 8),
|
OZONE_FLAG2_RESET_DEPTH = (1 << 8),
|
||||||
OZONE_FLAG2_PENDING_CURSOR_IN_SIDEBAR = (1 << 9),
|
OZONE_FLAG2_PENDING_CURSOR_IN_SIDEBAR = (1 << 9),
|
||||||
OZONE_FLAG2_IS_QUICK_MENU = (1 << 10),
|
OZONE_FLAG2_IS_QUICK_MENU = (1 << 10),
|
||||||
OZONE_FLAG2_IS_PLAYLISTS_TAB = (1 << 11)
|
OZONE_FLAG2_IS_PLAYLISTS_TAB = (1 << 11),
|
||||||
|
OZONE_FLAG2_IGNORE_MISSING_ASSETS = (1 << 12)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ozone_handle
|
struct ozone_handle
|
||||||
|
@ -1732,7 +1733,7 @@ static void ozone_set_color_theme(
|
||||||
ozone->theme->message_background,
|
ozone->theme->message_background,
|
||||||
sizeof(ozone->theme_dynamic.message_background));
|
sizeof(ozone->theme_dynamic.message_background));
|
||||||
|
|
||||||
if (ozone->flags & OZONE_FLAG_HAS_ALL_ASSETS)
|
if (ozone->flags & OZONE_FLAG_HAS_ALL_ASSETS || ozone->flags2 & OZONE_FLAG2_IGNORE_MISSING_ASSETS)
|
||||||
ozone_restart_cursor_animation(ozone);
|
ozone_restart_cursor_animation(ozone);
|
||||||
|
|
||||||
ozone_last_color_theme = color_theme;
|
ozone_last_color_theme = color_theme;
|
||||||
|
@ -3215,7 +3216,7 @@ static void ozone_draw_cursor(
|
||||||
|
|
||||||
/* Draw the cursor */
|
/* Draw the cursor */
|
||||||
if ( (ozone->theme->name)
|
if ( (ozone->theme->name)
|
||||||
&& (ozone->flags & OZONE_FLAG_HAS_ALL_ASSETS))
|
&& (ozone->flags & OZONE_FLAG_HAS_ALL_ASSETS || ozone->flags2 & OZONE_FLAG2_IGNORE_MISSING_ASSETS))
|
||||||
ozone_draw_cursor_slice(ozone,
|
ozone_draw_cursor_slice(ozone,
|
||||||
p_disp,
|
p_disp,
|
||||||
userdata,
|
userdata,
|
||||||
|
@ -7024,7 +7025,7 @@ static void ozone_draw_messagebox(
|
||||||
dispctx->blend_begin(userdata);
|
dispctx->blend_begin(userdata);
|
||||||
|
|
||||||
/* Avoid drawing a black box if there's no assets */
|
/* Avoid drawing a black box if there's no assets */
|
||||||
if (ozone->flags & OZONE_FLAG_HAS_ALL_ASSETS)
|
if (ozone->flags & OZONE_FLAG_HAS_ALL_ASSETS || ozone->flags2 & OZONE_FLAG2_IGNORE_MISSING_ASSETS)
|
||||||
{
|
{
|
||||||
/* Note: The fact that we use a texture slice here
|
/* Note: The fact that we use a texture slice here
|
||||||
* makes things very messy
|
* makes things very messy
|
||||||
|
@ -9432,9 +9433,14 @@ static void ozone_context_reset(void *data, bool is_threaded)
|
||||||
|
|
||||||
if (ozone)
|
if (ozone)
|
||||||
{
|
{
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
|
||||||
ozone->flags |= OZONE_FLAG_HAS_ALL_ASSETS;
|
ozone->flags |= OZONE_FLAG_HAS_ALL_ASSETS;
|
||||||
|
|
||||||
ozone_set_layout(ozone, config_get_ptr()->bools.ozone_collapse_sidebar, is_threaded);
|
if (settings->bools.menu_ignore_missing_assets)
|
||||||
|
ozone->flags2 |= OZONE_FLAG2_IGNORE_MISSING_ASSETS;
|
||||||
|
|
||||||
|
ozone_set_layout(ozone, settings->bools.ozone_collapse_sidebar, is_threaded);
|
||||||
|
|
||||||
/* Textures init */
|
/* Textures init */
|
||||||
for (i = 0; i < OZONE_TEXTURE_LAST; i++)
|
for (i = 0; i < OZONE_TEXTURE_LAST; i++)
|
||||||
|
@ -9527,7 +9533,7 @@ static void ozone_context_reset(void *data, bool is_threaded)
|
||||||
ozone_update_thumbnail_image(ozone);
|
ozone_update_thumbnail_image(ozone);
|
||||||
ozone_update_savestate_thumbnail_image(ozone);
|
ozone_update_savestate_thumbnail_image(ozone);
|
||||||
|
|
||||||
if (ozone->flags & OZONE_FLAG_HAS_ALL_ASSETS)
|
if (ozone->flags & OZONE_FLAG_HAS_ALL_ASSETS || ozone->flags2 & OZONE_FLAG2_IGNORE_MISSING_ASSETS)
|
||||||
ozone_restart_cursor_animation(ozone);
|
ozone_restart_cursor_animation(ozone);
|
||||||
|
|
||||||
/* Screensaver */
|
/* Screensaver */
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
# RetroArch Web Player
|
# RetroArch Web Player
|
||||||
|
|
||||||
The RetroArch Web Player is RetroArch compiled through [Emscripten](http://kripken.github.io/emscripten-site/). The following outlines how to compile RetroArch using Emscripten, and running it in your browser.
|
The RetroArch Web Player is RetroArch compiled through [Emscripten](https://emscripten.org/). The following outlines how to compile RetroArch using Emscripten, and running it in your browser.
|
||||||
|
|
||||||
## Compiling
|
## Compiling
|
||||||
|
|
||||||
To compile RetroArch with Emscripten, you'll first have to [download and install the Emscripten SDK](http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html) at 3.1.46:
|
To compile RetroArch with Emscripten, you'll first have to [download and install the Emscripten SDK](https://emscripten.org/docs/getting_started/downloads.html) at 3.1.46:
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/emscripten-core/emsdk.git
|
git clone https://github.com/emscripten-core/emsdk.git
|
||||||
|
|
|
@ -1,91 +1,83 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<title>RetroArch Web Player</title>
|
||||||
<title>RetroArch Web Player</title>
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<!-- Bootstrap core CSS -->
|
||||||
<!-- Bootstrap core CSS -->
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.3/css/bootstrap.min.css" rel="stylesheet" type="text/css">
|
||||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.3/css/bootstrap.min.css" rel="stylesheet" type="text/css">
|
<!-- Font Awesome -->
|
||||||
<!-- Font Awesome -->
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.0/css/font-awesome.min.css">
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.0/css/font-awesome.min.css">
|
<!-- Material Design Bootstrap -->
|
||||||
<!-- Material Design Bootstrap -->
|
<link href="//cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.1.1/css/mdb.min.css" rel="stylesheet">
|
||||||
<link href="//cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.1.1/css/mdb.min.css" rel="stylesheet">
|
<link href="libretro.css" rel="stylesheet" type="text/css">
|
||||||
|
<link rel="shortcut icon" href="https://web.libretro.com/media/retroarch.ico" />
|
||||||
<link href="libretro.css" rel="stylesheet" type="text/css">
|
</head>
|
||||||
<link rel="shortcut icon" href="https://web.libretro.com/media/retroarch.ico" />
|
<body>
|
||||||
</head>
|
<!--Navbar-->
|
||||||
<body>
|
<nav class="navbar navbar-dark bg-primary">
|
||||||
<!--Navbar-->
|
<div class="container">
|
||||||
<nav class="navbar navbar-dark bg-primary">
|
<!--navbar content-->
|
||||||
<div class="container">
|
<div class="navbar-toggleable-xs">
|
||||||
<!--navbar content-->
|
|
||||||
<div class="navbar-toggleable-xs">
|
|
||||||
|
|
||||||
<!--Links-->
|
<!--Links-->
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Core Selection</button>
|
<button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Core Selection</button>
|
||||||
<div class="dropdown-menu dropdown-primary" aria-labelledby="dropdownMenu1" data-dropdown-in="fadeIn" data-dropdown-out="fadeOut" id="core-selector">
|
<div class="dropdown-menu dropdown-primary" aria-labelledby="dropdownMenu1" data-dropdown-in="fadeIn" data-dropdown-out="fadeOut" id="core-selector">
|
||||||
<a class="dropdown-item" href="." data-core="chailove">ChaiLove</a>
|
<a class="dropdown-item" href="." data-core="chailove">ChaiLove</a>
|
||||||
<a class="dropdown-item" href="." data-core="fceumm">FCEUmm</a>
|
<a class="dropdown-item" href="." data-core="fceumm">FCEUmm</a>
|
||||||
<a class="dropdown-item" href="." data-core="gambatte">Gambatte</a>
|
<a class="dropdown-item" href="." data-core="gambatte">Gambatte</a>
|
||||||
<a class="dropdown-item" href="." data-core="genesis_plus_gx">Genesis Plus GX</a>
|
<a class="dropdown-item" href="." data-core="genesis_plus_gx">Genesis Plus GX</a>
|
||||||
<a class="dropdown-item" href="." data-core="lutro">Lutro</a>
|
<a class="dropdown-item" href="." data-core="lutro">Lutro</a>
|
||||||
<a class="dropdown-item" href="." data-core="nestopia">Nestopia (NES)</a>
|
<a class="dropdown-item" href="." data-core="nestopia">Nestopia (NES)</a>
|
||||||
<a class="dropdown-item" href="." data-core="snes9x2010">Snes9x 2010 (SNES)</a>
|
<a class="dropdown-item" href="." data-core="snes9x">Snes9x (SNES)</a>
|
||||||
<a class="dropdown-item" href="." data-core="theodore">Theodore (Thomson TO8/TO9)</a>
|
<a class="dropdown-item" href="." data-core="snes9x2010">Snes9x 2010 (SNES)</a>
|
||||||
<a class="dropdown-item" href="." data-core="vba_next">VBA Next (Gameboy Advance)</a>
|
<a class="dropdown-item" href="." data-core="theodore">Theodore (Thomson TO8/TO9)</a>
|
||||||
|
<a class="dropdown-item" href="." data-core="vba_next">VBA Next (Gameboy Advance)</a>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-primary disabled" id="btnRun" onclick="startRetroArch()" disabled>
|
<button class="btn btn-primary disabled" id="btnRun" disabled>
|
||||||
<span class="fa fa-spinner fa-spin" id="icnRun"></span> Run
|
<span class="fa fa-spinner fa-spin" id="icnRun"></span> Run
|
||||||
</button>
|
</button>
|
||||||
|
<button class="btn btn-primary disabled" id="btnAdd" disabled>
|
||||||
<button class="btn btn-primary disabled" id="btnAdd" onclick="document.getElementById('btnRom').click()" disabled>
|
<span class="fa fa-plus" id="icnAdd"></span> Add Content
|
||||||
<span class="fa fa-plus" id="icnAdd"></span> Add Content
|
|
||||||
</button>
|
</button>
|
||||||
|
<input style="display: none" type="file" id="btnRom" name="upload" multiple />
|
||||||
<button class="btn btn-primary tooltip-enable" id="btnClean" onclick="cleanupStorage();" title="Cleanup storage">
|
<button class="btn btn-primary tooltip-enable" id="btnClean" title="Cleanup storage">
|
||||||
<span class="fa fa-trash-o" id="icnClean"></span> <span class="sr-only">Cleanup</span>
|
<span class="fa fa-trash-o" id="icnClean"></span> <span class="sr-only">Cleanup</span>
|
||||||
</button>
|
</button>
|
||||||
|
<button class="btn btn-primary disabled tooltip-enable" id="btnMenu" title="Menu toggle" disabled>
|
||||||
<input class="btn btn-primary disabled" style="display: none" type="file" id="btnRom" name="upload" onclick="document.getElementById('btnAdd').click();" onchange="selectFiles(event.target.files)" multiple />
|
<span class="fa fa-bars" id="icnMenu"></span> <span class="sr-only">Menu</span>
|
||||||
<button class="btn btn-primary disabled tooltip-enable" id="btnMenu" onclick="keyPress('F1');" title="Menu toggle" disabled>
|
|
||||||
<span class="fa fa-bars" id="btnMenu"></span> <span class="sr-only">Menu</span>
|
|
||||||
</button>
|
</button>
|
||||||
|
<button class="btn btn-primary disabled tooltip-enable" id="btnFullscreen" title="Fullscreen" disabled>
|
||||||
<button class="btn btn-primary disabled tooltip-enable" id="btnFullscreen" onclick="Module.requestFullscreen(false)" title="Fullscreen" disabled>
|
<span class="fa fa-desktop" id="icnFullscreen"></span> <span class="sr-only">Fullscreen</span>
|
||||||
<span class="fa fa-desktop" id="icnAdd"></span> <span class="sr-only">Fullscreen</span>
|
|
||||||
</button>
|
</button>
|
||||||
|
</li>
|
||||||
</li>
|
</div>
|
||||||
</div>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<!--/.navbar content-->
|
<!--/.navbar content-->
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="bg-inverse webplayer-container">
|
<div class="bg-inverse webplayer-container">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="webplayer_border text-xs-center" id="canvas_div">
|
<div class="webplayer_border text-xs-center" id="canvas_div">
|
||||||
<canvas class="webplayer" id="canvas" tabindex="1" oncontextmenu="event.preventDefault()" style="display: none"></canvas>
|
<canvas class="webplayer" id="canvas" tabindex="1" oncontextmenu="event.preventDefault()" style="display: none"></canvas>
|
||||||
<img class="webplayer-preview img-fluid" src="media/canvas.png" width="960px" height="720px" alt="RetroArch Logo">
|
<img class="webplayer-preview img-fluid" src="media/canvas.png" width="960" height="720" alt="RetroArch Logo">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<script src="//code.jquery.com/jquery-3.1.0.min.js"></script>
|
||||||
|
<script src="//rawgit.com/jeresig/jquery.hotkeys/master/jquery.hotkeys.js"></script>
|
||||||
<script src="//code.jquery.com/jquery-3.1.0.min.js"></script>
|
<script src="//cdnjs.cloudflare.com/ajax/libs/tether/1.3.4/js/tether.min.js"></script>
|
||||||
<script src="//rawgit.com/jeresig/jquery.hotkeys/master/jquery.hotkeys.js"></script>
|
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.3/js/bootstrap.min.js"></script>
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/tether/1.3.4/js/tether.min.js"></script>
|
<script src="analytics.js"></script>
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.3/js/bootstrap.min.js"></script>
|
<!--script src="//wzrd.in/standalone/browserfs@0.6.1"></script-->
|
||||||
<script src="analytics.js"></script>
|
<script src="browserfs.min.js"></script>
|
||||||
<!--script src="//wzrd.in/standalone/browserfs@0.6.1"></script-->
|
<script src="libretro.js"></script>
|
||||||
<script src="browserfs.min.js"></script>
|
<div align="center">
|
||||||
<script src="libretro.js"></script>
|
<a href="https://www.patreon.com/libretro">
|
||||||
<div align="center">
|
<img src="https://patreon_public_assets.s3.amazonaws.com/sized/becomeAPatronBanner.png" alt="Become a patron" width="350" height="116"></a>
|
||||||
<a href="https://www.patreon.com/libretro">
|
</div>
|
||||||
<img src="https://patreon_public_assets.s3.amazonaws.com/sized/becomeAPatronBanner.png" width="350" height="116"></a>
|
</body>
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,30 +1,28 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>RetroArch Web Player</title>
|
<title>RetroArch Web Player</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<!-- Bootstrap core CSS -->
|
<!-- Bootstrap core CSS -->
|
||||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.3/css/bootstrap.min.css" rel="stylesheet" type="text/css">
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.3/css/bootstrap.min.css" rel="stylesheet" type="text/css">
|
||||||
<!-- Font Awesome -->
|
<!-- Font Awesome -->
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.0/css/font-awesome.min.css">
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.0/css/font-awesome.min.css">
|
||||||
<!-- Material Design Bootstrap -->
|
<!-- Material Design Bootstrap -->
|
||||||
<link href="//cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.1.1/css/mdb.min.css" rel="stylesheet">
|
<link href="//cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.1.1/css/mdb.min.css" rel="stylesheet">
|
||||||
|
<link href="libretro.css" rel="stylesheet" type="text/css">
|
||||||
<link href="libretro.css" rel="stylesheet" type="text/css">
|
<link rel="shortcut icon" href="media/retroarch.ico" />
|
||||||
<link rel="shortcut icon" href="media/retroarch.ico" />
|
</head>
|
||||||
|
<body>
|
||||||
</head>
|
<!--Navbar-->
|
||||||
<body>
|
<nav class="navbar navbar-dark bg-primary">
|
||||||
<!--Navbar-->
|
<div class="container">
|
||||||
<nav class="navbar navbar-dark bg-primary">
|
<!--navbar content-->
|
||||||
<div class="container">
|
<div class="navbar-toggleable-xs">
|
||||||
<!--navbar content-->
|
|
||||||
<div class="navbar-toggleable-xs">
|
|
||||||
<!--Links-->
|
<!--Links-->
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Core Selection</button>
|
<button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Core Selection</button>
|
||||||
<div class="dropdown-menu dropdown-primary" aria-labelledby="dropdownMenu1" data-dropdown-in="fadeIn" data-dropdown-out="fadeOut" id="core-selector">
|
<div class="dropdown-menu dropdown-primary" aria-labelledby="dropdownMenu1" data-dropdown-in="fadeIn" data-dropdown-out="fadeOut" id="core-selector">
|
||||||
<a class="dropdown-item" href="." data-core="2048">2048</a>
|
<a class="dropdown-item" href="." data-core="2048">2048</a>
|
||||||
|
@ -117,92 +115,90 @@
|
||||||
<a class="dropdown-item" href="." data-core="x1">Sharp X1 (X Millenium)</a>
|
<a class="dropdown-item" href="." data-core="x1">Sharp X1 (X Millenium)</a>
|
||||||
<a class="dropdown-item" href="." data-core="xrick">Rick Dangerous (XRick)</a>
|
<a class="dropdown-item" href="." data-core="xrick">Rick Dangerous (XRick)</a>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-primary disabled" id="btnRun" onclick="startRetroArch()" disabled>
|
<button class="btn btn-primary disabled" id="btnRun" disabled>
|
||||||
<span class="fa fa-spinner fa-spin" id="icnRun"></span> Run
|
<span class="fa fa-spinner fa-spin" id="icnRun"></span> Run
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-primary disabled" id="btnAdd" onclick="document.getElementById('btnRom').click()" disabled>
|
<button class="btn btn-primary disabled" id="btnAdd" disabled>
|
||||||
<span class="fa fa-plus" id="icnAdd"></span> Add Content
|
<span class="fa fa-plus" id="icnAdd"></span> Add Content
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-primary tooltip-enable" id="btnClean" onclick="cleanupStorage();" title="Cleanup storage">
|
<input style="display: none" type="file" id="btnRom" name="upload" multiple />
|
||||||
<span class="fa fa-trash-o" id="icnClean"></span> <span class="sr-only">Cleanup</span>
|
<button class="btn btn-primary tooltip-enable" id="btnClean" title="Cleanup storage">
|
||||||
|
<span class="fa fa-trash-o" id="icnClean"></span> <span class="sr-only">Cleanup</span>
|
||||||
</button>
|
</button>
|
||||||
<input class="btn btn-primary disabled" style="display: none" type="file" id="btnRom" name="upload" onclick="document.getElementById('btnAdd').click();" onchange="selectFiles(event.target.files)" multiple />
|
<button class="btn btn-primary disabled tooltip-enable" id="btnMenu" title="Menu toggle" disabled>
|
||||||
<button class="btn btn-primary disabled tooltip-enable" id="btnMenu" onclick="keyPress('F1');" title="Menu toggle" disabled>
|
<span class="fa fa-bars" id="icnMenu"></span> <span class="sr-only">Menu</span>
|
||||||
<span class="fa fa-bars" id="btnMenu"></span> <span class="sr-only">Menu</span>
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-primary disabled tooltip-enable" id="btnFullscreen" onclick="Module.requestFullscreen(false)" title="Fullscreen" disabled>
|
|
||||||
<span class="fa fa-desktop" id="icnAdd"></span> <span class="sr-only">Fullscreen</span>
|
|
||||||
</button>
|
</button>
|
||||||
|
<button class="btn btn-primary disabled tooltip-enable" id="btnFullscreen" title="Fullscreen" disabled>
|
||||||
|
<span class="fa fa-desktop" id="icnFullscreen"></span> <span class="sr-only">Fullscreen</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-primary tooltip-enable" data-toggle="modal" data-target="#helpModal">Help</button>
|
<button type="button" class="btn btn-primary tooltip-enable" data-toggle="modal" data-target="#helpModal">Help</button>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="toggleMenu">
|
<div class="toggleMenu">
|
||||||
<button class="btn btn-primary" id="btnHideMenu" title="Toggle Menu">
|
<button class="btn btn-primary" id="btnHideMenu" title="Toggle Menu">
|
||||||
<span class="fa fa-chevron-up" id="icnHideMenu"></span> <span class="sr-only">Hide Top Navigation</span>
|
<span class="fa fa-chevron-up" id="icnHideMenu"></span> <span class="sr-only">Hide Top Navigation</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Basics steps modal for Web Libretro -->
|
<!-- Basics steps modal for Web Libretro -->
|
||||||
<div class="modal fade" id="helpModal" role="dialog" style="color:black;">
|
<div class="modal fade" id="helpModal" role="dialog" style="color:black;">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||||
<h1 class="modal-title">Basics</h1>
|
<h1 class="modal-title">Basics</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<h3><b>Load Core</b></h3>
|
<h3><b>Load Core</b></h3>
|
||||||
<p>Load your core by clicking on the first tab. Scroll down until you reach the desired Core. We will use Nestopia for now. Don't forget - Content must be compatible with the matched Core.</p>
|
<p>Load your core by clicking on the first tab. Scroll down until you reach the desired Core. We will use Nestopia for now. Don't forget - Content must be compatible with the matched Core.</p>
|
||||||
<li>Nes: <i>NESTOPIA</i></li>
|
<ul>
|
||||||
<li>Game Boy / Color: <i>Gambatte</i></li>
|
<li>Nes: <i>NESTOPIA</i></li>
|
||||||
</ul>
|
<li>Game Boy / Color: <i>Gambatte</i></li>
|
||||||
<p>etc.</p>
|
</ul>
|
||||||
<p></p>
|
<p>etc.</p>
|
||||||
<h3><b>Load Content</b></h3>
|
<p></p>
|
||||||
<p>After selecting Core, click Run. After RetroArch opens, click Add Content and select your compatible ROM.</p>
|
<h3><b>Load Content</b></h3>
|
||||||
<li>Nestopia > <i>YourGame.nes</i></li>
|
<p>After selecting Core, click Run. After RetroArch opens, click Add Content and select your compatible ROM.</p>
|
||||||
<li>Gambatte > <i>YourGame.gbc</i></li>
|
<ul>
|
||||||
</ul>
|
<li>Nestopia > <i>YourGame.nes</i></li>
|
||||||
<p>etc.</p>
|
<li>Gambatte > <i>YourGame.gbc</i></li>
|
||||||
<p></p>
|
</ul>
|
||||||
<h3><b><span class="fa fa-trash-o"></span> Cleanup Storage</b></h3>
|
<p>etc.</p>
|
||||||
<p>The trashcan erases your existing configuration and presets. If the Web Player doesn't start, you should click the trashcan and refresh the cache in your browser (usually F5 or Shift+F5).</p>
|
<p></p>
|
||||||
<p></p>
|
<h3><b><span class="fa fa-trash-o"></span> Cleanup Storage</b></h3>
|
||||||
<h3><b><span class="fa fa-bars"></span> Quick Menu</b></h3>
|
<p>The trashcan erases your existing configuration and presets. If the Web Player doesn't start, you should click the trashcan and refresh the cache in your browser (usually F5 or Shift+F5).</p>
|
||||||
<p>If you click on the three line icons, the Quick Menu will open here as in RetroArch.</p>
|
<p></p>
|
||||||
|
<h3><b><span class="fa fa-bars"></span> Quick Menu</b></h3>
|
||||||
</div>
|
<p>If you click on the three line icons, the Quick Menu will open here as in RetroArch.</p>
|
||||||
<div class="modal-footer">
|
</div>
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
<div class="modal-footer">
|
||||||
</div>
|
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--/.navbar content-->
|
||||||
|
</nav>
|
||||||
|
<div class="bg-inverse webplayer-container">
|
||||||
|
<div class="webplayer_border text-xs-center" id="canvas_div">
|
||||||
|
<div class="showMenu">
|
||||||
|
<button type="button" class="btn btn-link">
|
||||||
|
<span class="fa fa-chevron-down" id="icnShowMenu"></span> <span class="sr-only">Show Top Navigation</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<canvas class="webplayer" id="canvas" tabindex="1" oncontextmenu="event.preventDefault()" style="display: none"></canvas>
|
||||||
|
<img class="webplayer-preview img-fluid" src="media/canvas.png" width="960" height="720" alt="RetroArch Logo">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<script src="//code.jquery.com/jquery-3.1.0.min.js"></script>
|
||||||
</div>
|
<script src="//rawgit.com/jeresig/jquery.hotkeys/master/jquery.hotkeys.js"></script>
|
||||||
</div>
|
<script src="//cdnjs.cloudflare.com/ajax/libs/tether/1.3.4/js/tether.min.js"></script>
|
||||||
<!--/.navbar content-->
|
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.3/js/bootstrap.min.js"></script>
|
||||||
</div>
|
<script src="analytics.js"></script>
|
||||||
</nav>
|
<!--script src="//wzrd.in/standalone/browserfs@0.6.1"></script-->
|
||||||
<div class="bg-inverse webplayer-container">
|
<script src="browserfs.min.js"></script>
|
||||||
<div class="webplayer_border text-xs-center" id="canvas_div">
|
<script src="libretro.js"></script>
|
||||||
<div class="showMenu">
|
</body>
|
||||||
<button type="button" class="btn btn-link">
|
|
||||||
<span class="fa fa-chevron-down" id="icnShowMenu"></span> <span class="sr-only">Show Top Navigation</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<canvas class="webplayer" id="canvas" tabindex="1" oncontextmenu="event.preventDefault()" style="display: none"></canvas>
|
|
||||||
<img class="webplayer-preview img-fluid" src="media/canvas.png" width="960px" height="720px" alt="RetroArch Logo">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="//code.jquery.com/jquery-3.1.0.min.js"></script>
|
|
||||||
<script src="//rawgit.com/jeresig/jquery.hotkeys/master/jquery.hotkeys.js"></script>
|
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/tether/1.3.4/js/tether.min.js"></script>
|
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.3/js/bootstrap.min.js"></script>
|
|
||||||
<script src="analytics.js"></script>
|
|
||||||
<!--script src="//wzrd.in/standalone/browserfs@0.6.1"></script-->
|
|
||||||
<script src="browserfs.min.js"></script>
|
|
||||||
<script src="libretro.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -81,12 +81,22 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Disable the border around the player.
|
|
||||||
*/
|
|
||||||
canvas.webplayer {
|
canvas.webplayer {
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
width: 800px;
|
||||||
|
height: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hack to make emscripten stop messing with the canvas size while in fullscreen.
|
||||||
|
* Foiled again!
|
||||||
|
*/
|
||||||
|
:fullscreen canvas.webplayer {
|
||||||
|
min-width: 100vw;
|
||||||
|
max-width: 100vw;
|
||||||
|
min-height: 100vh;
|
||||||
|
max-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
|
|
|
@ -6,24 +6,23 @@
|
||||||
var BrowserFS = BrowserFS;
|
var BrowserFS = BrowserFS;
|
||||||
var afs;
|
var afs;
|
||||||
var initializationCount = 0;
|
var initializationCount = 0;
|
||||||
var setImmediate;
|
|
||||||
|
|
||||||
var Module = {
|
var Module = {
|
||||||
noInitialRun: true,
|
noInitialRun: true,
|
||||||
arguments: ["-v", "--menu"],
|
arguments: ["-v", "--menu"],
|
||||||
|
|
||||||
encoder: new TextEncoder(),
|
encoder: new TextEncoder(),
|
||||||
message_queue:[],
|
message_queue: [],
|
||||||
message_out:[],
|
message_out: [],
|
||||||
message_accum:"",
|
message_accum: "",
|
||||||
|
|
||||||
retroArchSend: function(msg) {
|
retroArchSend: function(msg) {
|
||||||
let bytes = this.encoder.encode(msg+"\n");
|
let bytes = this.encoder.encode(msg + "\n");
|
||||||
this.message_queue.push([bytes,0]);
|
this.message_queue.push([bytes, 0]);
|
||||||
},
|
},
|
||||||
retroArchRecv: function() {
|
retroArchRecv: function() {
|
||||||
let out = this.message_out.shift();
|
let out = this.message_out.shift();
|
||||||
if(out == null && this.message_accum != "") {
|
if (out == null && this.message_accum != "") {
|
||||||
out = this.message_accum;
|
out = this.message_accum;
|
||||||
this.message_accum = "";
|
this.message_accum = "";
|
||||||
}
|
}
|
||||||
|
@ -33,35 +32,36 @@ var Module = {
|
||||||
function(module) {
|
function(module) {
|
||||||
function stdin() {
|
function stdin() {
|
||||||
// Return ASCII code of character, or null if no input
|
// Return ASCII code of character, or null if no input
|
||||||
while(module.message_queue.length > 0){
|
while (module.message_queue.length > 0) {
|
||||||
var msg = module.message_queue[0][0];
|
var msg = module.message_queue[0][0];
|
||||||
var index = module.message_queue[0][1];
|
var index = module.message_queue[0][1];
|
||||||
if(index >= msg.length) {
|
if (index >= msg.length) {
|
||||||
module.message_queue.shift();
|
module.message_queue.shift();
|
||||||
} else {
|
} else {
|
||||||
module.message_queue[0][1] = index+1;
|
module.message_queue[0][1] = index + 1;
|
||||||
// assumption: msg is a uint8array
|
// assumption: msg is a uint8array
|
||||||
return msg[index];
|
return msg[index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function stdout(c) {
|
function stdout(c) {
|
||||||
if(c == null) {
|
if (c == null) {
|
||||||
// flush
|
// flush
|
||||||
if(module.message_accum != "") {
|
if (module.message_accum != "") {
|
||||||
module.message_out.push(module.message_accum);
|
module.message_out.push(module.message_accum);
|
||||||
module.message_accum = "";
|
module.message_accum = "";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let s = String.fromCharCode(c);
|
let s = String.fromCharCode(c);
|
||||||
if(s == "\n") {
|
if (s == "\n") {
|
||||||
if(module.message_accum != "") {
|
if (module.message_accum != "") {
|
||||||
module.message_out.push(module.message_accum);
|
module.message_out.push(module.message_accum);
|
||||||
module.message_accum = "";
|
module.message_accum = "";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
module.message_accum = module.message_accum+s;
|
module.message_accum = module.message_accum + s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,88 +69,71 @@ var Module = {
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
postRun: [],
|
postRun: [],
|
||||||
onRuntimeInitialized: function()
|
onRuntimeInitialized: function() {
|
||||||
{
|
appInitialized();
|
||||||
appInitialized();
|
},
|
||||||
},
|
print: function(text) {
|
||||||
print: function(text)
|
console.log("stdout:", text);
|
||||||
{
|
},
|
||||||
console.log(text);
|
printErr: function(text) {
|
||||||
},
|
console.log("stderr:", text);
|
||||||
printErr: function(text)
|
},
|
||||||
{
|
canvas: document.getElementById("canvas"),
|
||||||
console.error(text);
|
|
||||||
},
|
|
||||||
canvas: document.getElementById("canvas"),
|
|
||||||
totalDependencies: 0,
|
totalDependencies: 0,
|
||||||
monitorRunDependencies: function(left)
|
monitorRunDependencies: function(left) {
|
||||||
{
|
this.totalDependencies = Math.max(this.totalDependencies, left);
|
||||||
this.totalDependencies = Math.max(this.totalDependencies, left);
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function cleanupStorage()
|
function cleanupStorage() {
|
||||||
{
|
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
if (BrowserFS.FileSystem.IndexedDB.isAvailable())
|
if (BrowserFS.FileSystem.IndexedDB.isAvailable()) {
|
||||||
{
|
|
||||||
var req = indexedDB.deleteDatabase("RetroArch");
|
var req = indexedDB.deleteDatabase("RetroArch");
|
||||||
req.onsuccess = function () {
|
req.onsuccess = function() {
|
||||||
console.log("Deleted database successfully");
|
console.log("Deleted database successfully");
|
||||||
};
|
};
|
||||||
req.onerror = function () {
|
req.onerror = function() {
|
||||||
console.log("Couldn't delete database");
|
console.error("Couldn't delete database");
|
||||||
};
|
};
|
||||||
req.onblocked = function () {
|
req.onblocked = function() {
|
||||||
console.log("Couldn't delete database due to the operation being blocked");
|
console.error("Couldn't delete database due to the operation being blocked");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById("btnClean").disabled = true;
|
document.getElementById("btnClean").disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function idbfsInit()
|
function idbfsInit() {
|
||||||
{
|
|
||||||
$('#icnLocal').removeClass('fa-globe');
|
$('#icnLocal').removeClass('fa-globe');
|
||||||
$('#icnLocal').addClass('fa-spinner fa-spin');
|
$('#icnLocal').addClass('fa-spinner fa-spin');
|
||||||
var imfs = new BrowserFS.FileSystem.InMemory();
|
var imfs = new BrowserFS.FileSystem.InMemory();
|
||||||
if (BrowserFS.FileSystem.IndexedDB.isAvailable())
|
if (BrowserFS.FileSystem.IndexedDB.isAvailable()) {
|
||||||
{
|
|
||||||
afs = new BrowserFS.FileSystem.AsyncMirror(imfs,
|
afs = new BrowserFS.FileSystem.AsyncMirror(imfs,
|
||||||
new BrowserFS.FileSystem.IndexedDB(function(e, fs)
|
new BrowserFS.FileSystem.IndexedDB(function(e, fs) {
|
||||||
{
|
if (e) {
|
||||||
if (e)
|
// fallback to imfs
|
||||||
{
|
|
||||||
//fallback to imfs
|
|
||||||
afs = new BrowserFS.FileSystem.InMemory();
|
|
||||||
console.log("WEBPLAYER: error: " + e + " falling back to in-memory filesystem");
|
|
||||||
appInitialized();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// initialize afs by copying files from async storage to sync storage.
|
|
||||||
afs.initialize(function (e)
|
|
||||||
{
|
|
||||||
if (e)
|
|
||||||
{
|
|
||||||
afs = new BrowserFS.FileSystem.InMemory();
|
afs = new BrowserFS.FileSystem.InMemory();
|
||||||
console.log("WEBPLAYER: error: " + e + " falling back to in-memory filesystem");
|
console.error("WEBPLAYER: error: " + e + " falling back to in-memory filesystem");
|
||||||
appInitialized();
|
appInitialized();
|
||||||
|
} else {
|
||||||
|
// initialize afs by copying files from async storage to sync storage.
|
||||||
|
afs.initialize(function(e) {
|
||||||
|
if (e) {
|
||||||
|
afs = new BrowserFS.FileSystem.InMemory();
|
||||||
|
console.error("WEBPLAYER: error: " + e + " falling back to in-memory filesystem");
|
||||||
|
appInitialized();
|
||||||
|
} else {
|
||||||
|
idbfsSyncComplete();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
},
|
||||||
{
|
"RetroArch"));
|
||||||
idbfsSyncComplete();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RetroArch"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function idbfsSyncComplete()
|
function idbfsSyncComplete() {
|
||||||
{
|
|
||||||
$('#icnLocal').removeClass('fa-spinner').removeClass('fa-spin');
|
$('#icnLocal').removeClass('fa-spinner').removeClass('fa-spin');
|
||||||
$('#icnLocal').addClass('fa-check');
|
$('#icnLocal').addClass('fa-check');
|
||||||
console.log("WEBPLAYER: idbfs setup successful");
|
console.log("WEBPLAYER: idbfs setup successful");
|
||||||
|
@ -158,69 +141,66 @@ function idbfsSyncComplete()
|
||||||
appInitialized();
|
appInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
function appInitialized()
|
function appInitialized() {
|
||||||
{
|
/* Need to wait for the file system, the wasm runtime, and the zip download
|
||||||
/* Need to wait for the file system, the wasm runtime, and the zip download
|
to complete before enabling the Run button. */
|
||||||
to complete before enabling the Run button. */
|
initializationCount++;
|
||||||
initializationCount++;
|
if (initializationCount == 3) {
|
||||||
if (initializationCount == 3)
|
setupFileSystem("browser");
|
||||||
{
|
preLoadingComplete();
|
||||||
setupFileSystem("browser");
|
}
|
||||||
preLoadingComplete();
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function preLoadingComplete()
|
function preLoadingComplete() {
|
||||||
{
|
// Make the Preview image clickable to start RetroArch.
|
||||||
/* Make the Preview image clickable to start RetroArch. */
|
$('.webplayer-preview').addClass('loaded').click(function() {
|
||||||
$('.webplayer-preview').addClass('loaded').click(function () {
|
|
||||||
startRetroArch();
|
startRetroArch();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
document.getElementById("btnRun").disabled = false;
|
$('#btnRun').removeClass('disabled').removeAttr("disabled").click(function() {
|
||||||
$('#btnRun').removeClass('disabled');
|
startRetroArch();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var zipTOC;
|
var zipTOC;
|
||||||
|
|
||||||
function zipfsInit() {
|
function zipfsInit() {
|
||||||
// 256 MB max bundle size
|
// 256 MB max bundle size
|
||||||
let buffer = new ArrayBuffer(256*1024*1024);
|
let buffer = new ArrayBuffer(256 * 1024 * 1024);
|
||||||
let bufferView = new Uint8Array(buffer);
|
let bufferView = new Uint8Array(buffer);
|
||||||
let idx = 0;
|
let idx = 0;
|
||||||
// bundle should be in five parts (this can be changed later)
|
// bundle should be in five parts (this can be changed later)
|
||||||
Promise.all([fetch("assets/frontend/bundle.zip.aa"),
|
Promise.all([fetch("assets/frontend/bundle.zip.aa"),
|
||||||
fetch("assets/frontend/bundle.zip.ab"),
|
fetch("assets/frontend/bundle.zip.ab"),
|
||||||
fetch("assets/frontend/bundle.zip.ac"),
|
fetch("assets/frontend/bundle.zip.ac"),
|
||||||
fetch("assets/frontend/bundle.zip.ad"),
|
fetch("assets/frontend/bundle.zip.ad"),
|
||||||
fetch("assets/frontend/bundle.zip.ae")
|
fetch("assets/frontend/bundle.zip.ae")
|
||||||
]).then(function(resps) {
|
]).then(function(resps) {
|
||||||
Promise.all(resps.map((r) => r.arrayBuffer())).then(function(buffers) {
|
Promise.all(resps.map((r) => r.arrayBuffer())).then(function(buffers) {
|
||||||
for (let buf of buffers) {
|
for (let buf of buffers) {
|
||||||
if (idx+buf.byteLength > buffer.maxByteLength) {
|
if (idx + buf.byteLength > buffer.maxByteLength) {
|
||||||
console.log("WEBPLAYER: error: bundle.zip is too large");
|
console.error("WEBPLAYER: error: bundle.zip is too large");
|
||||||
}
|
}
|
||||||
bufferView.set(new Uint8Array(buf), idx, buf.byteLength);
|
bufferView.set(new Uint8Array(buf), idx, buf.byteLength);
|
||||||
idx += buf.byteLength;
|
idx += buf.byteLength;
|
||||||
}
|
}
|
||||||
BrowserFS.FileSystem.ZipFS.computeIndex(BrowserFS.BFSRequire('buffer').Buffer(new Uint8Array(buffer, 0, idx)), function(toc) {
|
BrowserFS.FileSystem.ZipFS.computeIndex(BrowserFS.BFSRequire('buffer').Buffer(new Uint8Array(buffer, 0, idx)), function(toc) {
|
||||||
zipTOC = toc;
|
zipTOC = toc;
|
||||||
appInitialized();
|
appInitialized();
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function setupFileSystem(backend)
|
|
||||||
{
|
|
||||||
/* create a mountable filesystem that will server as a root
|
|
||||||
mountpoint for browserfs */
|
|
||||||
var mfs = new BrowserFS.FileSystem.MountableFileSystem();
|
|
||||||
|
|
||||||
/* create an XmlHttpRequest filesystem for the bundled data */
|
function setupFileSystem(backend) {
|
||||||
|
// create a mountable filesystem that will server as a root mountpoint for browserfs
|
||||||
|
var mfs = new BrowserFS.FileSystem.MountableFileSystem();
|
||||||
|
|
||||||
|
// create an XmlHttpRequest filesystem for the bundled data
|
||||||
var xfs1 = new BrowserFS.FileSystem.ZipFS(zipTOC);
|
var xfs1 = new BrowserFS.FileSystem.ZipFS(zipTOC);
|
||||||
/* create an XmlHttpRequest filesystem for core assets */
|
// create an XmlHttpRequest filesystem for core assets
|
||||||
var xfs2 = new BrowserFS.FileSystem.XmlHttpRequest
|
var xfs2 = new BrowserFS.FileSystem.XmlHttpRequest(".index-xhr", "assets/cores/");
|
||||||
(".index-xhr", "assets/cores/");
|
|
||||||
|
|
||||||
console.log("WEBPLAYER: initializing filesystem: " + backend);
|
console.log("WEBPLAYER: initializing filesystem: " + backend);
|
||||||
mfs.mount('/home/web_user/retroarch/userdata', afs);
|
mfs.mount('/home/web_user/retroarch/userdata', afs);
|
||||||
|
@ -229,75 +209,81 @@ function setupFileSystem(backend)
|
||||||
mfs.mount('/home/web_user/retroarch/userdata/content/downloads', xfs2);
|
mfs.mount('/home/web_user/retroarch/userdata/content/downloads', xfs2);
|
||||||
BrowserFS.initialize(mfs);
|
BrowserFS.initialize(mfs);
|
||||||
var BFS = new BrowserFS.EmscriptenFS(Module.FS, Module.PATH, Module.ERRNO_CODES);
|
var BFS = new BrowserFS.EmscriptenFS(Module.FS, Module.PATH, Module.ERRNO_CODES);
|
||||||
Module.FS.mount(BFS, {root: '/home'}, '/home');
|
Module.FS.mount(BFS, {
|
||||||
|
root: '/home'
|
||||||
|
}, '/home');
|
||||||
console.log("WEBPLAYER: " + backend + " filesystem initialization successful");
|
console.log("WEBPLAYER: " + backend + " filesystem initialization successful");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Retrieve the value of the given GET parameter.
|
||||||
* Retrieve the value of the given GET parameter.
|
|
||||||
*/
|
|
||||||
function getParam(name) {
|
function getParam(name) {
|
||||||
var results = new RegExp('[?&]' + name + '=([^&#]*)').exec(window.location.href);
|
var results = new RegExp('[?&]' + name + '=([^&#]*)').exec(window.location.href);
|
||||||
if (results) {
|
if (results) {
|
||||||
return results[1] || null;
|
return results[1] || null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function startRetroArch()
|
function startRetroArch() {
|
||||||
{
|
|
||||||
$('.webplayer').show();
|
$('.webplayer').show();
|
||||||
$('.webplayer-preview').hide();
|
$('.webplayer-preview').hide();
|
||||||
document.getElementById("btnRun").disabled = true;
|
document.getElementById("btnRun").disabled = true;
|
||||||
|
|
||||||
$('#btnFullscreen').removeClass('disabled');
|
$('#btnAdd').removeClass("disabled").removeAttr("disabled").click(function() {
|
||||||
$('#btnMenu').removeClass('disabled');
|
$('#btnRom').click();
|
||||||
$('#btnAdd').removeClass('disabled');
|
});
|
||||||
$('#btnRom').removeClass('disabled');
|
$('#btnRom').removeAttr("disabled").change(function(e) {
|
||||||
|
selectFiles(e.target.files);
|
||||||
|
});
|
||||||
|
$('#btnMenu').removeClass("disabled").removeAttr("disabled").click(function() {
|
||||||
|
Module._cmd_toggle_menu();
|
||||||
|
Module.canvas.focus();
|
||||||
|
});
|
||||||
|
$('#btnFullscreen').removeClass("disabled").removeAttr("disabled").click(function() {
|
||||||
|
Module.requestFullscreen(false);
|
||||||
|
Module.canvas.focus();
|
||||||
|
});
|
||||||
|
|
||||||
document.getElementById("btnAdd").disabled = false;
|
Module.canvas.focus();
|
||||||
document.getElementById("btnRom").disabled = false;
|
Module.canvas.addEventListener("pointerdown", function() {
|
||||||
document.getElementById("btnMenu").disabled = false;
|
Module.canvas.focus();
|
||||||
document.getElementById("btnFullscreen").disabled = false;
|
}, false);
|
||||||
|
Module.callMain(Module.arguments);
|
||||||
Module["canvas"] = document.getElementById("canvas");
|
|
||||||
Module["canvas"].addEventListener("click", () => Module["canvas"].focus());
|
|
||||||
Module['callMain'](Module['arguments']);
|
|
||||||
Module['resumeMainLoop']();
|
|
||||||
Module['canvas'].focus();
|
|
||||||
}
|
}
|
||||||
function selectFiles(files)
|
|
||||||
{
|
function selectFiles(files) {
|
||||||
$('#btnAdd').addClass('disabled');
|
$('#btnAdd').addClass('disabled');
|
||||||
$('#icnAdd').removeClass('fa-plus');
|
$('#icnAdd').removeClass('fa-plus');
|
||||||
$('#icnAdd').addClass('fa-spinner spinning');
|
$('#icnAdd').addClass('fa-spinner spinning');
|
||||||
var count = files.length;
|
var count = files.length;
|
||||||
|
|
||||||
for (var i = 0; i < count; i++)
|
for (var i = 0; i < count; i++) {
|
||||||
{
|
|
||||||
filereader = new FileReader();
|
filereader = new FileReader();
|
||||||
filereader.file_name = files[i].name;
|
filereader.file_name = files[i].name;
|
||||||
filereader.readAsArrayBuffer(files[i]);
|
filereader.readAsArrayBuffer(files[i]);
|
||||||
filereader.onload = function(){uploadData(this.result, this.file_name)};
|
filereader.onload = function() {
|
||||||
filereader.onloadend = function(evt)
|
uploadData(this.result, this.file_name)
|
||||||
{
|
};
|
||||||
|
filereader.onloadend = function(evt) {
|
||||||
console.log("WEBPLAYER: file: " + this.file_name + " upload complete");
|
console.log("WEBPLAYER: file: " + this.file_name + " upload complete");
|
||||||
if (evt.target.readyState == FileReader.DONE)
|
if (evt.target.readyState == FileReader.DONE) {
|
||||||
{
|
|
||||||
$('#btnAdd').removeClass('disabled');
|
$('#btnAdd').removeClass('disabled');
|
||||||
$('#icnAdd').removeClass('fa-spinner spinning');
|
$('#icnAdd').removeClass('fa-spinner spinning');
|
||||||
$('#icnAdd').addClass('fa-plus');
|
$('#icnAdd').addClass('fa-plus');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function uploadData(data,name)
|
function uploadData(data, name) {
|
||||||
{
|
|
||||||
var dataView = new Uint8Array(data);
|
var dataView = new Uint8Array(data);
|
||||||
Module.FS.createDataFile('/', name, dataView, true, false);
|
Module.FS.createDataFile('/', name, dataView, true, false);
|
||||||
|
|
||||||
var data = Module.FS.readFile(name,{ encoding: 'binary' });
|
var data = Module.FS.readFile(name, {
|
||||||
Module.FS.writeFile('/home/web_user/retroarch/userdata/content/' + name, data ,{ encoding: 'binary' });
|
encoding: 'binary'
|
||||||
|
});
|
||||||
|
Module.FS.writeFile('/home/web_user/retroarch/userdata/content/' + name, data, {
|
||||||
|
encoding: 'binary'
|
||||||
|
});
|
||||||
Module.FS.unlink(name);
|
Module.FS.unlink(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,8 +292,7 @@ function switchCore(corename) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchStorage(backend) {
|
function switchStorage(backend) {
|
||||||
if (backend != localStorage.getItem("backend"))
|
if (backend != localStorage.getItem("backend")) {
|
||||||
{
|
|
||||||
localStorage.setItem("backend", backend);
|
localStorage.setItem("backend", backend);
|
||||||
location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
|
@ -315,21 +300,24 @@ function switchStorage(backend) {
|
||||||
|
|
||||||
// When the browser has loaded everything.
|
// When the browser has loaded everything.
|
||||||
$(function() {
|
$(function() {
|
||||||
// Enable all available ToolTips.
|
// Enable data clear
|
||||||
|
$('#btnClean').click(function() {
|
||||||
|
cleanupStorage();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Enable all available ToolTips.
|
||||||
$('.tooltip-enable').tooltip({
|
$('.tooltip-enable').tooltip({
|
||||||
placement: 'right'
|
placement: 'right'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Allow hiding the top menu.
|
// Allow hiding the top menu.
|
||||||
$('.showMenu').hide();
|
$('.showMenu').hide();
|
||||||
$('#btnHideMenu, .showMenu').click(function () {
|
$('#btnHideMenu, .showMenu').click(function() {
|
||||||
$('nav').slideToggle('slow');
|
$('nav').slideToggle('slow');
|
||||||
$('.showMenu').toggle('slow');
|
$('.showMenu').toggle('slow');
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
// Attempt to disable some default browser keys.
|
||||||
* Attempt to disable some default browser keys.
|
|
||||||
*/
|
|
||||||
var keys = {
|
var keys = {
|
||||||
9: "tab",
|
9: "tab",
|
||||||
13: "enter",
|
13: "enter",
|
||||||
|
@ -351,20 +339,20 @@ $(function() {
|
||||||
116: "F5",
|
116: "F5",
|
||||||
117: "F6",
|
117: "F6",
|
||||||
118: "F7",
|
118: "F7",
|
||||||
119: "F8",
|
119: "F8",
|
||||||
120: "F9",
|
120: "F9",
|
||||||
121: "F10",
|
121: "F10",
|
||||||
122: "F11",
|
122: "F11",
|
||||||
123: "F12"
|
123: "F12"
|
||||||
};
|
};
|
||||||
window.addEventListener('keydown', function (e) {
|
window.addEventListener('keydown', function(e) {
|
||||||
if (keys[e.which]) {
|
if (keys[e.which]) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Switch the core when selecting one.
|
// Switch the core when selecting one.
|
||||||
$('#core-selector a').click(function () {
|
$('#core-selector a').click(function() {
|
||||||
var coreChoice = $(this).data('core');
|
var coreChoice = $(this).data('core');
|
||||||
switchCore(coreChoice);
|
switchCore(coreChoice);
|
||||||
});
|
});
|
||||||
|
@ -381,8 +369,8 @@ function loadCore(core) {
|
||||||
var coreTitle = $('#core-selector a[data-core="' + core + '"]').addClass('active').text();
|
var coreTitle = $('#core-selector a[data-core="' + core + '"]').addClass('active').text();
|
||||||
$('#dropdownMenu1').text(coreTitle);
|
$('#dropdownMenu1').text(coreTitle);
|
||||||
// Load the Core's related JavaScript.
|
// Load the Core's related JavaScript.
|
||||||
import("./"+core+"_libretro.js").then(script => {
|
import("./" + core + "_libretro.js").then(script => {
|
||||||
script.default(Module).then(mod => {
|
script.default(Module).then(mod => {
|
||||||
Module = mod;
|
Module = mod;
|
||||||
$('#icnRun').removeClass('fa-spinner').removeClass('fa-spin');
|
$('#icnRun').removeClass('fa-spinner').removeClass('fa-spin');
|
||||||
$('#icnRun').addClass('fa-play');
|
$('#icnRun').addClass('fa-play');
|
||||||
|
@ -390,18 +378,12 @@ function loadCore(core) {
|
||||||
$('#lblLocal').addClass('active');
|
$('#lblLocal').addClass('active');
|
||||||
idbfsInit();
|
idbfsInit();
|
||||||
zipfsInit();
|
zipfsInit();
|
||||||
}).catch(err => { console.error("Couldn't instantiate module",err); throw err; });
|
}).catch(err => {
|
||||||
}).catch(err => { console.error("Couldn't load script",err); throw err; });
|
console.error("Couldn't instantiate module", err);
|
||||||
}
|
throw err;
|
||||||
|
});
|
||||||
function keyPress(k)
|
}).catch(err => {
|
||||||
{
|
console.error("Couldn't load script", err);
|
||||||
function kp(k, event) {
|
throw err;
|
||||||
var oEvent = new KeyboardEvent(event, { code: k });
|
});
|
||||||
|
}
|
||||||
document.dispatchEvent(oEvent);
|
|
||||||
document.getElementById('canvas').focus();
|
|
||||||
}
|
|
||||||
kp(k, "keydown");
|
|
||||||
setTimeout(function(){kp(k, "keyup")}, 50);
|
|
||||||
}
|
|
|
@ -3945,6 +3945,9 @@ bool command_event(enum event_command cmd, void *data)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
case CMD_EVENT_RELOAD_CONFIG:
|
||||||
|
config_load(global_get_ptr());
|
||||||
|
break;
|
||||||
case CMD_EVENT_DSP_FILTER_INIT:
|
case CMD_EVENT_DSP_FILTER_INIT:
|
||||||
#ifdef HAVE_DSP_FILTER
|
#ifdef HAVE_DSP_FILTER
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue