mirror of
https://github.com/libretro/RetroArch
synced 2025-04-09 21:45:45 +00:00
Merge pull request #303 from libretro/emscripten
Emscripten/Javascript port
This commit is contained in:
commit
7d90ff4011
159
Makefile.emscripten
Normal file
159
Makefile.emscripten
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
TARGET = retroarch.js
|
||||||
|
|
||||||
|
OBJ = frontend/frontend_emscripten.o \
|
||||||
|
retroarch.o \
|
||||||
|
file.o \
|
||||||
|
file_path.o \
|
||||||
|
driver.o \
|
||||||
|
conf/config_file.o \
|
||||||
|
settings.o \
|
||||||
|
hash.o \
|
||||||
|
dynamic.o \
|
||||||
|
dynamic_dummy.o \
|
||||||
|
message.o \
|
||||||
|
rewind.o \
|
||||||
|
movie.o \
|
||||||
|
gfx/gfx_common.o \
|
||||||
|
input/input_common.o \
|
||||||
|
input/rwebinput_input.o \
|
||||||
|
core_options.o \
|
||||||
|
patch.o \
|
||||||
|
compat/compat.o \
|
||||||
|
compat/rxml/rxml.o \
|
||||||
|
screenshot.o \
|
||||||
|
cheats.o \
|
||||||
|
audio/utils.o \
|
||||||
|
audio/rwebaudio.o \
|
||||||
|
input/overlay.o \
|
||||||
|
fifo_buffer.o \
|
||||||
|
gfx/scaler/scaler.o \
|
||||||
|
gfx/scaler/pixconv.o \
|
||||||
|
gfx/scaler/scaler_int.o \
|
||||||
|
gfx/scaler/filter.o \
|
||||||
|
gfx/state_tracker.o \
|
||||||
|
gfx/shader_parse.o \
|
||||||
|
gfx/fonts/fonts.o \
|
||||||
|
gfx/fonts/bitmapfont.o \
|
||||||
|
gfx/image.o \
|
||||||
|
audio/resampler.o \
|
||||||
|
audio/sinc.o \
|
||||||
|
audio/null.o \
|
||||||
|
performance.o
|
||||||
|
|
||||||
|
HAVE_OPENGL = 1
|
||||||
|
HAVE_RGUI = 1
|
||||||
|
HAVE_SDL = 0
|
||||||
|
HAVE_ZLIB = 1
|
||||||
|
HAVE_FBO = 1
|
||||||
|
WANT_MINIZ = 1
|
||||||
|
MEMORY = 67108864
|
||||||
|
LTO = 0
|
||||||
|
FAST_DOUBLES = 1
|
||||||
|
|
||||||
|
ifneq ($(NATIVE_ZLIB),)
|
||||||
|
WANT_MINIZ = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
libretro = libretro_emscripten.bc
|
||||||
|
|
||||||
|
LIBS = -lm
|
||||||
|
DEFINES = -DHAVE_SCREENSHOTS -DHAVE_NULLAUDIO -DHAVE_BSV_MOVIE -DPACKAGE_VERSION=\"0.9.9.3\"
|
||||||
|
LDFLAGS = -L. -s TOTAL_MEMORY=$(MEMORY) --js-library emscripten/library_rwebaudio.js --js-library emscripten/library_rwebinput.js
|
||||||
|
|
||||||
|
ifeq ($(PERF_TEST), 1)
|
||||||
|
DEFINES += -DPERF_TEST
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HAVE_RGUI), 1)
|
||||||
|
DEFINES += -DHAVE_RGUI
|
||||||
|
OBJ += frontend/menu/menu_common.o frontend/menu/rgui.o frontend/menu/history.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HAVE_SDL), 1)
|
||||||
|
OBJ += input/sdl_input.o
|
||||||
|
LIBS += -lSDL
|
||||||
|
DEFINES += -ISDL -DHAVE_SDL
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HAVE_OPENGL), 1)
|
||||||
|
OBJ += gfx/gl.o gfx/math/matrix.o gfx/fonts/gl_font.o gfx/fonts/gl_raster_font.o gfx/gfx_context.o gfx/context/emscriptenegl_ctx.o gfx/shader_glsl.o gfx/glsym/rglgen.o gfx/glsym/glsym_es2.o
|
||||||
|
DEFINES += -DHAVE_OPENGL -DHAVE_OPENGLES -DHAVE_OPENGLES2 -DHAVE_EGL -DHAVE_OVERLAY -DHAVE_GLSL
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HAVE_ZLIB), 1)
|
||||||
|
OBJ += gfx/rpng/rpng.o file_extract.o
|
||||||
|
DEFINES += -DHAVE_ZLIB
|
||||||
|
ifeq ($(WANT_MINIZ), 1)
|
||||||
|
OBJ += deps/miniz/miniz.o
|
||||||
|
DEFINES += -DWANT_MINIZ
|
||||||
|
else
|
||||||
|
LIBS += -lz
|
||||||
|
DEFINES += -DHAVE_ZLIB_DEFLATE
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HAVE_FBO), 1)
|
||||||
|
DEFINES += -DHAVE_FBO
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(V), 1)
|
||||||
|
Q := @
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(DEBUG), 1)
|
||||||
|
LDFLAGS += -O0 -g
|
||||||
|
CFLAGS += -O0 -g
|
||||||
|
else
|
||||||
|
LDFLAGS += -O2
|
||||||
|
# WARNING: some optimizations can break some cores (ex: LTO breaks tyrquake)
|
||||||
|
ifeq ($(FAST_DOUBLES), 1)
|
||||||
|
LDFLAGS += -s DOUBLE_MODE=0
|
||||||
|
endif
|
||||||
|
ifeq ($(LTO), 1)
|
||||||
|
LDFLAGS += --llvm-lto 3
|
||||||
|
endif
|
||||||
|
CFLAGS += -O2
|
||||||
|
endif
|
||||||
|
|
||||||
|
CFLAGS += -Wall -Wno-unused-result -Wno-unused-variable -I. -std=gnu99
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(OBJ)
|
||||||
|
@$(if $(Q), $(shell echo echo LD $@),)
|
||||||
|
$(Q)$(LD) -o $@ $(OBJ) $(libretro) $(LIBS) $(LDFLAGS)
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
@$(if $(Q), $(shell echo echo CC $<),)
|
||||||
|
$(Q)$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||||
|
|
||||||
|
%.o: %.cpp
|
||||||
|
@$(if $(Q), $(shell echo echo CXX $<),)
|
||||||
|
$(Q)$(CXX) $(CXXFLAGS) $(DEFINES) -c -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o
|
||||||
|
rm -f deps/miniz/*.o
|
||||||
|
rm -f frontend/*.o
|
||||||
|
rm -f frontend/menu/*.o
|
||||||
|
rm -f audio/*.o
|
||||||
|
rm -f audio/xaudio-c/*.o
|
||||||
|
rm -f compat/*.o
|
||||||
|
rm -f compat/rxml/*.o
|
||||||
|
rm -f conf/*.o
|
||||||
|
rm -f gfx/scaler/*.o
|
||||||
|
rm -f gfx/*.o
|
||||||
|
rm -f gfx/d3d9/*.o
|
||||||
|
rm -f gfx/context/*.o
|
||||||
|
rm -f gfx/math/*.o
|
||||||
|
rm -f gfx/fonts/*.o
|
||||||
|
rm -f gfx/py_state/*.o
|
||||||
|
rm -f gfx/rpng/*.o
|
||||||
|
rm -f gfx/glsym/*.o
|
||||||
|
rm -f record/*.o
|
||||||
|
rm -f input/*.o
|
||||||
|
rm -f tools/*.o
|
||||||
|
rm -f $(TARGET)
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
90
audio/rwebaudio.c
Normal file
90
audio/rwebaudio.c
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2010-2013 - Michael Lelli
|
||||||
|
*
|
||||||
|
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../driver.h"
|
||||||
|
#include "../general.h"
|
||||||
|
|
||||||
|
#include "../emscripten/RWebAudio.h"
|
||||||
|
|
||||||
|
static void ra_free(void *data)
|
||||||
|
{
|
||||||
|
RWebAudioFree();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *ra_init(const char *device, unsigned rate, unsigned latency)
|
||||||
|
{
|
||||||
|
(void)device;
|
||||||
|
(void)rate;
|
||||||
|
void *data = RWebAudioInit(latency);
|
||||||
|
if (data)
|
||||||
|
g_settings.audio.out_rate = RWebAudioSampleRate();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t ra_write(void *data, const void *buf, size_t size)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
return RWebAudioWrite(buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ra_stop(void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
return RWebAudioStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ra_set_nonblock_state(void *data, bool state)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
RWebAudioSetNonblockState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ra_start(void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
return RWebAudioStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ra_use_float(void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t ra_write_avail(void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
return RWebAudioWriteAvail();
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t ra_buffer_size(void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
return RWebAudioBufferSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
const audio_driver_t audio_rwebaudio = {
|
||||||
|
ra_init,
|
||||||
|
ra_write,
|
||||||
|
ra_stop,
|
||||||
|
ra_start,
|
||||||
|
ra_set_nonblock_state,
|
||||||
|
ra_free,
|
||||||
|
ra_use_float,
|
||||||
|
"rwebaudio",
|
||||||
|
ra_write_avail,
|
||||||
|
ra_buffer_size,
|
||||||
|
};
|
||||||
|
|
@ -63,6 +63,7 @@ enum
|
|||||||
AUDIO_PS3,
|
AUDIO_PS3,
|
||||||
AUDIO_XENON360,
|
AUDIO_XENON360,
|
||||||
AUDIO_WII,
|
AUDIO_WII,
|
||||||
|
AUDIO_RWEBAUDIO,
|
||||||
AUDIO_NULL,
|
AUDIO_NULL,
|
||||||
|
|
||||||
INPUT_ANDROID,
|
INPUT_ANDROID,
|
||||||
@ -77,6 +78,7 @@ enum
|
|||||||
INPUT_LINUXRAW,
|
INPUT_LINUXRAW,
|
||||||
INPUT_APPLE,
|
INPUT_APPLE,
|
||||||
INPUT_QNX,
|
INPUT_QNX,
|
||||||
|
INPUT_RWEBINPUT,
|
||||||
INPUT_NULL
|
INPUT_NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -130,6 +132,8 @@ enum
|
|||||||
#define AUDIO_DEFAULT_DRIVER AUDIO_SL
|
#define AUDIO_DEFAULT_DRIVER AUDIO_SL
|
||||||
#elif defined(HAVE_DSOUND)
|
#elif defined(HAVE_DSOUND)
|
||||||
#define AUDIO_DEFAULT_DRIVER AUDIO_DSOUND
|
#define AUDIO_DEFAULT_DRIVER AUDIO_DSOUND
|
||||||
|
#elif defined(EMSCRIPTEN)
|
||||||
|
#define AUDIO_DEFAULT_DRIVER AUDIO_RWEBAUDIO
|
||||||
#elif defined(HAVE_SDL)
|
#elif defined(HAVE_SDL)
|
||||||
#define AUDIO_DEFAULT_DRIVER AUDIO_SDL
|
#define AUDIO_DEFAULT_DRIVER AUDIO_SDL
|
||||||
#elif defined(HAVE_XAUDIO)
|
#elif defined(HAVE_XAUDIO)
|
||||||
@ -152,6 +156,8 @@ enum
|
|||||||
#define INPUT_DEFAULT_DRIVER INPUT_ANDROID
|
#define INPUT_DEFAULT_DRIVER INPUT_ANDROID
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
#define INPUT_DEFAULT_DRIVER INPUT_DINPUT
|
#define INPUT_DEFAULT_DRIVER INPUT_DINPUT
|
||||||
|
#elif defined(EMSCRIPTEN)
|
||||||
|
#define INPUT_DEFAULT_DRIVER INPUT_RWEBINPUT
|
||||||
#elif defined(HAVE_SDL)
|
#elif defined(HAVE_SDL)
|
||||||
#define INPUT_DEFAULT_DRIVER INPUT_SDL
|
#define INPUT_DEFAULT_DRIVER INPUT_SDL
|
||||||
#elif defined(__CELLOS_LV2__)
|
#elif defined(__CELLOS_LV2__)
|
||||||
|
6
driver.c
6
driver.c
@ -84,6 +84,9 @@ static const audio_driver_t *audio_drivers[] = {
|
|||||||
#ifdef GEKKO
|
#ifdef GEKKO
|
||||||
&audio_gx,
|
&audio_gx,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
&audio_rwebaudio,
|
||||||
|
#endif
|
||||||
#ifdef HAVE_NULLAUDIO
|
#ifdef HAVE_NULLAUDIO
|
||||||
&audio_null,
|
&audio_null,
|
||||||
#endif
|
#endif
|
||||||
@ -165,6 +168,9 @@ static const input_driver_t *input_drivers[] = {
|
|||||||
#ifdef __BLACKBERRY_QNX__
|
#ifdef __BLACKBERRY_QNX__
|
||||||
&input_qnx,
|
&input_qnx,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
&input_rwebinput,
|
||||||
|
#endif
|
||||||
#ifdef HAVE_NULLINPUT
|
#ifdef HAVE_NULLINPUT
|
||||||
&input_null,
|
&input_null,
|
||||||
#endif
|
#endif
|
||||||
|
2
driver.h
2
driver.h
@ -511,6 +511,7 @@ extern const audio_driver_t audio_coreaudio;
|
|||||||
extern const audio_driver_t audio_xenon360;
|
extern const audio_driver_t audio_xenon360;
|
||||||
extern const audio_driver_t audio_ps3;
|
extern const audio_driver_t audio_ps3;
|
||||||
extern const audio_driver_t audio_gx;
|
extern const audio_driver_t audio_gx;
|
||||||
|
extern const audio_driver_t audio_rwebaudio;
|
||||||
extern const audio_driver_t audio_null;
|
extern const audio_driver_t audio_null;
|
||||||
extern const video_driver_t video_gl;
|
extern const video_driver_t video_gl;
|
||||||
extern const video_driver_t video_psp1;
|
extern const video_driver_t video_psp1;
|
||||||
@ -536,6 +537,7 @@ extern const input_driver_t input_xinput;
|
|||||||
extern const input_driver_t input_linuxraw;
|
extern const input_driver_t input_linuxraw;
|
||||||
extern const input_driver_t input_apple;
|
extern const input_driver_t input_apple;
|
||||||
extern const input_driver_t input_qnx;
|
extern const input_driver_t input_qnx;
|
||||||
|
extern const input_driver_t input_rwebinput;
|
||||||
extern const input_driver_t input_null;
|
extern const input_driver_t input_null;
|
||||||
|
|
||||||
#include "driver_funcs.h"
|
#include "driver_funcs.h"
|
||||||
|
28
emscripten/RWebAudio.h
Normal file
28
emscripten/RWebAudio.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2010-2013 - Michael Lelli
|
||||||
|
*
|
||||||
|
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
unsigned RWebAudioSampleRate(void);
|
||||||
|
void *RWebAudioInit(unsigned latency);
|
||||||
|
ssize_t RWebAudioWrite(const void *buf, size_t size);
|
||||||
|
bool RWebAudioStop(void);
|
||||||
|
bool RWebAudioStart(void);
|
||||||
|
void RWebAudioSetNonblockState(bool state);
|
||||||
|
void RWebAudioFree(void);
|
||||||
|
size_t RWebAudioWriteAvail(void);
|
||||||
|
size_t RWebAudioBufferSize(void);
|
29
emscripten/RWebInput.h
Normal file
29
emscripten/RWebInput.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2010-2013 - Michael Lelli
|
||||||
|
*
|
||||||
|
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef struct rwebinput_state
|
||||||
|
{
|
||||||
|
char keys[32];
|
||||||
|
int mouse_x;
|
||||||
|
int mouse_y;
|
||||||
|
char mouse_l;
|
||||||
|
char mouse_r;
|
||||||
|
} rwebinput_state_t;
|
||||||
|
|
||||||
|
int RWebInputInit(void);
|
||||||
|
rwebinput_state_t *RWebInputPoll(int context);
|
||||||
|
void RWebInputDestroy(int context);
|
166
emscripten/library_rwebaudio.js
Normal file
166
emscripten/library_rwebaudio.js
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
//"use strict";
|
||||||
|
|
||||||
|
var LibraryRWebAudio = {
|
||||||
|
$RA__deps: ['$Browser', 'usleep'],
|
||||||
|
$RA: {
|
||||||
|
BUFFER_SIZE: 256,
|
||||||
|
|
||||||
|
context: null,
|
||||||
|
buffers: [],
|
||||||
|
numBuffers: 0,
|
||||||
|
bufIndex: 0,
|
||||||
|
bufOffset: 0,
|
||||||
|
startTime: 0,
|
||||||
|
nonblock: false,
|
||||||
|
currentTimeWorkaround: false,
|
||||||
|
|
||||||
|
setStartTime: function() {
|
||||||
|
if (RA.context.currentTime) {
|
||||||
|
RA.startTime = window['performance']['now']() - RA.context.currentTime * 1000;
|
||||||
|
var time1 = RA.context.currentTime;
|
||||||
|
_usleep(50);
|
||||||
|
if (time1 === RA.context.currentTime) {
|
||||||
|
RA.currentTimeWorkaround = true;
|
||||||
|
if (RA.startTime === 0) throw 'startTime is 0';
|
||||||
|
}
|
||||||
|
Module["resumeMainLoop"]();
|
||||||
|
} else window['setTimeout'](RA.setStartTime, 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
getCurrentPerfTime: function() {
|
||||||
|
if (!RA.currentTimeWorkaround) return RA.context.currentTime;
|
||||||
|
else if (RA.startTime) return (window['performance']['now']() - RA.startTime) / 1000;
|
||||||
|
else throw 'getCurrentPerfTime() called before start time set';
|
||||||
|
},
|
||||||
|
|
||||||
|
process: function(queueBuffers) {
|
||||||
|
var currentTime = RA.getCurrentPerfTime();
|
||||||
|
for (var i = 0; i < RA.bufIndex; i++) {
|
||||||
|
if (RA.buffers[i].endTime < currentTime) {
|
||||||
|
var buf = RA.buffers.splice(i, 1);
|
||||||
|
RA.buffers[RA.numBuffers - 1] = buf[0];
|
||||||
|
i--;
|
||||||
|
RA.bufIndex--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
fillBuffer: function(buf, samples) {
|
||||||
|
var count = 0;
|
||||||
|
var leftBuffer = RA.buffers[RA.bufIndex].getChannelData(0);
|
||||||
|
var rightBuffer = RA.buffers[RA.bufIndex].getChannelData(1);
|
||||||
|
while (samples && RA.bufOffset !== RA.BUFFER_SIZE) {
|
||||||
|
leftBuffer[RA.bufOffset] = {{{ makeGetValue('buf', 'count * 8', 'float') }}};
|
||||||
|
rightBuffer[RA.bufOffset] = {{{ makeGetValue('buf', 'count * 8 + 4', 'float') }}};
|
||||||
|
RA.bufOffset++;
|
||||||
|
count++;
|
||||||
|
samples--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
|
||||||
|
queueAudio: function() {
|
||||||
|
var index = RA.bufIndex;
|
||||||
|
|
||||||
|
var startTime;
|
||||||
|
if (RA.bufIndex) startTime = RA.buffers[RA.bufIndex - 1].endTime;
|
||||||
|
else startTime = RA.context.currentTime;
|
||||||
|
RA.buffers[index].endTime = startTime + RA.buffers[index].duration;
|
||||||
|
|
||||||
|
var bufferSource = RA.context.createBufferSource();
|
||||||
|
bufferSource.buffer = RA.buffers[index];
|
||||||
|
bufferSource.connect(RA.context.destination);
|
||||||
|
bufferSource.start(startTime);
|
||||||
|
|
||||||
|
RA.bufIndex++;
|
||||||
|
RA.bufOffset = 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
block: function() {
|
||||||
|
do {
|
||||||
|
RA.process();
|
||||||
|
} while (RA.bufIndex === RA.numBuffers - 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
RWebAudioInit: function(latency) {
|
||||||
|
var ac = window['AudioContext'] || window['webkitAudioContext'];
|
||||||
|
|
||||||
|
if (!ac) return 0;
|
||||||
|
|
||||||
|
RA.context = new ac();
|
||||||
|
|
||||||
|
RA.numBuffers = ((latency * RA.context.sampleRate) / (1000 * RA.BUFFER_SIZE))|0;
|
||||||
|
if (RA.numBuffers < 2) RA.numBuffers = 2;
|
||||||
|
|
||||||
|
for (var i = 0; i < RA.numBuffers; i++) RA.buffers[i] = RA.context.createBuffer(2, RA.BUFFER_SIZE, RA.context.sampleRate);
|
||||||
|
|
||||||
|
RA.nonblock = false;
|
||||||
|
RA.startTime = 0;
|
||||||
|
// chrome hack to get currentTime running
|
||||||
|
RA.context.createGain();
|
||||||
|
window['setTimeout'](RA.setStartTime, 0);
|
||||||
|
Module["pauseMainLoop"]();
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
|
|
||||||
|
RWebAudioSampleRate: function() {
|
||||||
|
return RA.context.sampleRate;
|
||||||
|
},
|
||||||
|
|
||||||
|
RWebAudioWrite: function (buf, size) {
|
||||||
|
RA.process();
|
||||||
|
var samples = size / 8;
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
while (samples) {
|
||||||
|
var fill = RA.fillBuffer(buf, samples);
|
||||||
|
samples -= fill;
|
||||||
|
count += fill;
|
||||||
|
buf += fill * 8;
|
||||||
|
|
||||||
|
if (RA.bufOffset === RA.BUFFER_SIZE) {
|
||||||
|
if (RA.bufIndex === RA.numBuffers - 1) {
|
||||||
|
if (RA.nonblock) break;
|
||||||
|
else RA.block();
|
||||||
|
}
|
||||||
|
RA.queueAudio();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count * 8;
|
||||||
|
},
|
||||||
|
|
||||||
|
RWebAudioStop: function() {
|
||||||
|
RA.bufIndex = 0;
|
||||||
|
RA.bufOffset = 0;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
RWebAudioStart: function() {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
RWebAudioSetNonblockState: function(state) {
|
||||||
|
RA.nonblock = state;
|
||||||
|
},
|
||||||
|
|
||||||
|
RWebAudioFree: function() {
|
||||||
|
RA.bufIndex = 0;
|
||||||
|
RA.bufOffset = 0;
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
|
||||||
|
RWebAudioBufferSize: function() {
|
||||||
|
return RA.numBuffers * RA.BUFFER_SIZE + RA.BUFFER_SIZE;
|
||||||
|
},
|
||||||
|
|
||||||
|
RWebAudioWriteAvail: function() {
|
||||||
|
RA.process();
|
||||||
|
return ((RA.numBuffers - RA.bufIndex) * RA.BUFFER_SIZE - RA.bufOffset) * 8;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
autoAddDeps(LibraryRWebAudio, '$RA');
|
||||||
|
mergeInto(LibraryManager.library, LibraryRWebAudio);
|
108
emscripten/library_rwebinput.js
Normal file
108
emscripten/library_rwebinput.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
//"use strict";
|
||||||
|
|
||||||
|
var LibraryRWebInput = {
|
||||||
|
$RI__deps: ['$Browser'],
|
||||||
|
$RI: {
|
||||||
|
temp: null,
|
||||||
|
contexts: [],
|
||||||
|
|
||||||
|
eventHandler: function(event) {
|
||||||
|
var i;
|
||||||
|
switch (event.type) {
|
||||||
|
case 'mousemove':
|
||||||
|
var x = event['movementX'] || event['mozMovementX'] || event['webkitMovementX'];
|
||||||
|
var y = event['movementY'] || event['mozMovementY'] || event['webkitMovementY'];
|
||||||
|
for (i = 0; i < RI.contexts.length; i++) {
|
||||||
|
var oldX = {{{ makeGetValue('RI.contexts[i].state', '32', 'i32') }}};
|
||||||
|
var oldY = {{{ makeGetValue('RI.contexts[i].state', '36', 'i32') }}};
|
||||||
|
x += oldX;
|
||||||
|
y += oldY;
|
||||||
|
{{{ makeSetValue('RI.contexts[i].state', '32', 'x', 'i32') }}};
|
||||||
|
{{{ makeSetValue('RI.contexts[i].state', '36', 'y', 'i32') }}};
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'mouseup':
|
||||||
|
case 'mousedown':
|
||||||
|
var value;
|
||||||
|
var offset;
|
||||||
|
if (event.button === 0) offset = 40;
|
||||||
|
else if (event.button === 2) offset = 41;
|
||||||
|
else break;
|
||||||
|
if (event.type === 'mouseup') value = 0;
|
||||||
|
else value = 1;
|
||||||
|
for (i = 0; i < RI.contexts.length; i++) {
|
||||||
|
{{{ makeSetValue('RI.contexts[i].state', 'offset', 'value', 'i8') }}};
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'keyup':
|
||||||
|
case 'keydown':
|
||||||
|
var key = event.keyCode;
|
||||||
|
var offset = key >> 3;
|
||||||
|
var bit = 1 << (key & 7);
|
||||||
|
if (offset >= 32) throw 'key code error! bad code: ' + key;
|
||||||
|
for (i = 0; i < RI.contexts.length; i++) {
|
||||||
|
var value = {{{ makeGetValue('RI.contexts[i].state', 'offset', 'i8') }}};
|
||||||
|
if (event.type === 'keyup') value &= ~bit;
|
||||||
|
else value |= bit;
|
||||||
|
{{{ makeSetValue('RI.contexts[i].state', 'offset', 'value', 'i8') }}};
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
break;
|
||||||
|
case 'blur':
|
||||||
|
case 'visibilitychange':
|
||||||
|
for (i = 0; i < RI.contexts.length; i++) {
|
||||||
|
_memset(RI.contexts[i].state, 0, 42);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
RWebInputInit: function(latency) {
|
||||||
|
if (RI.contexts.length === 0) {
|
||||||
|
document.addEventListener('keyup', RI.eventHandler, false);
|
||||||
|
document.addEventListener('keydown', RI.eventHandler, false);
|
||||||
|
document.addEventListener('mousemove', RI.eventHandler, false);
|
||||||
|
document.addEventListener('mouseup', RI.eventHandler, false);
|
||||||
|
document.addEventListener('mousedown', RI.eventHandler, false);
|
||||||
|
document.addEventListener('blur', RI.eventHandler, false);
|
||||||
|
document.addEventListener('onvisbilitychange', RI.eventHandler, false);
|
||||||
|
}
|
||||||
|
if (RI.temp === null) RI.temp = _malloc(42);
|
||||||
|
|
||||||
|
var s = _malloc(42);
|
||||||
|
_memset(s, 0, 42);
|
||||||
|
RI.contexts.push({
|
||||||
|
state: s
|
||||||
|
});
|
||||||
|
return RI.contexts.length;
|
||||||
|
},
|
||||||
|
|
||||||
|
RWebInputPoll: function(context) {
|
||||||
|
context -= 1;
|
||||||
|
var state = RI.contexts[context].state;
|
||||||
|
_memcpy(RI.temp, state, 42);
|
||||||
|
// reset mouse movements
|
||||||
|
{{{ makeSetValue('RI.contexts[context].state', '32', '0', 'i32') }}};
|
||||||
|
{{{ makeSetValue('RI.contexts[context].state', '36', '0', 'i32') }}};
|
||||||
|
return RI.temp;
|
||||||
|
},
|
||||||
|
|
||||||
|
RWebInputDestroy: function (context) {
|
||||||
|
if (context === RI.contexts.length) {
|
||||||
|
RI.contexts.pop();
|
||||||
|
if (RI.contexts.length === 0) {
|
||||||
|
document.removeEventListener('keyup', RI.eventHandler, false);
|
||||||
|
document.removeEventListener('keydown', RI.eventHandler, false);
|
||||||
|
document.removeEventListener('mousemove', RI.eventHandler, false);
|
||||||
|
document.removeEventListener('mouseup', RI.eventHandler, false);
|
||||||
|
document.removeEventListener('mousedown', RI.eventHandler, false);
|
||||||
|
document.removeEventListener('blur', RI.eventHandler, false);
|
||||||
|
document.removeEventListener('onvisbilitychange', RI.eventHandler, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
autoAddDeps(LibraryRWebInput, '$RI');
|
||||||
|
mergeInto(LibraryManager.library, LibraryRWebInput);
|
@ -42,6 +42,8 @@
|
|||||||
#define EXT_EXECUTABLES "dol|DOL"
|
#define EXT_EXECUTABLES "dol|DOL"
|
||||||
#define SALAMANDER_FILE "boot.dol"
|
#define SALAMANDER_FILE "boot.dol"
|
||||||
#define DEFAULT_EXE_EXT ".dol"
|
#define DEFAULT_EXE_EXT ".dol"
|
||||||
|
#elif defined(EMSCRIPTEN)
|
||||||
|
#define EXT_EXECUTABLES ""
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
147
frontend/frontend_emscripten.c
Normal file
147
frontend/frontend_emscripten.c
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2010-2013 - Hans-Kristian Arntzen
|
||||||
|
* Copyright (C) 2011-2013 - Daniel De Matteis
|
||||||
|
*
|
||||||
|
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <emscripten/emscripten.h>
|
||||||
|
#include "../general.h"
|
||||||
|
#include "../conf/config_file.h"
|
||||||
|
#include "../file.h"
|
||||||
|
#include "../emscripten/RWebAudio.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_RGUI
|
||||||
|
#include "../frontend/menu/rgui.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_RGUI) || defined(HAVE_RMENU) || defined(HAVE_RMENU_XUI)
|
||||||
|
#define HAVE_MENU
|
||||||
|
#else
|
||||||
|
#undef HAVE_MENU
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool menuloop;
|
||||||
|
|
||||||
|
static void endloop(void)
|
||||||
|
{
|
||||||
|
g_extern.system.shutdown = false;
|
||||||
|
menu_free();
|
||||||
|
|
||||||
|
if (g_extern.config_save_on_exit && *g_extern.config_path)
|
||||||
|
config_save_file(g_extern.config_path);
|
||||||
|
|
||||||
|
if (g_extern.main_is_init)
|
||||||
|
rarch_main_deinit();
|
||||||
|
|
||||||
|
rarch_deinit_msg_queue();
|
||||||
|
|
||||||
|
#ifdef PERF_TEST
|
||||||
|
rarch_perf_log();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rarch_main_clear_state();
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mainloop(void)
|
||||||
|
{
|
||||||
|
if (g_extern.system.shutdown)
|
||||||
|
{
|
||||||
|
endloop();
|
||||||
|
}
|
||||||
|
else if (menuloop)
|
||||||
|
{
|
||||||
|
if (!menu_iterate())
|
||||||
|
{
|
||||||
|
menuloop = false;
|
||||||
|
driver_set_nonblock_state(driver.nonblock_state);
|
||||||
|
|
||||||
|
if (driver.audio_data && !audio_start_func())
|
||||||
|
{
|
||||||
|
RARCH_ERR("Failed to resume audio driver. Will continue without audio.\n");
|
||||||
|
g_extern.audio_active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_extern.lifecycle_mode_state &= ~(1ULL << MODE_MENU);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (g_extern.lifecycle_mode_state & (1ULL << MODE_LOAD_GAME))
|
||||||
|
{
|
||||||
|
load_menu_game_prepare();
|
||||||
|
|
||||||
|
// If ROM load fails, we exit RetroArch. On console it might make more sense to go back to menu though ...
|
||||||
|
if (load_menu_game())
|
||||||
|
g_extern.lifecycle_mode_state |= (1ULL << MODE_GAME);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef RARCH_CONSOLE
|
||||||
|
g_extern.lifecycle_mode_state |= (1ULL << MODE_MENU);
|
||||||
|
#else
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
g_extern.lifecycle_mode_state &= ~(1ULL << MODE_LOAD_GAME);
|
||||||
|
}
|
||||||
|
else if (g_extern.lifecycle_mode_state & (1ULL << MODE_GAME))
|
||||||
|
{
|
||||||
|
bool r;
|
||||||
|
if (g_extern.is_paused && !g_extern.is_oneshot)
|
||||||
|
r = rarch_main_idle_iterate();
|
||||||
|
else
|
||||||
|
r = rarch_main_iterate();
|
||||||
|
if (!r)
|
||||||
|
g_extern.lifecycle_mode_state &= ~(1ULL << MODE_GAME);
|
||||||
|
}
|
||||||
|
else if (g_extern.lifecycle_mode_state & (1ULL << MODE_MENU))
|
||||||
|
{
|
||||||
|
g_extern.lifecycle_mode_state |= 1ULL << MODE_MENU_PREINIT;
|
||||||
|
// Menu should always run with vsync on.
|
||||||
|
video_set_nonblock_state_func(false);
|
||||||
|
|
||||||
|
if (driver.audio_data)
|
||||||
|
audio_stop_func();
|
||||||
|
|
||||||
|
menuloop = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_extern.system.shutdown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
emscripten_set_canvas_size(800, 600);
|
||||||
|
|
||||||
|
rarch_main_clear_state();
|
||||||
|
rarch_init_msg_queue();
|
||||||
|
|
||||||
|
int init_ret;
|
||||||
|
if ((init_ret = rarch_main_init(argc, argv))) return init_ret;
|
||||||
|
|
||||||
|
#ifdef HAVE_MENU
|
||||||
|
menu_init();
|
||||||
|
g_extern.lifecycle_mode_state |= 1ULL << MODE_GAME;
|
||||||
|
|
||||||
|
// If we started a ROM directly from command line,
|
||||||
|
// push it to ROM history.
|
||||||
|
if (!g_extern.libretro_dummy)
|
||||||
|
menu_rom_history_push_current();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
emscripten_set_main_loop(mainloop, g_settings.video.vsync ? 0 : INT_MAX, 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
275
gfx/context/emscriptenegl_ctx.c
Normal file
275
gfx/context/emscriptenegl_ctx.c
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2010-2013 - Hans-Kristian Arntzen
|
||||||
|
* Copyright (C) 2012 - Michael Lelli
|
||||||
|
*
|
||||||
|
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// VideoCore context, for Rasperry Pi.
|
||||||
|
|
||||||
|
#include "../../driver.h"
|
||||||
|
#include "../gfx_context.h"
|
||||||
|
#include "../gl_common.h"
|
||||||
|
#include "../gfx_common.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "../../config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <emscripten/emscripten.h>
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <EGL/eglext.h>
|
||||||
|
|
||||||
|
static EGLContext g_egl_ctx;
|
||||||
|
static EGLSurface g_egl_surf;
|
||||||
|
static EGLDisplay g_egl_dpy;
|
||||||
|
static EGLConfig g_config;
|
||||||
|
|
||||||
|
static bool g_inited;
|
||||||
|
|
||||||
|
static unsigned g_fb_width;
|
||||||
|
static unsigned g_fb_height;
|
||||||
|
|
||||||
|
static void gfx_ctx_swap_interval(unsigned interval)
|
||||||
|
{
|
||||||
|
// no way to control vsync in WebGL
|
||||||
|
(void)interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gfx_ctx_check_window(bool *quit,
|
||||||
|
bool *resize, unsigned *width, unsigned *height, unsigned frame_count)
|
||||||
|
{
|
||||||
|
(void)frame_count;
|
||||||
|
int iWidth, iHeight, isFullscreen;
|
||||||
|
|
||||||
|
emscripten_get_canvas_size(&iWidth, &iHeight, &isFullscreen);
|
||||||
|
*width = (unsigned) iWidth;
|
||||||
|
*height = (unsigned) iHeight;
|
||||||
|
|
||||||
|
if (*width != g_fb_width || *height != g_fb_height)
|
||||||
|
*resize = true;
|
||||||
|
else
|
||||||
|
*resize = false;
|
||||||
|
|
||||||
|
g_fb_width = (unsigned) iWidth;
|
||||||
|
g_fb_height = (unsigned) iHeight;
|
||||||
|
*quit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gfx_ctx_swap_buffers(void)
|
||||||
|
{
|
||||||
|
// no-op in emscripten, no way to force swap/wait for vsync in browsers
|
||||||
|
//eglSwapBuffers(g_egl_dpy, g_egl_surf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gfx_ctx_set_resize(unsigned width, unsigned height)
|
||||||
|
{
|
||||||
|
(void)width;
|
||||||
|
(void)height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gfx_ctx_update_window_title(void)
|
||||||
|
{
|
||||||
|
char buf[128];
|
||||||
|
if (gfx_get_fps(buf, sizeof(buf), false))
|
||||||
|
RARCH_LOG("%s\n", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gfx_ctx_get_video_size(unsigned *width, unsigned *height)
|
||||||
|
{
|
||||||
|
*width = g_fb_width;
|
||||||
|
*height = g_fb_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gfx_ctx_destroy(void);
|
||||||
|
|
||||||
|
static bool gfx_ctx_init(void)
|
||||||
|
{
|
||||||
|
EGLint width;
|
||||||
|
EGLint height;
|
||||||
|
|
||||||
|
RARCH_LOG("[EMSCRIPTEN/EGL]: Initializing...\n");
|
||||||
|
if (g_inited)
|
||||||
|
{
|
||||||
|
RARCH_LOG("[EMSCRIPTEN/EGL]: Attempted to re-initialize driver.\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLint num_config;
|
||||||
|
|
||||||
|
static const EGLint attribute_list[] =
|
||||||
|
{
|
||||||
|
EGL_RED_SIZE, 8,
|
||||||
|
EGL_GREEN_SIZE, 8,
|
||||||
|
EGL_BLUE_SIZE, 8,
|
||||||
|
EGL_ALPHA_SIZE, 8,
|
||||||
|
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||||
|
EGL_NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
static const EGLint context_attributes[] =
|
||||||
|
{
|
||||||
|
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||||
|
EGL_NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
// get an EGL display connection
|
||||||
|
g_egl_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||||
|
if (!g_egl_dpy)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// initialize the EGL display connection
|
||||||
|
if (!eglInitialize(g_egl_dpy, NULL, NULL))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// get an appropriate EGL frame buffer configuration
|
||||||
|
if (!eglChooseConfig(g_egl_dpy, attribute_list, &g_config, 1, &num_config))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// create an EGL rendering context
|
||||||
|
g_egl_ctx = eglCreateContext(g_egl_dpy, g_config, EGL_NO_CONTEXT, context_attributes);
|
||||||
|
if (!g_egl_ctx)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// create an EGL window surface
|
||||||
|
g_egl_surf = eglCreateWindowSurface(g_egl_dpy, g_config, 0, NULL);
|
||||||
|
if (!g_egl_surf)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// connect the context to the surface
|
||||||
|
if (!eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
eglQuerySurface(g_egl_dpy, g_egl_surf, EGL_WIDTH, &width);
|
||||||
|
eglQuerySurface(g_egl_dpy, g_egl_surf, EGL_HEIGHT, &height);
|
||||||
|
g_fb_width = width;
|
||||||
|
g_fb_height = height;
|
||||||
|
RARCH_LOG("[EMSCRIPTEN/EGL]: Dimensions: %ux%u\n", width, height);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error:
|
||||||
|
gfx_ctx_destroy();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gfx_ctx_set_video_mode(
|
||||||
|
unsigned width, unsigned height,
|
||||||
|
bool fullscreen)
|
||||||
|
{
|
||||||
|
if (g_inited)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
g_inited = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gfx_ctx_bind_api(enum gfx_ctx_api api, unsigned major, unsigned minor)
|
||||||
|
{
|
||||||
|
(void)major;
|
||||||
|
(void)minor;
|
||||||
|
switch (api)
|
||||||
|
{
|
||||||
|
case GFX_CTX_OPENGL_ES_API:
|
||||||
|
return eglBindAPI(EGL_OPENGL_ES_API);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gfx_ctx_destroy(void)
|
||||||
|
{
|
||||||
|
if (g_egl_dpy)
|
||||||
|
{
|
||||||
|
eglMakeCurrent(g_egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||||
|
|
||||||
|
if (g_egl_ctx)
|
||||||
|
{
|
||||||
|
eglDestroyContext(g_egl_dpy, g_egl_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_egl_surf)
|
||||||
|
{
|
||||||
|
eglDestroySurface(g_egl_dpy, g_egl_surf);
|
||||||
|
}
|
||||||
|
|
||||||
|
eglTerminate(g_egl_dpy);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_egl_ctx = NULL;
|
||||||
|
g_egl_surf = NULL;
|
||||||
|
g_egl_dpy = NULL;
|
||||||
|
g_config = 0;
|
||||||
|
g_inited = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gfx_ctx_input_driver(const input_driver_t **input, void **input_data)
|
||||||
|
{
|
||||||
|
*input = NULL;
|
||||||
|
|
||||||
|
void *rwebinput = input_rwebinput.init();
|
||||||
|
|
||||||
|
if (rwebinput)
|
||||||
|
{
|
||||||
|
*input = &input_rwebinput;
|
||||||
|
*input_data = rwebinput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gfx_ctx_has_focus(void)
|
||||||
|
{
|
||||||
|
return g_inited;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gfx_ctx_proc_t gfx_ctx_get_proc_address(const char *symbol)
|
||||||
|
{
|
||||||
|
return eglGetProcAddress(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float gfx_ctx_translate_aspect(unsigned width, unsigned height)
|
||||||
|
{
|
||||||
|
return (float)width / height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gfx_ctx_driver_t gfx_ctx_emscripten = {
|
||||||
|
gfx_ctx_init,
|
||||||
|
gfx_ctx_destroy,
|
||||||
|
gfx_ctx_bind_api,
|
||||||
|
gfx_ctx_swap_interval,
|
||||||
|
gfx_ctx_set_video_mode,
|
||||||
|
gfx_ctx_get_video_size,
|
||||||
|
gfx_ctx_translate_aspect,
|
||||||
|
gfx_ctx_update_window_title,
|
||||||
|
gfx_ctx_check_window,
|
||||||
|
gfx_ctx_set_resize,
|
||||||
|
gfx_ctx_has_focus,
|
||||||
|
gfx_ctx_swap_buffers,
|
||||||
|
gfx_ctx_input_driver,
|
||||||
|
gfx_ctx_get_proc_address,
|
||||||
|
gfx_ctx_init_egl_image_buffer,
|
||||||
|
gfx_ctx_write_egl_image,
|
||||||
|
NULL,
|
||||||
|
"emscripten",
|
||||||
|
};
|
@ -13,6 +13,7 @@
|
|||||||
* If not, see <http://www.gnu.org/licenses/>.
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "../general.h"
|
||||||
#include "gfx_context.h"
|
#include "gfx_context.h"
|
||||||
#include "../general.h"
|
#include "../general.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -52,6 +53,9 @@ static const gfx_ctx_driver_t *gfx_ctx_drivers[] = {
|
|||||||
#if defined(IOS) || defined(OSX) //< Don't use __APPLE__ as it breaks basic SDL builds
|
#if defined(IOS) || defined(OSX) //< Don't use __APPLE__ as it breaks basic SDL builds
|
||||||
&gfx_ctx_apple,
|
&gfx_ctx_apple,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
&gfx_ctx_emscripten,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
const gfx_ctx_driver_t *gfx_ctx_find_driver(const char *ident)
|
const gfx_ctx_driver_t *gfx_ctx_find_driver(const char *ident)
|
||||||
|
@ -108,6 +108,7 @@ extern const gfx_ctx_driver_t gfx_ctx_wgl;
|
|||||||
extern const gfx_ctx_driver_t gfx_ctx_videocore;
|
extern const gfx_ctx_driver_t gfx_ctx_videocore;
|
||||||
extern const gfx_ctx_driver_t gfx_ctx_bbqnx;
|
extern const gfx_ctx_driver_t gfx_ctx_bbqnx;
|
||||||
extern const gfx_ctx_driver_t gfx_ctx_apple;
|
extern const gfx_ctx_driver_t gfx_ctx_apple;
|
||||||
|
extern const gfx_ctx_driver_t gfx_ctx_emscripten;
|
||||||
extern const gfx_ctx_driver_t gfx_ctx_null;
|
extern const gfx_ctx_driver_t gfx_ctx_null;
|
||||||
|
|
||||||
const gfx_ctx_driver_t *gfx_ctx_find_driver(const char *ident); // Finds driver with ident. Does not initialize.
|
const gfx_ctx_driver_t *gfx_ctx_find_driver(const char *ident); // Finds driver with ident. Does not initialize.
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "input_common.h"
|
#include "input_common.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "../general.h"
|
#include "../general.h"
|
||||||
#include "../driver.h"
|
#include "../driver.h"
|
||||||
@ -515,6 +516,96 @@ const struct rarch_key_map rarch_key_map_dinput[] = {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
const struct rarch_key_map rarch_key_map_rwebinput[] = {
|
||||||
|
{ 37, RETROK_LEFT },
|
||||||
|
{ 39, RETROK_RIGHT },
|
||||||
|
{ 38, RETROK_UP },
|
||||||
|
{ 40, RETROK_DOWN },
|
||||||
|
{ 13, RETROK_RETURN },
|
||||||
|
{ 9, RETROK_TAB },
|
||||||
|
{ 45, RETROK_INSERT },
|
||||||
|
{ 46, RETROK_DELETE },
|
||||||
|
{ 16, RETROK_RSHIFT },
|
||||||
|
{ 16, RETROK_LSHIFT },
|
||||||
|
{ 17, RETROK_LCTRL },
|
||||||
|
{ 35, RETROK_END },
|
||||||
|
{ 36, RETROK_HOME },
|
||||||
|
{ 34, RETROK_PAGEDOWN },
|
||||||
|
{ 33, RETROK_PAGEUP },
|
||||||
|
{ 18, RETROK_LALT },
|
||||||
|
{ 32, RETROK_SPACE },
|
||||||
|
{ 27, RETROK_ESCAPE },
|
||||||
|
{ 8, RETROK_BACKSPACE },
|
||||||
|
{ 13, RETROK_KP_ENTER },
|
||||||
|
{ 107, RETROK_KP_PLUS },
|
||||||
|
{ 109, RETROK_KP_MINUS },
|
||||||
|
{ 106, RETROK_KP_MULTIPLY },
|
||||||
|
{ 111, RETROK_KP_DIVIDE },
|
||||||
|
{ 192, RETROK_BACKQUOTE },
|
||||||
|
{ 19, RETROK_PAUSE },
|
||||||
|
{ 96, RETROK_KP0 },
|
||||||
|
{ 97, RETROK_KP1 },
|
||||||
|
{ 98, RETROK_KP2 },
|
||||||
|
{ 99, RETROK_KP3 },
|
||||||
|
{ 100, RETROK_KP4 },
|
||||||
|
{ 101, RETROK_KP5 },
|
||||||
|
{ 102, RETROK_KP6 },
|
||||||
|
{ 103, RETROK_KP7 },
|
||||||
|
{ 104, RETROK_KP8 },
|
||||||
|
{ 105, RETROK_KP9 },
|
||||||
|
{ 48, RETROK_0 },
|
||||||
|
{ 49, RETROK_1 },
|
||||||
|
{ 50, RETROK_2 },
|
||||||
|
{ 51, RETROK_3 },
|
||||||
|
{ 52, RETROK_4 },
|
||||||
|
{ 53, RETROK_5 },
|
||||||
|
{ 54, RETROK_6 },
|
||||||
|
{ 55, RETROK_7 },
|
||||||
|
{ 56, RETROK_8 },
|
||||||
|
{ 57, RETROK_9 },
|
||||||
|
{ 112, RETROK_F1 },
|
||||||
|
{ 113, RETROK_F2 },
|
||||||
|
{ 114, RETROK_F3 },
|
||||||
|
{ 115, RETROK_F4 },
|
||||||
|
{ 116, RETROK_F5 },
|
||||||
|
{ 117, RETROK_F6 },
|
||||||
|
{ 118, RETROK_F7 },
|
||||||
|
{ 119, RETROK_F8 },
|
||||||
|
{ 120, RETROK_F9 },
|
||||||
|
{ 121, RETROK_F10 },
|
||||||
|
{ 122, RETROK_F11 },
|
||||||
|
{ 123, RETROK_F12 },
|
||||||
|
{ 65, RETROK_a },
|
||||||
|
{ 66, RETROK_b },
|
||||||
|
{ 67, RETROK_c },
|
||||||
|
{ 68, RETROK_d },
|
||||||
|
{ 69, RETROK_e },
|
||||||
|
{ 70, RETROK_f },
|
||||||
|
{ 71, RETROK_g },
|
||||||
|
{ 72, RETROK_h },
|
||||||
|
{ 73, RETROK_i },
|
||||||
|
{ 74, RETROK_j },
|
||||||
|
{ 75, RETROK_k },
|
||||||
|
{ 76, RETROK_l },
|
||||||
|
{ 77, RETROK_m },
|
||||||
|
{ 78, RETROK_n },
|
||||||
|
{ 79, RETROK_o },
|
||||||
|
{ 80, RETROK_p },
|
||||||
|
{ 81, RETROK_q },
|
||||||
|
{ 82, RETROK_r },
|
||||||
|
{ 83, RETROK_s },
|
||||||
|
{ 84, RETROK_t },
|
||||||
|
{ 85, RETROK_u },
|
||||||
|
{ 86, RETROK_v },
|
||||||
|
{ 87, RETROK_w },
|
||||||
|
{ 88, RETROK_x },
|
||||||
|
{ 89, RETROK_y },
|
||||||
|
{ 90, RETROK_z },
|
||||||
|
{ 0, RETROK_UNKNOWN },
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
static enum retro_key rarch_keysym_lut[RETROK_LAST];
|
static enum retro_key rarch_keysym_lut[RETROK_LAST];
|
||||||
|
|
||||||
void input_init_keyboard_lut(const struct rarch_key_map *map)
|
void input_init_keyboard_lut(const struct rarch_key_map *map)
|
||||||
|
@ -106,6 +106,7 @@ struct rarch_key_map
|
|||||||
extern const struct rarch_key_map rarch_key_map_x11[];
|
extern const struct rarch_key_map rarch_key_map_x11[];
|
||||||
extern const struct rarch_key_map rarch_key_map_sdl[];
|
extern const struct rarch_key_map rarch_key_map_sdl[];
|
||||||
extern const struct rarch_key_map rarch_key_map_dinput[];
|
extern const struct rarch_key_map rarch_key_map_dinput[];
|
||||||
|
extern const struct rarch_key_map rarch_key_map_rwebinput[];
|
||||||
|
|
||||||
void input_init_keyboard_lut(const struct rarch_key_map *map);
|
void input_init_keyboard_lut(const struct rarch_key_map *map);
|
||||||
enum retro_key input_translate_keysym_to_rk(unsigned sym);
|
enum retro_key input_translate_keysym_to_rk(unsigned sym);
|
||||||
|
149
input/rwebinput_input.c
Normal file
149
input/rwebinput_input.c
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2010-2013 - Michael Lelli
|
||||||
|
*
|
||||||
|
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "input_common.h"
|
||||||
|
|
||||||
|
#include "../driver.h"
|
||||||
|
|
||||||
|
#include "../boolean.h"
|
||||||
|
#include "../general.h"
|
||||||
|
|
||||||
|
#include "../emscripten/RWebInput.h"
|
||||||
|
|
||||||
|
static bool uninited = false;
|
||||||
|
|
||||||
|
typedef struct rwebinput_input
|
||||||
|
{
|
||||||
|
rwebinput_state_t state;
|
||||||
|
int context;
|
||||||
|
} rwebinput_input_t;
|
||||||
|
|
||||||
|
static void *rwebinput_input_init(void)
|
||||||
|
{
|
||||||
|
rwebinput_input_t *rwebinput = (rwebinput_input_t*)calloc(1, sizeof(*rwebinput));
|
||||||
|
if (!rwebinput)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
rwebinput->context = RWebInputInit();
|
||||||
|
if (!rwebinput->context)
|
||||||
|
{
|
||||||
|
free(rwebinput);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
input_init_keyboard_lut(rarch_key_map_rwebinput);
|
||||||
|
|
||||||
|
return rwebinput;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool rwebinput_key_pressed(rwebinput_input_t *rwebinput, int key)
|
||||||
|
{
|
||||||
|
if (key >= RETROK_LAST)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
unsigned sym = input_translate_rk_to_keysym((enum retro_key)key);
|
||||||
|
bool ret = rwebinput->state.keys[sym >> 3] & (1 << (sym & 7));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool rwebinput_is_pressed(rwebinput_input_t *rwebinput, const struct retro_keybind *binds, unsigned id)
|
||||||
|
{
|
||||||
|
if (id < RARCH_BIND_LIST_END)
|
||||||
|
{
|
||||||
|
const struct retro_keybind *bind = &binds[id];
|
||||||
|
return bind->valid && rwebinput_key_pressed(rwebinput, binds[id].key);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool rwebinput_bind_button_pressed(void *data, int key)
|
||||||
|
{
|
||||||
|
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
|
||||||
|
return rwebinput_is_pressed(rwebinput, g_settings.input.binds[0], key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int16_t rwebinput_mouse_state(rwebinput_input_t *rwebinput, unsigned id)
|
||||||
|
{
|
||||||
|
switch (id)
|
||||||
|
{
|
||||||
|
case RETRO_DEVICE_ID_MOUSE_X:
|
||||||
|
return (int16_t) rwebinput->state.mouse_x;
|
||||||
|
case RETRO_DEVICE_ID_MOUSE_Y:
|
||||||
|
return (int16_t) rwebinput->state.mouse_y;
|
||||||
|
case RETRO_DEVICE_ID_MOUSE_LEFT:
|
||||||
|
return rwebinput->state.mouse_l;
|
||||||
|
case RETRO_DEVICE_ID_MOUSE_RIGHT:
|
||||||
|
return rwebinput->state.mouse_r;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int16_t rwebinput_input_state(void *data, const struct retro_keybind **binds, unsigned port, unsigned device, unsigned index, unsigned id)
|
||||||
|
{
|
||||||
|
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
|
||||||
|
|
||||||
|
switch (device)
|
||||||
|
{
|
||||||
|
case RETRO_DEVICE_JOYPAD:
|
||||||
|
return rwebinput_is_pressed(rwebinput, binds[port], id);
|
||||||
|
|
||||||
|
case RETRO_DEVICE_KEYBOARD:
|
||||||
|
return rwebinput_key_pressed(rwebinput, id);
|
||||||
|
|
||||||
|
case RETRO_DEVICE_MOUSE:
|
||||||
|
return rwebinput_mouse_state(rwebinput, id);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rwebinput_input_free(void *data)
|
||||||
|
{
|
||||||
|
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
|
||||||
|
uninited = true;
|
||||||
|
|
||||||
|
RWebInputDestroy(rwebinput->context);
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rwebinput_input_poll(void *data)
|
||||||
|
{
|
||||||
|
rwebinput_input_t *rwebinput = (rwebinput_input_t*)data;
|
||||||
|
|
||||||
|
rwebinput_state_t *state = RWebInputPoll(rwebinput->context);
|
||||||
|
memcpy(&rwebinput->state, state, sizeof(rwebinput->state));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rwebinput_grab_mouse(void *data, bool state)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
(void)state;
|
||||||
|
}
|
||||||
|
|
||||||
|
const input_driver_t input_rwebinput = {
|
||||||
|
rwebinput_input_init,
|
||||||
|
rwebinput_input_poll,
|
||||||
|
rwebinput_input_state,
|
||||||
|
rwebinput_bind_button_pressed,
|
||||||
|
rwebinput_input_free,
|
||||||
|
NULL,
|
||||||
|
"rwebinput",
|
||||||
|
rwebinput_grab_mouse,
|
||||||
|
};
|
||||||
|
|
@ -1,4 +1,8 @@
|
|||||||
|
|
||||||
|
ifneq ($(EMSCRIPTEN),)
|
||||||
|
platform = emscripten
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(platform),)
|
ifeq ($(platform),)
|
||||||
platform = unix
|
platform = unix
|
||||||
ifeq ($(shell uname -a),)
|
ifeq ($(shell uname -a),)
|
||||||
@ -32,6 +36,10 @@ else ifeq ($(platform), qnx)
|
|||||||
TARGET := $(TARGET_NAME)_libretro_qnx.so
|
TARGET := $(TARGET_NAME)_libretro_qnx.so
|
||||||
fpic := -fPIC
|
fpic := -fPIC
|
||||||
SHARED := -shared -Wl,--version-script=link.T -Wl,--no-undefined
|
SHARED := -shared -Wl,--version-script=link.T -Wl,--no-undefined
|
||||||
|
else ifeq ($(platform), emscripten)
|
||||||
|
TARGET := $(TARGET_NAME)_libretro_emscripten.so
|
||||||
|
fpic := -fPIC
|
||||||
|
SHARED := -shared -Wl,--version-script=link.T -Wl,--no-undefined
|
||||||
else
|
else
|
||||||
CC = gcc
|
CC = gcc
|
||||||
TARGET := $(TARGET_NAME)_retro.dll
|
TARGET := $(TARGET_NAME)_retro.dll
|
||||||
|
@ -58,6 +58,10 @@
|
|||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
#include <emscripten.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef PERF_TEST
|
#ifdef PERF_TEST
|
||||||
#define MAX_COUNTERS 64
|
#define MAX_COUNTERS 64
|
||||||
static struct rarch_perf_counter *perf_counters[MAX_COUNTERS];
|
static struct rarch_perf_counter *perf_counters[MAX_COUNTERS];
|
||||||
@ -145,6 +149,8 @@ rarch_time_t rarch_get_time_usec(void)
|
|||||||
if (clock_gettime(CLOCK_MONOTONIC, &tv) < 0)
|
if (clock_gettime(CLOCK_MONOTONIC, &tv) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
return tv.tv_sec * INT64_C(1000000) + (tv.tv_nsec + 500) / 1000;
|
return tv.tv_sec * INT64_C(1000000) + (tv.tv_nsec + 500) / 1000;
|
||||||
|
#elif defined(EMSCRIPTEN)
|
||||||
|
return emscripten_get_now() * 1000;
|
||||||
#else
|
#else
|
||||||
#error "Your platform does not have a timer function implemented in rarch_get_time_usec(). Cannot continue."
|
#error "Your platform does not have a timer function implemented in rarch_get_time_usec(). Cannot continue."
|
||||||
#endif
|
#endif
|
||||||
|
@ -67,6 +67,8 @@ const char *config_get_default_audio(void)
|
|||||||
return "ps3";
|
return "ps3";
|
||||||
case AUDIO_WII:
|
case AUDIO_WII:
|
||||||
return "gx";
|
return "gx";
|
||||||
|
case AUDIO_RWEBAUDIO:
|
||||||
|
return "rwebaudio";
|
||||||
case AUDIO_NULL:
|
case AUDIO_NULL:
|
||||||
return "null";
|
return "null";
|
||||||
default:
|
default:
|
||||||
@ -137,6 +139,8 @@ const char *config_get_default_input(void)
|
|||||||
return "apple_input";
|
return "apple_input";
|
||||||
case INPUT_QNX:
|
case INPUT_QNX:
|
||||||
return "qnx_input";
|
return "qnx_input";
|
||||||
|
case INPUT_RWEBINPUT:
|
||||||
|
return "rwebinput";
|
||||||
case INPUT_NULL:
|
case INPUT_NULL:
|
||||||
return "null";
|
return "null";
|
||||||
default:
|
default:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user