blob: 445ee6e718f08182ce7aa3e1d17fe09924e49104 [file] [log] [blame]
diff --git a/port.h b/port.h
--- a/port.h
+++ b/port.h
@@ -331,7 +331,7 @@ void SetInfoDlgColor(unsigned char, unsigned char, unsigned char);
#define TITLE "Snes9x"
#endif
-#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__x86_64__) || defined(__alpha__) || defined(__MIPSEL__) || defined(_M_IX86) || defined(_M_X64)
+#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__x86_64__) || defined(__alpha__) || defined(__MIPSEL__) || defined(_M_IX86) || defined(_M_X64) || defined(__native_client__)
#define LSB_FIRST
#define FAST_LSB_WORD_ACCESS
#else
diff --git a/unix/Makefile.in b/unix/Makefile.in
--- a/unix/Makefile.in
+++ b/unix/Makefile.in
@@ -2,14 +2,19 @@
@S9XNETPLAY@
@S9XZIP@
@S9XJMA@
+@S9XX11@
# Fairly good and special-char-safe descriptor of the os being built on.
OS = `uname -s -r -m|sed \"s/ /-/g\"|tr \"[A-Z]\" \"[a-z]\"|tr \"/()\" \"___\"`
BUILDDIR = .
-OBJECTS = ../apu/apu.o ../apu/SNES_SPC.o ../apu/SNES_SPC_misc.o ../apu/SNES_SPC_state.o ../apu/SPC_DSP.o ../apu/SPC_Filter.o ../bsx.o ../c4.o ../c4emu.o ../cheats.o ../cheats2.o ../clip.o ../conffile.o ../controls.o ../cpu.o ../cpuexec.o ../cpuops.o ../crosshairs.o ../dma.o ../dsp.o ../dsp1.o ../dsp2.o ../dsp3.o ../dsp4.o ../fxinst.o ../fxemu.o ../gfx.o ../globals.o ../logger.o ../memmap.o ../movie.o ../obc1.o ../ppu.o ../reader.o ../sa1.o ../sa1cpu.o ../screenshot.o ../sdd1.o ../sdd1emu.o ../seta.o ../seta010.o ../seta011.o ../seta018.o ../snapshot.o ../snes9x.o ../spc7110.o ../srtc.o ../tile.o ../filter/2xsai.o ../filter/blit.o ../filter/epx.o ../filter/hq2x.o ../filter/snes_ntsc.o unix.o x11.o
+OBJECTS = ../apu/apu.o ../apu/SNES_SPC.o ../apu/SNES_SPC_misc.o ../apu/SNES_SPC_state.o ../apu/SPC_DSP.o ../apu/SPC_Filter.o ../bsx.o ../c4.o ../c4emu.o ../cheats.o ../cheats2.o ../clip.o ../conffile.o ../controls.o ../cpu.o ../cpuexec.o ../cpuops.o ../crosshairs.o ../dma.o ../dsp.o ../dsp1.o ../dsp2.o ../dsp3.o ../dsp4.o ../fxinst.o ../fxemu.o ../gfx.o ../globals.o ../logger.o ../memmap.o ../movie.o ../obc1.o ../ppu.o ../reader.o ../sa1.o ../sa1cpu.o ../screenshot.o ../sdd1.o ../sdd1emu.o ../seta.o ../seta010.o ../seta011.o ../seta018.o ../snapshot.o ../snes9x.o ../spc7110.o ../srtc.o ../tile.o ../filter/2xsai.o ../filter/blit.o ../filter/epx.o ../filter/hq2x.o ../filter/snes_ntsc.o ../unix/unix.o ../unix/nacl.o
DEFS = -DMITSHM
+ifdef S9XX11
+OBJECTS += ../unix/x11.o
+endif
+
ifdef S9XDEBUGGER
OBJECTS += ../debug.o ../fxdbg.o
endif
diff --git a/unix/configure.ac b/unix/configure.ac
--- a/unix/configure.ac
+++ b/unix/configure.ac
@@ -38,7 +38,7 @@ AC_DEFUN([AC_S9X_COMPILER_FLAG],
return (argc);
}
],
- [snes9x_cv_option_$2="yes"], [snes9x_cv_option_$2="no"])
+ [snes9x_cv_option_$2="yes"], [snes9x_cv_option_$2="no"], [AC_MSG_RESULT(skip for crosscompiling)])
])
CXXFLAGS="[$]OLD_CXXFLAGS"
@@ -58,15 +58,15 @@ AC_DEFUN([AC_S9X_COMPILER_FLAG],
# Remove -g and -O2 flags manually.
-if test "x$CFLAGS" != "x"; then
- CFLAGS="`echo \"$CFLAGS\" | sed -e 's/-g//'`"
- CFLAGS="`echo \"$CFLAGS\" | sed -e 's/-O2//'`"
-fi
-
-if test "x$CXXFLAGS" != "x"; then
- CXXFLAGS="`echo \"$CXXFLAGS\" | sed -e 's/-g//'`"
- CXXFLAGS="`echo \"$CXXFLAGS\" | sed -e 's/-O2//'`"
-fi
+#if test "x$CFLAGS" != "x"; then
+# CFLAGS="`echo \"$CFLAGS\" | sed -e 's/-g//'`"
+# CFLAGS="`echo \"$CFLAGS\" | sed -e 's/-O2//'`"
+#fi
+#
+#if test "x$CXXFLAGS" != "x"; then
+# CXXFLAGS="`echo \"$CXXFLAGS\" | sed -e 's/-g//'`"
+# CXXFLAGS="`echo \"$CXXFLAGS\" | sed -e 's/-O2//'`"
+#fi
# Test what compiler flags we should use.
@@ -259,12 +259,13 @@ AC_CHECK_FUNC([mkstemp],
S9XDEFS="$S9XDEFS -DHAVE_MKSTEMP"
])
-# Check X11
+# Check X11.
+
+S9XX11="#S9XX11=1"
AC_PATH_XTRA
-if test "x$no_x" = "xyes"; then
- AC_MSG_ERROR([X11 is required.])
-else
+if test "x$no_x" != "xyes"; then
+ S9XX11="S9XX11=1"
S9XFLGS="$S9XFLGS $X_CFLAGS"
S9XLIBS="$S9XLIBS $X_PRE_LIBS -lX11 -lXext $X_LIBS $X_EXTRA_LIBS"
fi
@@ -303,7 +304,7 @@ if test "x$snes9x_have_stdint_h" = "x"; then
return (!(sizeof(void *) == sizeof(int)));
}
],
- [snes9x_ptr_is_int="yes"], [snes9x_ptr_is_int="no"])
+ [snes9x_ptr_is_int="yes"], [snes9x_ptr_is_int="no"], [AC_MSG_RESULT(skip for crosscompiling)])
if test "x$snes9x_ptr_is_int" = "xyes"; then
AC_MSG_RESULT(yes)
@@ -350,7 +351,7 @@ AC_DEFUN([AC_S9X_CHECK_SAR],
return (i < 0 ? 0 : 1);
}
],
- [snes9x_sar_$1="yes"], [snes9x_sar_$1="no"])
+ [snes9x_sar_$1="yes"], [snes9x_sar_$1="no"], [AC_MSG_RESULT(skip for crosscompiling)])
CXXFLAGS="[$]OLD_CXXFLAGS"
@@ -388,7 +389,7 @@ if test "x$enable_sound" = "xyes"; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
- AC_MSG_WARN([Your OS is not Linux. Build without sound support.])
+ AC_MSG_WARN([Your OS is not Linux. Build without Linux sound support.])
enable_sound="no"
fi
fi
@@ -406,7 +407,7 @@ fi
# Output.
S9XFLGS="$CXXFLAGS $CPPFLAGS $LDFLAGS $S9XFLGS"
-S9XLIBS="$LIBS $S9XLIBS"
+S9XLIBS="$LIBS $EXTRA_LIBS $S9XLIBS"
S9XFLGS="`echo \"$S9XFLGS\" | sed -e 's/ */ /g'`"
S9XDEFS="`echo \"$S9XDEFS\" | sed -e 's/ */ /g'`"
@@ -422,6 +423,7 @@ AC_SUBST(S9XDEBUGGER)
AC_SUBST(S9XNETPLAY)
AC_SUBST(S9XZIP)
AC_SUBST(S9XJMA)
+AC_SUBST(S9XX11)
rm config.info 2>/dev/null
diff --git a/unix/keycodes.h b/unix/keycodes.h
new file mode 100644
--- /dev/null
+++ b/unix/keycodes.h
@@ -0,0 +1,271 @@
+/* Copyright (c) 2013 The Native Client Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+const char* kKeyCodeNames[] = {
+ NULL, // 0
+ NULL, // 1
+ NULL, // 2
+ "Cancel", // 3
+ NULL, // 4
+ NULL, // 5
+ "Help", // 6
+ NULL, // 7
+ "BackSpace", // 8
+ "Tab", // 9
+ NULL, // 10
+ NULL, // 11
+ "Clear", // 12
+ "Return", // 13
+ "Enter", // 14
+ NULL, // 15
+ "Shift", // 16
+ "Control", // 17
+ "Alt", // 18
+ "Pause", // 19
+ "CapsLock", // 20
+ "Kana", // 21
+ "Eisu", // 22
+ "Junja", // 23
+ "Final", // 24
+ "Hanja", // 25
+ NULL, // 26
+ "Escape", // 27
+ "Convert", // 28
+ "Nonconvert", // 29
+ "Accept", // 30
+ "Modechange", // 31
+ "Space", // 32
+ "PageUp", // 33
+ "PageDown", // 34
+ "End", // 35
+ "Home", // 36
+ "Left", // 37
+ "Up", // 38
+ "Right", // 39
+ "Down", // 40
+ "Select", // 41
+ "Print", // 42
+ "Execute", // 43
+ "Printscreen", // 44
+ "Insert", // 45
+ "Delete", // 46
+ NULL,
+ "0", // 48
+ "1", // 49
+ "2", // 50
+ "3", // 51
+ "4", // 52
+ "5", // 53
+ "6", // 54
+ "7", // 55
+ "8", // 56
+ "9", // 57
+ "Colon", // 58
+ "Semicolon", // 59
+ "LessThan", // 60
+ "Equals", // 61
+ "GreaterThan", // 62
+ "QuestionMark", // 63
+ "At", // 64
+ "A", // 65
+ "B", // 66
+ "C", // 67
+ "D", // 68
+ "E", // 69
+ "F", // 70
+ "G", // 71
+ "H", // 72
+ "I", // 73
+ "J", // 74
+ "K", // 75
+ "L", // 76
+ "M", // 77
+ "N", // 78
+ "O", // 79
+ "P", // 80
+ "Q", // 81
+ "R", // 82
+ "S", // 83
+ "T", // 84
+ "U", // 85
+ "V", // 86
+ "W", // 87
+ "X", // 88
+ "Y", // 89
+ "Z", // 90
+ "Win", // 91
+ NULL,
+ "ContextMenu", // 93
+ NULL,
+ "Sleep", // 95
+ "Numpad0", // 96
+ "Numpad1", // 97
+ "Numpad2", // 98
+ "Numpad3", // 99
+ "Numpad4", // 100
+ "Numpad5", // 101
+ "Numpad6", // 102
+ "Numpad7", // 103
+ "Numpad8", // 104
+ "Numpad9", // 105
+ "Multiply", // 106
+ "Add", // 107
+ "Separator", // 108
+ "Subtract", // 109
+ "Decimal", // 110
+ "Divide", // 111
+ "F1", // 112
+ "F2", // 113
+ "F3", // 114
+ "F4", // 115
+ "F5", // 116
+ "F6", // 117
+ "F7", // 118
+ "F8", // 119
+ "F9", // 120
+ "F10", // 121
+ "F11", // 122
+ "F12", // 123
+ "F13", // 124
+ "F14", // 125
+ "F15", // 126
+ "F16", // 127
+ "F17", // 128
+ "F18", // 129
+ "F19", // 130
+ "F20", // 131
+ "F21", // 132
+ "F22", // 133
+ "F23", // 134
+ "F24", // 135
+ NULL, // 136
+ NULL, // 137
+ NULL, // 138
+ NULL, // 139
+ NULL, // 140
+ NULL, // 141
+ NULL, // 142
+ NULL, // 143
+ "NumLock", // 144
+ "ScrollLock", // 145
+ "WinOemFjJisho", // 146
+ "WinOemFjMasshou", // 147
+ "WinOemFjTouroku", // 148
+ "WinOemFjLoya", // 149
+ "WinOemFjRoya", // 150
+ NULL, // 151
+ NULL, // 152
+ NULL, // 153
+ NULL, // 154
+ NULL, // 155
+ NULL, // 156
+ NULL, // 157
+ NULL, // 158
+ NULL, // 159
+ "Circumflex", // 160
+ "Exclamation", // 161
+ "DoubleQuote", // 162
+ "Hash", // 163
+ "Dollar", // 164
+ "Percent", // 165
+ "Ampersand", // 166
+ "Underscore", // 167
+ "OpenParen", // 168
+ "CloseParen", // 169
+ "Asterisk", // 170
+ "Plus", // 171
+ "Pipe", // 172
+ "HyphenMinus", // 173
+ "OpenCurlyBracket", // 174
+ "CloseCurlyBracket", // 175
+ "Tilde", // 176
+ NULL, // 177
+ NULL, // 178
+ NULL, // 179
+ NULL, // 180
+ "VolumeMute", // 181
+ "VolumeDown", // 182
+ "VolumeUp", // 183
+ NULL, // 184
+ NULL, // 185
+ NULL, // 186
+ NULL, // 187
+ "Comma", // 188
+ NULL, // 189
+ "Period", // 190
+ "Slash", // 191
+ "BackQuote", // 192
+ NULL, // 193
+ NULL, // 194
+ NULL, // 195
+ NULL, // 196
+ NULL, // 197
+ NULL, // 198
+ NULL, // 199
+ NULL, // 200
+ NULL, // 201
+ NULL, // 202
+ NULL, // 203
+ NULL, // 204
+ NULL, // 205
+ NULL, // 206
+ NULL, // 207
+ NULL, // 208
+ NULL, // 209
+ NULL, // 210
+ NULL, // 211
+ NULL, // 212
+ NULL, // 213
+ NULL, // 214
+ NULL, // 215
+ NULL, // 216
+ NULL, // 217
+ NULL, // 218
+ "OpenBracket", // 219
+ "BackSlash", // 220
+ "CloseBracket", // 221
+ "Quote", // 222
+ NULL, // 223
+ "Meta", // 224
+ "AltGr", // 225
+ NULL, // 226
+ "WinIcoHelp", // 227
+ "WinIco00", // 228
+ NULL, // 229
+ "WinIcoClear", // 230
+ NULL, // 231
+ NULL, // 232
+ "WinOemReset", // 233
+ "WinOemJump", // 234
+ "WinOemPa1", // 235
+ "WinOemPa2", // 236
+ "WinOemPa3", // 237
+ "WinOemWsctrl", // 238
+ "WinOemCusel", // 239
+ "WinOemAttn", // 240
+ "WinOemFinish", // 241
+ "WinOemCopy", // 242
+ "WinOemAuto", // 243
+ "WinOemEnlw", // 244
+ "WinOemBacktab", // 245
+ "Attn", // 246
+ "CrSel", // 247
+ "ExSel", // 248
+ "ErEOF", // 249
+ "Play", // 250
+ "Zoom", // 251
+ NULL, // 252
+ "PA1", // 253
+ "WinOemClear", // 254
+};
+
+static inline int StringToCode(const char* name) {
+ const int kNumKeyCodeNames = sizeof(kKeyCodeNames)/sizeof(kKeyCodeNames[0]);
+ for (int i = 0; i < kNumKeyCodeNames; ++i) {
+ if (kKeyCodeNames[i] && strcmp(name, kKeyCodeNames[i]) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
diff --git a/unix/nacl.cpp b/unix/nacl.cpp
new file mode 100644
--- /dev/null
+++ b/unix/nacl.cpp
@@ -0,0 +1,694 @@
+/* Copyright (c) 2013 The Native Client Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#ifdef __native_client__
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+#include <utility>
+
+#include <ppapi/c/ppb_input_event.h>
+#include <ppapi/cpp/audio.h>
+#include <ppapi/cpp/audio_config.h>
+#include <ppapi/cpp/instance.h>
+#include <ppapi/cpp/input_event.h>
+
+#include "nacl_io/nacl_io.h"
+#include "ppapi_simple/ps_context_2d.h"
+#include "ppapi_simple/ps_event.h"
+#include "ppapi_simple/ps_interface.h"
+#include "ppapi_simple/ps_main.h"
+
+#include "snes9x.h"
+#include "apu.h"
+#include "blit.h"
+#include "conffile.h"
+#include "controls.h"
+#include "display.h"
+#include "logger.h"
+#include "memmap.h"
+#include "movie.h"
+#include "ppu.h"
+#include "ring_buffer.h"
+
+#include "keycodes.h"
+
+enum {
+ VIDEOMODE_BLOCKY = 1,
+ VIDEOMODE_TV,
+ VIDEOMODE_SMOOTH,
+ VIDEOMODE_SUPEREAGLE,
+ VIDEOMODE_2XSAI,
+ VIDEOMODE_SUPER2XSAI,
+ VIDEOMODE_EPX,
+ VIDEOMODE_HQ2X
+};
+
+typedef void (* Blitter) (uint8 *, int, uint8 *, int, int, int);
+
+
+// Consts
+const int kSampleFrameCount = 1024;
+const int kSampleSize = 4; // Always 16-bit stereo
+const int kFilterBufferPitch = (SNES_WIDTH * 2) * 2;
+const uint32 kMousePointerBit = 0x00008000;
+const uint32 kKeyboardBit = 0x00000000;
+const uint32 kMouseBit = 0x40000000;
+const uint32 kJoystickBit = 0x80000000;
+
+const uint32_t kModifiersMask =
+ PP_INPUTEVENT_MODIFIER_SHIFTKEY |
+ PP_INPUTEVENT_MODIFIER_CONTROLKEY |
+ PP_INPUTEVENT_MODIFIER_ALTKEY |
+ PP_INPUTEVENT_MODIFIER_METAKEY;
+const int kModifierShift = 8;
+const uint32_t kKeyCodeMask = 0xff;
+
+
+// Statics
+static PSContext2D_t* s_context2d;
+static uint8* s_snes_buffer;
+static uint8* s_filter_buffer;
+static int s_video_mode = VIDEOMODE_BLOCKY;
+static bool s_no_repeat = true;
+static int s_sample_frame_count;
+static pp::Audio s_audio;
+static pthread_mutex_t s_audio_mutex;
+
+
+// Externs
+typedef std::pair<std::string, std::string> strpair_t;
+extern std::vector<strpair_t> keymaps;
+
+///////////////////////////////////////////////////////////////////////////////
+
+int snes9x_main(int argc, char *argv[]);
+int snes9x_pepper_main(int argc, char* argv[]) {
+ PSEventSetFilter(PSE_ALL);
+
+ umount("/");
+ mount("", "/", "memfs", 0, NULL);
+ mkdir("/mnt", 0777);
+ mount("", "/mnt/html5fs", "html5fs", 0, "type=TEMPORARY");
+ mkdir("/home", 0777);
+ setenv("HOME", "/home", 1);
+
+ if (argc < 1) {
+ fprintf(stderr, "Expect ROM filename as first argument!\n");
+ exit(1);
+ }
+
+ // Assume that argv[1] is the URL of the ROM.
+ char* filename = argv[1];
+ printf("Loading ROM: %s\n", filename);
+
+ char buffer[PATH_MAX];
+ snprintf(buffer, PATH_MAX - 1, "/mnt/html5fs/%s", filename);
+ buffer[PATH_MAX - 1] = 0;
+
+ printf("Setting argv[1] to \"%s\"\n", buffer);
+ argv[1] = &buffer[0];
+
+ return snes9x_main(argc, argv);
+}
+
+PPAPI_SIMPLE_REGISTER_MAIN(snes9x_pepper_main)
+
+void S9xExtraDisplayUsage() {
+}
+
+void S9xParseDisplayArg(char **argv, int &i, int argc) {
+ if (!strcasecmp(argv[i], "-setrepeat")) {
+// s_no_repeat = FALSE;
+ } else if (!strncasecmp(argv[i], "-v", 2)) {
+ switch (argv[i][2]) {
+ case '1': s_video_mode = VIDEOMODE_BLOCKY; break;
+ case '2': s_video_mode = VIDEOMODE_TV; break;
+ case '3': s_video_mode = VIDEOMODE_SMOOTH; break;
+ case '4': s_video_mode = VIDEOMODE_SUPEREAGLE; break;
+ case '5': s_video_mode = VIDEOMODE_2XSAI; break;
+ case '6': s_video_mode = VIDEOMODE_SUPER2XSAI; break;
+ case '7': s_video_mode = VIDEOMODE_EPX; break;
+ case '8': s_video_mode = VIDEOMODE_HQ2X; break;
+ }
+ } else {
+ S9xUsage();
+ }
+}
+
+const char * S9xParseDisplayConfig(ConfigFile &conf, int pass) {
+ if (pass != 1)
+ return "Unix/NaCl";
+
+ // NaCl needs to use 44100.
+ Settings.SoundPlaybackRate = 44100;
+
+ if (!conf.GetBool("Unix::ClearAllControls", false)) {
+ keymaps.push_back(strpair_t("K00:K", "Joypad1 Right"));
+ keymaps.push_back(strpair_t("K00:Right", "Joypad1 Right"));
+ keymaps.push_back(strpair_t("K00:H", "Joypad1 Left"));
+ keymaps.push_back(strpair_t("K00:Left", "Joypad1 Left"));
+ keymaps.push_back(strpair_t("K00:J", "Joypad1 Down"));
+ keymaps.push_back(strpair_t("K00:N", "Joypad1 Down"));
+ keymaps.push_back(strpair_t("K00:Down", "Joypad1 Down"));
+ keymaps.push_back(strpair_t("K00:U", "Joypad1 Up"));
+ keymaps.push_back(strpair_t("K00:Up", "Joypad1 Up"));
+ keymaps.push_back(strpair_t("K00:Return", "Joypad1 Start"));
+ keymaps.push_back(strpair_t("K00:space", "Joypad1 Select"));
+ keymaps.push_back(strpair_t("K00:S+D", "Joypad1 ToggleTurbo A"));
+ keymaps.push_back(strpair_t("K00:C+D", "Joypad1 ToggleSticky A"));
+ keymaps.push_back(strpair_t("K00:D", "Joypad1 A"));
+ keymaps.push_back(strpair_t("K00:S+C", "Joypad1 ToggleTurbo B"));
+ keymaps.push_back(strpair_t("K00:C+C", "Joypad1 ToggleSticky B"));
+ keymaps.push_back(strpair_t("K00:C", "Joypad1 B"));
+ keymaps.push_back(strpair_t("K00:S+S", "Joypad1 ToggleTurbo X"));
+ keymaps.push_back(strpair_t("K00:C+S", "Joypad1 ToggleSticky X"));
+ keymaps.push_back(strpair_t("K00:S", "Joypad1 X"));
+ keymaps.push_back(strpair_t("K00:S+X", "Joypad1 ToggleTurbo Y"));
+ keymaps.push_back(strpair_t("K00:C+X", "Joypad1 ToggleSticky Y"));
+ keymaps.push_back(strpair_t("K00:X", "Joypad1 Y"));
+ keymaps.push_back(strpair_t("K00:S+A", "Joypad1 ToggleTurbo L"));
+ keymaps.push_back(strpair_t("K00:S+V", "Joypad1 ToggleTurbo L"));
+ keymaps.push_back(strpair_t("K00:C+A", "Joypad1 ToggleSticky L"));
+ keymaps.push_back(strpair_t("K00:C+V", "Joypad1 ToggleSticky L"));
+ keymaps.push_back(strpair_t("K00:A", "Joypad1 L"));
+ keymaps.push_back(strpair_t("K00:V", "Joypad1 L"));
+ keymaps.push_back(strpair_t("K00:S+Z", "Joypad1 ToggleTurbo R"));
+ keymaps.push_back(strpair_t("K00:C+Z", "Joypad1 ToggleSticky R"));
+ keymaps.push_back(strpair_t("K00:Z", "Joypad1 R"));
+
+ keymaps.push_back(strpair_t("K00:Numpad4", "Joypad2 Left"));
+ keymaps.push_back(strpair_t("K00:Numpad6", "Joypad2 Right"));
+ keymaps.push_back(strpair_t("K00:Numpad8", "Joypad2 Up"));
+ keymaps.push_back(strpair_t("K00:Numpad2", "Joypad2 Down"));
+ keymaps.push_back(strpair_t("K00:Enter", "Joypad2 Start"));
+ keymaps.push_back(strpair_t("K00:Add", "Joypad2 Select"));
+ keymaps.push_back(strpair_t("K00:PageUp", "Joypad2 A"));
+ keymaps.push_back(strpair_t("K00:PageDown", "Joypad2 B"));
+ keymaps.push_back(strpair_t("K00:Home", "Joypad2 X"));
+ keymaps.push_back(strpair_t("K00:End", "Joypad2 Y"));
+ keymaps.push_back(strpair_t("K00:Insert", "Joypad2 L"));
+ keymaps.push_back(strpair_t("K00:Delete", "Joypad2 R"));
+
+ keymaps.push_back(strpair_t("K00:A+F4", "SoundChannel0"));
+ keymaps.push_back(strpair_t("K00:C+F4", "SoundChannel0"));
+ keymaps.push_back(strpair_t("K00:A+F5", "SoundChannel1"));
+ keymaps.push_back(strpair_t("K00:C+F5", "SoundChannel1"));
+ keymaps.push_back(strpair_t("K00:A+F6", "SoundChannel2"));
+ keymaps.push_back(strpair_t("K00:C+F6", "SoundChannel2"));
+ keymaps.push_back(strpair_t("K00:A+F7", "SoundChannel3"));
+ keymaps.push_back(strpair_t("K00:C+F7", "SoundChannel3"));
+ keymaps.push_back(strpair_t("K00:A+F8", "SoundChannel4"));
+ keymaps.push_back(strpair_t("K00:C+F8", "SoundChannel4"));
+ keymaps.push_back(strpair_t("K00:A+F9", "SoundChannel5"));
+ keymaps.push_back(strpair_t("K00:C+F9", "SoundChannel5"));
+ keymaps.push_back(strpair_t("K00:A+F10", "SoundChannel6"));
+ keymaps.push_back(strpair_t("K00:C+F10", "SoundChannel6"));
+ keymaps.push_back(strpair_t("K00:A+F11", "SoundChannel7"));
+ keymaps.push_back(strpair_t("K00:C+F11", "SoundChannel7"));
+ keymaps.push_back(strpair_t("K00:A+F12", "SoundChannelsOn"));
+ keymaps.push_back(strpair_t("K00:C+F12", "SoundChannelsOn"));
+
+ keymaps.push_back(strpair_t("K00:S+1", "BeginRecordingMovie"));
+ keymaps.push_back(strpair_t("K00:S+2", "EndRecordingMovie"));
+ keymaps.push_back(strpair_t("K00:S+3", "LoadMovie"));
+ keymaps.push_back(strpair_t("K00:A+F1", "SaveSPC"));
+ keymaps.push_back(strpair_t("K00:C+F1", "SaveSPC"));
+ keymaps.push_back(strpair_t("K00:F10", "LoadOopsFile"));
+ keymaps.push_back(strpair_t("K00:A+F2", "LoadFreezeFile"));
+ keymaps.push_back(strpair_t("K00:C+F2", "LoadFreezeFile"));
+ keymaps.push_back(strpair_t("K00:F11", "LoadFreezeFile"));
+ keymaps.push_back(strpair_t("K00:A+F3", "SaveFreezeFile"));
+ keymaps.push_back(strpair_t("K00:C+F3", "SaveFreezeFile"));
+ keymaps.push_back(strpair_t("K00:F12", "SaveFreezeFile"));
+ keymaps.push_back(strpair_t("K00:F1", "QuickLoad000"));
+ keymaps.push_back(strpair_t("K00:F2", "QuickLoad001"));
+ keymaps.push_back(strpair_t("K00:F3", "QuickLoad002"));
+ keymaps.push_back(strpair_t("K00:F4", "QuickLoad003"));
+ keymaps.push_back(strpair_t("K00:F5", "QuickLoad004"));
+ keymaps.push_back(strpair_t("K00:F6", "QuickLoad005"));
+ keymaps.push_back(strpair_t("K00:F7", "QuickLoad006"));
+ keymaps.push_back(strpair_t("K00:F8", "QuickLoad007"));
+ keymaps.push_back(strpair_t("K00:F9", "QuickLoad008"));
+ keymaps.push_back(strpair_t("K00:S+F1", "QuickSave000"));
+ keymaps.push_back(strpair_t("K00:S+F2", "QuickSave001"));
+ keymaps.push_back(strpair_t("K00:S+F3", "QuickSave002"));
+ keymaps.push_back(strpair_t("K00:S+F4", "QuickSave003"));
+ keymaps.push_back(strpair_t("K00:S+F5", "QuickSave004"));
+ keymaps.push_back(strpair_t("K00:S+F6", "QuickSave005"));
+ keymaps.push_back(strpair_t("K00:S+F7", "QuickSave006"));
+ keymaps.push_back(strpair_t("K00:S+F8", "QuickSave007"));
+ keymaps.push_back(strpair_t("K00:S+F9", "QuickSave008"));
+
+ keymaps.push_back(strpair_t("K00:ScrollLock", "Pause"));
+ keymaps.push_back(strpair_t("K00:CS+Escape", "Reset"));
+ keymaps.push_back(strpair_t("K00:S+Escape", "SoftReset"));
+ keymaps.push_back(strpair_t("K00:Escape", "ExitEmu"));
+ keymaps.push_back(strpair_t("K00:Tab", "EmuTurbo"));
+ keymaps.push_back(strpair_t("K00:S+Tab", "ToggleEmuTurbo"));
+ keymaps.push_back(strpair_t("K00:A+Equals", "IncEmuTurbo"));
+ keymaps.push_back(strpair_t("K00:A+Subtract", "DecEmuTurbo"));
+ keymaps.push_back(strpair_t("K00:C+Equals", "IncTurboSpeed"));
+ keymaps.push_back(strpair_t("K00:C+Subtract", "DecTurboSpeed"));
+ keymaps.push_back(strpair_t("K00:Equals", "IncFrameRate"));
+ keymaps.push_back(strpair_t("K00:Subtract", "DecFrameRate"));
+ keymaps.push_back(strpair_t("K00:S+Equals", "IncFrameTime"));
+ keymaps.push_back(strpair_t("K00:S+Subtract", "DecFrameTime"));
+ keymaps.push_back(strpair_t("K00:6", "SwapJoypads"));
+ keymaps.push_back(strpair_t("K00:Printscreen", "Screenshot"));
+
+ keymaps.push_back(strpair_t("K00:1", "ToggleBG0"));
+ keymaps.push_back(strpair_t("K00:2", "ToggleBG1"));
+ keymaps.push_back(strpair_t("K00:3", "ToggleBG2"));
+ keymaps.push_back(strpair_t("K00:4", "ToggleBG3"));
+ keymaps.push_back(strpair_t("K00:5", "ToggleSprites"));
+ keymaps.push_back(strpair_t("K00:9", "ToggleTransparency"));
+ keymaps.push_back(strpair_t("K00:BackSpace", "ClipWindows"));
+ keymaps.push_back(strpair_t("K00:A+Escape", "Debugger"));
+
+ keymaps.push_back(strpair_t("M00:B0", "{Mouse1 L,Superscope Fire,Justifier1 Trigger}"));
+ keymaps.push_back(strpair_t("M00:B1", "{Justifier1 AimOffscreen Trigger,Superscope AimOffscreen}"));
+ keymaps.push_back(strpair_t("M00:B2", "{Mouse1 R,Superscope Cursor,Justifier1 Start}"));
+ keymaps.push_back(strpair_t("M00:Pointer", "Pointer Mouse1+Superscope+Justifier1"));
+ keymaps.push_back(strpair_t("K00:BackQuote", "Superscope ToggleTurbo"));
+ keymaps.push_back(strpair_t("K00:Slash", "Superscope Pause"));
+ }
+
+ // s_no_repeat = !conf.GetBool("Unix/NaCl::SetKeyRepeat", TRUE);
+
+ if (conf.Exists("Unix/NaCl::VideoMode")) {
+ s_video_mode = conf.GetUInt("Unix/NaCl::VideoMode", VIDEOMODE_BLOCKY);
+ if (s_video_mode < 1 || s_video_mode > 8)
+ s_video_mode = VIDEOMODE_BLOCKY;
+ } else {
+ s_video_mode = VIDEOMODE_BLOCKY;
+ }
+
+ return "Unix/NaCl";
+}
+
+const char * S9xSelectFilename(const char *def, const char *dir1, const
+ char *ext1, const char *title) {
+ printf("S9xSelectFilename(%s, %s, %s, %s)\n", def, dir1, ext1, title);
+ return NULL;
+}
+
+void S9xMessage(int type, int number, const char *message) {
+ printf("S9xMessage \"%s\"\n", message);
+ const int max = 36 * 3;
+ static char buffer[max + 1];
+
+ fprintf(stdout, "%s\n", message);
+ strncpy(buffer, message, max + 1);
+ buffer[max] = 0;
+ S9xSetInfoString(buffer);
+}
+
+const char * S9xStringInput(const char *message) {
+ printf("S9xStringInput \"%s\"\n", message);
+ return NULL;
+}
+
+void S9xSetTitle (const char *string) {
+ printf("S9xSetTitle \"%s\"\n", string);
+}
+
+
+// Graphics stuff
+void S9xInitDisplay(int argc, char **argv) {
+ s_context2d = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL);
+ S9xSetRenderPixelFormat(RGB565);
+ S9xBlitFilterInit();
+ S9xBlit2xSaIFilterInit();
+ S9xBlitHQ2xFilterInit();
+
+ GFX.Pitch = SNES_WIDTH * 2 * 2;
+ s_snes_buffer =
+ (uint8 *) calloc(GFX.Pitch * ((SNES_HEIGHT_EXTENDED + 4) * 2), 1);
+
+ GFX.Screen = (uint16 *) (s_snes_buffer + (GFX.Pitch * 2 * 2));
+
+ s_filter_buffer =
+ (uint8 *) calloc((SNES_WIDTH * 2) * 2 * (SNES_HEIGHT_EXTENDED * 2), 1);
+
+ S9xGraphicsInit();
+}
+
+void S9xDeinitDisplay() {
+ S9xTextMode();
+ S9xBlitFilterDeinit();
+ S9xBlit2xSaIFilterDeinit();
+ S9xBlitHQ2xFilterDeinit();
+ PSContext2DFree(s_context2d);
+}
+
+static void Convert16To24(int width, int height);
+void S9xPutImage (int width, int height) {
+ PSContext2DGetBuffer(s_context2d);
+ if (NULL == s_context2d->data)
+ return;
+
+ static int prevWidth = 0, prevHeight = 0;
+ int copyWidth, copyHeight;
+ Blitter blitFn = NULL;
+
+ if (s_video_mode == VIDEOMODE_BLOCKY ||
+ s_video_mode == VIDEOMODE_TV ||
+ s_video_mode == VIDEOMODE_SMOOTH) {
+ if ((width <= SNES_WIDTH) &&
+ ((prevWidth != width) || (prevHeight != height)))
+ S9xBlitClearDelta();
+ }
+
+ if (width <= SNES_WIDTH) {
+ if (height > SNES_HEIGHT_EXTENDED) {
+ copyWidth = width * 2;
+ copyHeight = height;
+ blitFn = S9xBlitPixSimple2x1;
+ } else {
+ copyWidth = width * 2;
+ copyHeight = height * 2;
+
+ switch (s_video_mode) {
+ case VIDEOMODE_BLOCKY:
+ blitFn = S9xBlitPixSimple2x2;
+ break;
+ case VIDEOMODE_TV:
+ blitFn = S9xBlitPixTV2x2;
+ break;
+ case VIDEOMODE_SMOOTH:
+ blitFn = S9xBlitPixSmooth2x2;
+ break;
+ case VIDEOMODE_SUPEREAGLE:
+ blitFn = S9xBlitPixSuperEagle16;
+ break;
+ case VIDEOMODE_2XSAI:
+ blitFn = S9xBlitPix2xSaI16;
+ break;
+ case VIDEOMODE_SUPER2XSAI:
+ blitFn = S9xBlitPixSuper2xSaI16;
+ break;
+ case VIDEOMODE_EPX:
+ blitFn = S9xBlitPixEPX16;
+ break;
+ case VIDEOMODE_HQ2X:
+ blitFn = S9xBlitPixHQ2x16;
+ break;
+ }
+ }
+ } else if (height <= SNES_HEIGHT_EXTENDED) {
+ copyWidth = width;
+ copyHeight = height * 2;
+
+ switch (s_video_mode) {
+ default:
+ blitFn = S9xBlitPixSimple1x2;
+ break;
+ case VIDEOMODE_TV:
+ blitFn = S9xBlitPixTV1x2;
+ break;
+ }
+ } else {
+ copyWidth = width;
+ copyHeight = height;
+ blitFn = S9xBlitPixSimple1x1;
+ }
+
+ blitFn((uint8 *) GFX.Screen, GFX.Pitch, s_filter_buffer,
+ kFilterBufferPitch, width, height);
+
+ if (height < prevHeight) {
+ int p = kFilterBufferPitch >> 2;
+ for (int y = SNES_HEIGHT * 2; y < SNES_HEIGHT_EXTENDED * 2; y++) {
+ uint32 *d = (uint32 *) (s_filter_buffer + y * kFilterBufferPitch);
+ for (int x = 0; x < p; x++)
+ *d++ = 0;
+ }
+ }
+
+ Convert16To24(copyWidth, copyHeight);
+ PSContext2DSwapBuffer(s_context2d);
+
+ prevWidth = width;
+ prevHeight = height;
+}
+
+static void Convert16To24(int width, int height) {
+ // Draw centered in context2d canvas.
+ int x_offset, y_offset;
+
+ if (s_context2d->width < width)
+ width = s_context2d->width;
+ else
+ x_offset = (s_context2d->width - width) / 2;
+
+ if (s_context2d->height < height)
+ height = s_context2d->height;
+ else
+ y_offset = (s_context2d->height - height) / 2;
+
+ for (int y = 0; y < height; y++) {
+ uint16 *s = (uint16 *) (s_filter_buffer + y * kFilterBufferPitch);
+ uint32 *d = (uint32 *) (s_context2d->data +
+ (y + y_offset) * s_context2d->width +
+ x_offset);
+
+ for (int x = 0; x < width; x++) {
+ uint32 pixel = *s++;
+ int alpha = 255;
+ int red = ((pixel >> 11) & 0x1f) << 3;
+ int green = ((pixel >> 6) & 0x1f) << 3;
+ int blue = ( pixel & 0x1f) << 3;
+ *d++ = (alpha << 24) | (red << 16) | (green << 8) | blue;
+ }
+ }
+}
+
+// Control/Input stuff
+void S9xProcessEvents(bool8 block) {
+ PSEvent* ps_event;
+ // Consume all available events.
+ while ((ps_event = PSEventTryAcquire()) != NULL) {
+ if (0 != PSContext2DHandleEvent(s_context2d, ps_event))
+ return;
+ if (ps_event->type == PSE_INSTANCE_HANDLEINPUT) {
+ // Convert Pepper Simple event to a PPAPI C++ event
+ pp::InputEvent event(ps_event->as_resource);
+ switch (event.GetType()) {
+ case PP_INPUTEVENT_TYPE_KEYDOWN:
+ case PP_INPUTEVENT_TYPE_KEYUP: {
+ pp::KeyboardInputEvent key(event);
+ uint32_t modifiers = key.GetModifiers();
+ uint32_t key_code = key.GetKeyCode();
+ bool key_down = event.GetType() == PP_INPUTEVENT_TYPE_KEYDOWN;
+ uint32 id = kKeyboardBit;
+ id |= ((modifiers & kModifiersMask) << kModifierShift);
+ id |= (key_code & kKeyCodeMask);
+ S9xReportButton(id, key_down);
+ break;
+ }
+ case PP_INPUTEVENT_TYPE_MOUSEDOWN:
+ case PP_INPUTEVENT_TYPE_MOUSEUP: {
+ pp::MouseInputEvent mouse(event);
+ uint32 id = kMouseBit | (uint32) mouse.GetButton();
+ bool mouse_down = event.GetType() == PP_INPUTEVENT_TYPE_MOUSEDOWN;
+ S9xReportButton(id, mouse_down);
+ break;
+ }
+ case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
+ pp::MouseInputEvent mouse(event);
+ uint32 id = kMouseBit | kMousePointerBit;
+ int16 x = mouse.GetPosition().x();
+ int16 y = mouse.GetPosition().y();
+ S9xReportPointer(id, x, y);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ PSEventRelease(ps_event);
+ }
+}
+
+s9xcommand_t S9xGetDisplayCommandT(const char *n) {
+ s9xcommand_t cmd;
+
+ cmd.type = S9xBadMapping;
+ cmd.multi_press = 0;
+ cmd.button_norpt = 0;
+ cmd.port[0] = 0xff;
+ cmd.port[1] = 0;
+ cmd.port[2] = 0;
+ cmd.port[3] = 0;
+
+ return cmd;
+}
+
+char * S9xGetDisplayCommandName(s9xcommand_t cmd) {
+ return strdup("None");
+}
+
+bool8 S9xMapDisplayInput(const char *n, s9xcommand_t *cmd) {
+ int i, d;
+
+ if (!isdigit(n[1]) || !isdigit(n[2]) || n[3] != ':')
+ goto unrecog;
+
+ d = ((n[1] - '0') * 10 + (n[2] - '0')) << 24;
+
+ switch (n[0]) {
+ case 'K': {
+ d |= kKeyboardBit;
+
+ for (i = 4; n[i] != '\0' && n[i] != '+'; i++) ;
+
+ if (n[i] == '\0' || i == 4) {
+ i = 4;
+ } else {
+ for (i = 4; n[i] != '+'; i++) {
+ switch (n[i]) {
+ case 'S':
+ d |= PP_INPUTEVENT_MODIFIER_SHIFTKEY << kModifierShift;
+ break;
+ case 'C':
+ d |= PP_INPUTEVENT_MODIFIER_CONTROLKEY << kModifierShift;
+ break;
+ case 'A':
+ d |= PP_INPUTEVENT_MODIFIER_ALTKEY << kModifierShift;
+ break;
+ case 'M':
+ d |= PP_INPUTEVENT_MODIFIER_METAKEY << kModifierShift;
+ break;
+ default:
+ goto unrecog;
+ }
+ }
+
+ i++;
+ }
+
+ int key_code;
+ if ((key_code = StringToCode(n + i)) == -1)
+ goto unrecog;
+
+ d |= key_code & 0xff;
+
+ return S9xMapButton(d, *cmd, false);
+ }
+
+ case 'M': {
+ char *c;
+ int j;
+
+ d |= kMouseBit;
+
+ if (!strncmp(n + 4, "Pointer", 7)) {
+ d |= kMousePointerBit;
+
+ if (n[11] == '\0')
+ return S9xMapPointer(d, *cmd, false);
+
+ i = 11;
+ } else if (n[4] == 'B') {
+ i = 5;
+ } else {
+ goto unrecog;
+ }
+
+ d |= j = strtol(n + i, &c, 10);
+
+ if ((c != NULL && *c != '\0') || j > kMousePointerBit - 1)
+ goto unrecog;
+
+ if (d & kMousePointerBit)
+ return S9xMapPointer(d, *cmd, false);
+
+ return S9xMapButton(d, *cmd, false);
+ }
+
+ default:
+ break;
+ }
+
+unrecog:
+ char *err = new char[strlen(n) + 34];
+
+ sprintf(err, "Unrecognized input device name '%s'", n);
+ perror(err);
+ delete [] err;
+
+ return false;
+}
+
+// Sound stuff
+static void S9xSoundCallback(void* user_data);
+static void PepperSoundCallback(void* samples,
+ uint32_t buffer_size,
+ void* user_data);
+void S9xOpenSoundDeviceNaCl() {
+ pp::Instance instance(PSGetInstanceId());
+ // Ask the browser/device for an appropriate sample frame count size.
+ s_sample_frame_count =
+ pp::AudioConfig::RecommendSampleFrameCount(
+ &instance,
+ PP_AUDIOSAMPLERATE_44100,
+ kSampleFrameCount);
+
+ // Create an audio configuration resource.
+ pp::AudioConfig audio_config = pp::AudioConfig(
+ &instance,
+ PP_AUDIOSAMPLERATE_44100,
+ s_sample_frame_count);
+
+ // Create an audio resource.
+ s_audio = pp::Audio(
+ &instance,
+ audio_config,
+ PepperSoundCallback,
+ NULL);
+
+ pthread_mutex_init(&s_audio_mutex, NULL);
+ S9xSetSamplesAvailableCallback(S9xSoundCallback, NULL);
+
+ s_audio.StartPlayback();
+}
+
+static void S9xSoundCallback(void* user_data) {
+ pthread_mutex_lock(&s_audio_mutex);
+ S9xFinalizeSamples();
+ pthread_mutex_unlock(&s_audio_mutex);
+}
+
+static void PepperSoundCallback(void* samples,
+ uint32_t buffer_size,
+ void* user_data) {
+ pthread_mutex_lock(&s_audio_mutex);
+ S9xMixSamples((uint8*)samples, buffer_size >> 1);
+ pthread_mutex_unlock(&s_audio_mutex);
+}
+
+
+// Dummy functions
+void S9xSetPalette() {}
+void S9xTextMode() {}
+void S9xGraphicsMode() {}
+bool S9xDisplayPollButton(uint32 id, bool *pressed) { return false; }
+bool S9xDisplayPollAxis (uint32 id, int16 *value) { return false; }
+bool S9xDisplayPollPointer (uint32 id, int16 *x, int16 *y) { return false; }
+
+
+#endif
diff --git a/unix/unix.cpp b/unix/unix.cpp
--- a/unix/unix.cpp
+++ b/unix/unix.cpp
@@ -229,6 +229,14 @@
#endif
#endif
+#if defined(__native_client__) && defined(_NEWLIB_VERSION)
+// Definition of timercmp taken from GLibC.
+#define timercmp(a, b, CMP) \
+ (((a)->tv_sec == (b)->tv_sec) ? \
+ ((a)->tv_usec CMP (b)->tv_usec) : \
+ ((a)->tv_sec CMP (b)->tv_sec))
+#endif
+
typedef std::pair<std::string, std::string> strpair_t;
ConfigFile::secvec_t keymaps;
@@ -318,6 +326,10 @@ bool S9xDisplayPollButton (uint32, bool *);
bool S9xDisplayPollAxis (uint32, int16 *);
bool S9xDisplayPollPointer (uint32, int16 *, int16 *);
+#ifdef __native_client__
+void S9xOpenSoundDeviceNaCl();
+#endif
+
static long log2 (long);
static void SoundTrigger (void);
static void InitTimer (void);
@@ -1396,6 +1408,10 @@ static void InitTimer (void)
bool8 S9xOpenSoundDevice (void)
{
+#ifdef __native_client__
+ S9xOpenSoundDeviceNaCl();
+#endif
+
#ifndef NOSOUND
int J, K;
@@ -1545,7 +1561,11 @@ static void sigbrkhandler (int)
}
#endif
+#if defined(__native_client__)
+int snes9x_main (int argc, char **argv)
+#else
int main (int argc, char **argv)
+#endif
{
if (argc < 2)
S9xUsage();