aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabio Battaglia2009-12-30 21:11:38 +0000
committerFabio Battaglia2009-12-30 21:11:38 +0000
commita108df30a753bc062d2e2c041c70a4477f08b671 (patch)
tree13e38c42b014fa280f3a1be3aa950754dca3837e
parent0de5bac3498e9e9d158e4055c08475e04a00e7b3 (diff)
downloadscummvm-rg350-a108df30a753bc062d2e2c041c70a4477f08b671.tar.gz
scummvm-rg350-a108df30a753bc062d2e2c041c70a4477f08b671.tar.bz2
scummvm-rg350-a108df30a753bc062d2e2c041c70a4477f08b671.zip
Add Nintendo 64 port to trunk.
svn-id: r46773
-rw-r--r--backends/fs/n64/n64-fs-factory.cpp47
-rw-r--r--backends/fs/n64/n64-fs-factory.h42
-rw-r--r--backends/fs/n64/n64-fs.cpp213
-rw-r--r--backends/fs/stdiostream.cpp22
-rw-r--r--backends/module.mk1
-rw-r--r--backends/platform/n64/Makefile93
-rw-r--r--backends/platform/n64/module.mk10
-rw-r--r--backends/platform/n64/nintendo64.cpp35
-rw-r--r--backends/platform/n64/osys_n64.h206
-rw-r--r--backends/platform/n64/osys_n64_base.cpp804
-rw-r--r--backends/platform/n64/osys_n64_events.cpp243
-rw-r--r--backends/platform/n64/osys_n64_utilities.cpp123
-rw-r--r--backends/platform/n64/pad_rom.sh13
-rw-r--r--backends/platform/n64/pakfs_save_manager.cpp92
-rw-r--r--backends/platform/n64/pakfs_save_manager.h124
-rw-r--r--backends/platform/n64/portdefs.h46
-rw-r--r--common/debug.cpp7
-rw-r--r--common/scummsys.h25
-rw-r--r--common/util.cpp3
-rw-r--r--engines/scumm/saveload.cpp2
-rw-r--r--graphics/colormasks.h7
-rw-r--r--sound/softsynth/opl/mame.cpp4
22 files changed, 2159 insertions, 3 deletions
diff --git a/backends/fs/n64/n64-fs-factory.cpp b/backends/fs/n64/n64-fs-factory.cpp
new file mode 100644
index 0000000000..7e314693b8
--- /dev/null
+++ b/backends/fs/n64/n64-fs-factory.cpp
@@ -0,0 +1,47 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#ifdef __N64__
+
+#include <n64utils.h>
+
+#include "backends/fs/n64/n64-fs-factory.h"
+#include "backends/fs/n64/n64-fs.cpp"
+
+AbstractFSNode *N64FilesystemFactory::makeRootFileNode() const {
+ return new N64FilesystemNode();
+}
+
+AbstractFSNode *N64FilesystemFactory::makeCurrentDirectoryFileNode() const {
+ char buf[MAXPATHLEN];
+ return romfs_getcwd(buf, MAXPATHLEN) ? new N64FilesystemNode(Common::String(buf), false) : NULL;
+}
+
+AbstractFSNode *N64FilesystemFactory::makeFileNodePath(const Common::String &path) const {
+ assert(!path.empty());
+ return new N64FilesystemNode(path, false);
+}
+
+#endif
+
diff --git a/backends/fs/n64/n64-fs-factory.h b/backends/fs/n64/n64-fs-factory.h
new file mode 100644
index 0000000000..915153c6f8
--- /dev/null
+++ b/backends/fs/n64/n64-fs-factory.h
@@ -0,0 +1,42 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#ifndef N64_FILESYSTEM_FACTORY_H
+#define N64_FILESYSTEM_FACTORY_H
+
+#include <romfs.h>
+#include "backends/fs/fs-factory.h"
+
+/**
+ * Creates N64FilesystemNode objects.
+ *
+ * Parts of this class are documented in the base interface class, FilesystemFactory.
+ */
+class N64FilesystemFactory : public FilesystemFactory {
+ virtual AbstractFSNode *makeRootFileNode() const;
+ virtual AbstractFSNode *makeCurrentDirectoryFileNode() const;
+ virtual AbstractFSNode *makeFileNodePath(const Common::String &path) const;
+};
+
+#endif /*N64_FILESYSTEM_FACTORY_H*/
diff --git a/backends/fs/n64/n64-fs.cpp b/backends/fs/n64/n64-fs.cpp
new file mode 100644
index 0000000000..514e3be02d
--- /dev/null
+++ b/backends/fs/n64/n64-fs.cpp
@@ -0,0 +1,213 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef __N64__
+
+#include "backends/fs/abstract-fs.h"
+#include "backends/fs/stdiostream.h"
+
+#include <sys/param.h>
+
+#include <unistd.h>
+
+#include <n64utils.h>
+
+#define ROOT_PATH "/"
+
+/**
+ * Implementation of the ScummVM file system API based on N64 Hkz romfs.
+ *
+ * Parts of this class are documented in the base interface class, AbstractFSNode.
+ */
+class N64FilesystemNode : public AbstractFSNode {
+protected:
+ Common::String _displayName;
+ Common::String _path;
+ bool _isDirectory;
+ bool _isValid;
+
+public:
+ /**
+ * Creates a N64FilesystemNode with the root node as path.
+ */
+ N64FilesystemNode();
+
+ /**
+ * Creates a N64FilesystemNode for a given path.
+ *
+ * @param path Common::String with the path the new node should point to.
+ * @param verify true if the isValid and isDirectory flags should be verified during the construction.
+ */
+ N64FilesystemNode(const Common::String &p, bool verify = true);
+
+ virtual bool exists() const;
+ virtual Common::String getDisplayName() const {
+ return _displayName;
+ }
+ virtual Common::String getName() const {
+ return _displayName;
+ }
+ virtual Common::String getPath() const {
+ return _path;
+ }
+ virtual bool isDirectory() const {
+ return _isDirectory;
+ }
+ virtual bool isReadable() const;
+ virtual bool isWritable() const;
+
+ virtual AbstractFSNode *getChild(const Common::String &n) const;
+ virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
+ virtual AbstractFSNode *getParent() const;
+
+ virtual Common::SeekableReadStream *createReadStream();
+ virtual Common::WriteStream *createWriteStream();
+};
+
+N64FilesystemNode::N64FilesystemNode() {
+ _isDirectory = true;
+ _displayName = "Root";
+ _isValid = true;
+ _path = ROOT_PATH;
+}
+
+N64FilesystemNode::N64FilesystemNode(const Common::String &p, bool verify) {
+ assert(p.size() > 0);
+
+ _path = p;
+ _displayName = lastPathComponent(_path, '/');
+ _isValid = true;
+ _isDirectory = true;
+
+ // Check if it's a dir
+ ROMFILE *tmpfd = romfs_open(p.c_str(), "r");
+ if (tmpfd) {
+ _isDirectory = (tmpfd->type == 0 || tmpfd->type == 1);
+ romfs_close(tmpfd);
+ }
+}
+
+bool N64FilesystemNode::exists() const {
+ int ret = -1;
+
+ ret = romfs_access(_path.c_str(), F_OK);
+
+ return ret == 0;
+}
+
+bool N64FilesystemNode::isReadable() const {
+ int ret = -1;
+
+ ret = romfs_access(_path.c_str(), R_OK);
+
+ return ret == 0;
+}
+
+// We can't write on ROMFS!
+bool N64FilesystemNode::isWritable() const {
+ return false;
+}
+
+
+AbstractFSNode *N64FilesystemNode::getChild(const Common::String &n) const {
+ // FIXME: Pretty lame implementation! We do no error checking to speak
+ // of, do not check if this is a special node, etc.
+ assert(_isDirectory);
+
+ Common::String newPath(_path);
+ if (_path.lastChar() != '/')
+ newPath += '/';
+ newPath += n;
+
+ return new N64FilesystemNode(newPath, true);
+}
+
+bool N64FilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
+ assert(_isDirectory);
+ ROMDIR *dirp = romfs_opendir(_path.c_str());
+ romfs_dirent *dp;
+
+ if (dirp == NULL)
+ return false;
+
+ // loop over dir entries using readdir
+ while ((dp = romfs_readdir(dirp)) != NULL) {
+ // Skip 'invisible' files if necessary
+ if (dp->entryname[0] == '.' && !hidden) {
+ free(dp);
+ continue;
+ }
+ // Skip '.' and '..' to avoid cycles
+ if ((dp->entryname[0] == '.' && dp->entryname[1] == 0) || (dp->entryname[0] == '.' && dp->entryname[1] == '.')) {
+ free(dp);
+ continue;
+ }
+
+ // Start with a clone of this node, with the correct path set
+ N64FilesystemNode entry(*this);
+ entry._displayName = dp->entryname;
+ if (_path.lastChar() != '/')
+ entry._path += '/';
+ entry._path += entry._displayName;
+
+ // Force validity for now...
+ entry._isValid = 1;
+
+ entry._isDirectory = (dp->type == 0 || dp->type == 1);
+
+ // Honor the chosen mode
+ if ((mode == Common::FSNode::kListFilesOnly && entry._isDirectory) ||
+ (mode == Common::FSNode::kListDirectoriesOnly && !entry._isDirectory)) {
+
+ free(dp);
+ continue;
+ }
+
+ myList.push_back(new N64FilesystemNode(entry));
+
+ free(dp);
+ }
+ romfs_closedir(dirp);
+
+ return true;
+}
+
+AbstractFSNode *N64FilesystemNode::getParent() const {
+ if (_path == ROOT_PATH)
+ return 0;
+
+ const char *start = _path.c_str();
+ const char *end = lastPathComponent(_path, '/');
+
+ return new N64FilesystemNode(Common::String(start, end - start), false);
+}
+
+Common::SeekableReadStream *N64FilesystemNode::createReadStream() {
+ return StdioStream::makeFromPath(getPath(), false);
+}
+
+Common::WriteStream *N64FilesystemNode::createWriteStream() {
+ return StdioStream::makeFromPath(getPath(), true);
+}
+
+#endif //#ifdef __N64__
+
diff --git a/backends/fs/stdiostream.cpp b/backends/fs/stdiostream.cpp
index 8845d796c6..73796a31ea 100644
--- a/backends/fs/stdiostream.cpp
+++ b/backends/fs/stdiostream.cpp
@@ -25,6 +25,28 @@
#include "backends/fs/stdiostream.h"
+#ifdef __N64__
+ #include <romfs.h>
+
+ #undef feof
+ #undef clearerr
+ #undef ferror
+
+ #undef FILE
+ #define FILE ROMFILE
+
+ #define fopen(name, mode) romfs_open(name, mode)
+ #define fclose(handle) romfs_close(handle)
+ #define fread(ptr, size, items, file) romfs_read(ptr, size, items, file)
+ #define fwrite(ptr, size, items, file) romfs_write(ptr, size, items, file)
+ #define feof(handle) romfs_eof(handle)
+ #define ftell(handle) romfs_tell(handle)
+ #define fseek(handle, offset, whence) romfs_seek(handle, offset, whence)
+ #define clearerr(handle) romfs_clearerr(handle)
+ #define fflush(file) romfs_flush(file)
+ #define ferror(handle) romfs_error(handle)
+#endif
+
StdioStream::StdioStream(void *handle) : _handle(handle) {
assert(handle);
}
diff --git a/backends/module.mk b/backends/module.mk
index 0595846671..a902858b22 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -15,6 +15,7 @@ MODULE_OBJS := \
fs/symbian/symbian-fs-factory.o \
fs/windows/windows-fs-factory.o \
fs/wii/wii-fs-factory.o \
+ fs/n64/n64-fs-factory.o \
keymapper/action.o \
keymapper/keymap.o \
keymapper/keymapper.o \
diff --git a/backends/platform/n64/Makefile b/backends/platform/n64/Makefile
new file mode 100644
index 0000000000..833f660a49
--- /dev/null
+++ b/backends/platform/n64/Makefile
@@ -0,0 +1,93 @@
+
+TOOLPATH = /opt/mips64-toolchain
+LIBN64PATH = $(TOOLPATH)/hkz-libn64/
+GCCN64PREFIX = $(TOOLPATH)/bin/mips64-
+
+srcdir = ../../..
+VPATH = $(srcdir)
+
+CC = $(GCCN64PREFIX)gcc
+CXX = $(GCCN64PREFIX)g++
+AS = $(GCCN64PREFIX)as
+LD = $(GCCN64PREFIX)g++
+OBJCOPY = $(GCCN64PREFIX)objcopy
+AR = $(GCCN64PREFIX)ar cru
+RANLIB = $(GCCN64PREFIX)ranlib
+
+DEFINES += -D__N64__ -DLIMIT_FPS -DNONSTANDARD_PORT -DDISABLE_DEFAULT_SAVEFILEMANAGER -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE -DDISABLE_FANCY_THEMES -DDISABLE_DOSBOX_OPL -DENABLE_VKEYBD -DUSE_ZLIB
+LIBS += -lpakfs -ln64 -ln64utils -lromfs
+
+DEFINES += -D_ENABLE_DEBUG_
+
+USE_LIBMAD=0
+USE_LIBOGG=1
+
+ifeq ($(USE_LIBMAD),1)
+DEFINES += -DUSE_MAD
+LIBS += -lmad
+endif
+ifeq ($(USE_LIBOGG), 1)
+DEFINES += -DUSE_VORBIS -DUSE_TREMOR
+LIBS += -lvorbisidec
+endif
+
+LIBS += -lm -lstdc++ -lc -lgcc -lz -lnosys
+
+CXXFLAGS = -g -O2 -fomit-frame-pointer -march=vr4300 -mtune=vr4300 -mno-extern-sdata -fno-rtti -fno-exceptions -Wno-multichar -Wshadow -I$(LIBN64PATH) -I$(TOOLPATH)/include -I./ -I$(srcdir) -I$(srcdir)/engines
+LDFLAGS = -g -march=vr4300 -mtune=vr4300 -nodefaultlibs -nostartfiles -mno-crt0 -L$(LIBN64PATH) -L$(TOOLPATH)/lib $(LIBS) -T n64ld_cpp.x -Xlinker -Map -Xlinker scummvm.map
+
+TARGET = scummvm
+DEPDIR = .deps
+CXX_UPDATE_DEP_FLAG = -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP
+MKDIR = mkdir -p
+RM = rm -f
+RM_REC = rm -rf
+
+VERBOSE_BUILD=0
+HAVE_GCC3=1
+DISABLE_SCALERS=1
+DISABLE_HQ_SCALER=1
+USE_MT32EMU=0
+USE_RGB_COLOR=0
+
+ENABLED=STATIC_PLUGIN
+
+#ENABLE_SCUMM=$(ENABLED)
+#ENABLE_SKY=$(ENABLED)
+#ENABLE_SCI=$(ENABLED)
+#ENABLE_GOB=$(ENABLED)
+#ENABLE_PARALLACTION=$(ENABLED)
+#ENABLE_KYRA=$(ENABLED)
+#ENABLE_AGOS = $(ENABLED)
+#ENABLE_AGI = $(ENABLED)
+#ENABLE_QUEEN = $(ENABLED)
+#ENABLE_MADE = $(ENABLED)
+ENABLE_SAGA = $(ENABLED)
+
+OBJS := nintendo64.o osys_n64_base.o osys_n64_events.o osys_n64_utilities.o pakfs_save_manager.o
+
+include $(srcdir)/Makefile.common
+
+MODULE_DIRS += ./
+
+all: $(TARGET).v64
+
+$(TARGET).v64: $(TARGET).bin ROMFS.img bootcode
+ cat bootcode $(TARGET).bin ROMFS.img > $(TARGET).v64
+ ./pad_rom.sh
+
+ROMFS.img:
+ genromfs -f ./ROMFS.img -d ./ROMFS -V romtest
+
+$(TARGET).elf: $(OBJS)
+ $(LD) -o $(TARGET).elf $(OBJS) $(LDFLAGS)
+
+$(TARGET).bin : $(TARGET).elf
+ $(OBJCOPY) $(TARGET).elf $(TARGET).bin -O binary
+
+spotless : distclean
+ $(RM) *.bin *.elf *.v64 *.img *.bak *.tmp *.map
+
+send: $(TARGET).v64
+ sudo ucon64 --xv64 $(TARGET).v64
+
diff --git a/backends/platform/n64/module.mk b/backends/platform/n64/module.mk
new file mode 100644
index 0000000000..34a7badb44
--- /dev/null
+++ b/backends/platform/n64/module.mk
@@ -0,0 +1,10 @@
+MODULE := backends/platform/n64
+
+MODULE_OBJS := \
+ nintendo64.o
+
+MODULE_DIRS += \
+ backends/platform/n64/
+
+# We don't use the rules.mk here on purpose
+OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) $(OBJS)
diff --git a/backends/platform/n64/nintendo64.cpp b/backends/platform/n64/nintendo64.cpp
new file mode 100644
index 0000000000..76c00c8fb9
--- /dev/null
+++ b/backends/platform/n64/nintendo64.cpp
@@ -0,0 +1,35 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ */
+
+#include "osys_n64.h"
+
+int main(void) {
+ g_system = new OSystem_N64();
+ assert(g_system);
+
+ // Invoke the actual ScummVM main entry point:
+ int res = scummvm_main(0, NULL);
+ g_system->quit(); // TODO: Consider removing / replacing this!
+ return res;
+}
+
diff --git a/backends/platform/n64/osys_n64.h b/backends/platform/n64/osys_n64.h
new file mode 100644
index 0000000000..dd9b4751ea
--- /dev/null
+++ b/backends/platform/n64/osys_n64.h
@@ -0,0 +1,206 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ */
+
+#ifndef __OSYS_N64_H__
+#define __OSYS_N64_H__
+
+#include "common/rect.h"
+#include "common/config-manager.h"
+
+#include "backends/base-backend.h"
+#include "backends/saves/default/default-saves.h"
+#include "backends/timer/default/default-timer.h"
+
+#include "base/main.h"
+
+#include "graphics/surface.h"
+#include "graphics/colormasks.h"
+#include "graphics/pixelformat.h"
+
+#include "sound/mixer_intern.h"
+
+#include <libn64.h>
+#include <n64utils.h>
+
+#define DEFAULT_SOUND_SAMPLE_RATE 8000 // 8 kHz
+//#define DEFAULT_SOUND_SAMPLE_RATE 11025 // 11 kHz
+
+// Limit the N64 resolution to 320x240, because framebuffer
+// at higher resolutions would be too slow and memory hogging
+#define DEFAULT_SCREEN_WIDTH 320
+#define DEFAULT_SCREEN_HEIGHT 240
+
+#define N64_PAL_FPS 25
+#define N64_NTSC_FPS 30
+
+typedef int (*TimerProc)(int interval);
+
+// Interrupt callback functions
+void vblCallback(void);
+void sndCallback(void);
+void refillAudioBuffers(void);
+
+// External utility functions
+void enableAudioPlayback(void);
+void disableAudioPlayback(void);
+void checkTimers(void);
+int timer_handler(int t);
+
+static volatile bool _audioEnabled = false; // Used by interrupt callbacks
+
+/* Graphic mode identifiers */
+enum GraphicModeID {
+ OVERS_NTSC_340X240,
+ NORM_NTSC_320X240,
+ NORM_PAL_320X240,
+ OVERS_PAL_340X240,
+ NORM_MPAL_320X240,
+ OVERS_MPAL_340X240
+};
+
+class OSystem_N64 : public BaseBackend {
+protected:
+ Common::SaveFileManager *_savefile;
+ Audio::MixerImpl *_mixer;
+ Common::TimerManager *_timer;
+ FilesystemFactory *_fsFactory;
+
+ struct display_context * _dc; // Display context for N64 on screen buffer switching
+
+ Graphics::Surface _framebuffer;
+
+ uint16 *_offscreen_hic; // Offscreen converted to 16bit surface
+ uint8 *_offscreen_pal; // Offscreen with palette indexes
+ OverlayColor *_overlayBuffer; // Offscreen for the overlay (16 bit)
+
+ uint16 *_screenPalette; // Array for palette entries (256 colors max)
+ uint16 _cursorPalette[256]; // Palette entries for the cursor
+
+ int _graphicMode; // Graphic mode
+ uint16 _screenWidth, _screenHeight;
+ uint16 _gameWidth, _gameHeight;
+ uint16 _frameBufferWidth; // Width of framebuffer in N64 memory
+ uint8 _offscrPixels; // Pixels to skip on each line before start drawing, used to center image
+ uint8 _maxFps;
+
+ int _shakeOffset;
+
+ uint8 *_cursor_pal; // Cursor buffer, palettized
+ bool _cursorPaletteDisabled;
+ bool _dirtyPalette;
+
+ int _cursorWidth, _cursorHeight;
+ int _cursorKeycolor;
+
+ uint16 _overlayHeight, _overlayWidth;
+ bool _overlayVisible;
+
+ bool _mouseVisible;
+ int _mouseX, _mouseY;
+ int _mouseMaxX, _mouseMaxY;
+ int _mouseHotspotX, _mouseHotspotY;
+
+ controller_data_buttons *_ctrlData; // Controller data read from the N64 serial interface
+
+ bool _dirtyOffscreen;
+
+public:
+
+ /* These have to be accessed by interrupt callbacks */
+ uint16 _audioBufferSize;
+ uint32 _viClockRate; // Clock rate of video system, depending on VI mode
+
+ int _timerCallbackNext;
+ int _timerCallbackTimer;
+ TimerProc _timerCallback;
+ /* *** */
+
+ OSystem_N64();
+ virtual ~OSystem_N64();
+
+ virtual void initBackend();
+
+ virtual bool hasFeature(Feature f);
+ virtual void setFeatureState(Feature f, bool enable);
+ virtual bool getFeatureState(Feature f);
+ virtual const GraphicsMode *getSupportedGraphicsModes() const;
+ virtual int getDefaultGraphicsMode() const;
+ bool setGraphicsMode(const char *name);
+ virtual bool setGraphicsMode(int mode);
+ virtual int getGraphicsMode() const;
+ virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format);
+ virtual int16 getHeight();
+ virtual int16 getWidth();
+ virtual void setPalette(const byte *colors, uint start, uint num);
+ virtual void grabPalette(byte *colors, uint start, uint num);
+ virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h);
+ virtual void updateScreen();
+ virtual Graphics::Surface *lockScreen();
+ virtual void unlockScreen();
+ virtual void setShakePos(int shakeOffset);
+
+ virtual void showOverlay();
+ virtual void hideOverlay();
+ virtual void clearOverlay();
+ virtual void grabOverlay(OverlayColor *buf, int pitch);
+ virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h);
+ virtual int16 getOverlayHeight();
+ virtual int16 getOverlayWidth();
+ virtual Graphics::PixelFormat getOverlayFormat() const {
+ return Graphics::createPixelFormat<555>();
+ }
+
+ virtual bool showMouse(bool visible);
+
+ virtual void warpMouse(int x, int y);
+ virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format);
+ virtual void setCursorPalette(const byte *colors, uint start, uint num);
+ virtual void disableCursorPalette(bool disable);
+
+ virtual bool pollEvent(Common::Event &event);
+ virtual uint32 getMillis();
+ virtual void delayMillis(uint msecs);
+
+ virtual MutexRef createMutex(void);
+ virtual void lockMutex(MutexRef mutex);
+ virtual void unlockMutex(MutexRef mutex);
+ virtual void deleteMutex(MutexRef mutex);
+
+ virtual void quit();
+
+ virtual Common::SaveFileManager *getSavefileManager();
+ virtual Audio::Mixer *getMixer();
+ virtual void getTimeAndDate(TimeDate &t) const;
+ virtual Common::TimerManager *getTimerManager();
+ virtual void setTimerCallback(TimerProc callback, int interval);
+ FilesystemFactory *getFilesystemFactory();
+
+ void rebuildOffscreenGameBuffer(void);
+ void switchGraphicModeId(int mode);
+
+ void setupMixer(void);
+
+};
+
+#endif /* __OSYS_N64_H__ */
+
diff --git a/backends/platform/n64/osys_n64_base.cpp b/backends/platform/n64/osys_n64_base.cpp
new file mode 100644
index 0000000000..65290c5c6e
--- /dev/null
+++ b/backends/platform/n64/osys_n64_base.cpp
@@ -0,0 +1,804 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <romfs.h>
+
+#include "osys_n64.h"
+#include "pakfs_save_manager.h"
+#include "backends/fs/n64/n64-fs-factory.h"
+
+#define DEFAULT_FRAMEBUFFER_WIDTH 340 // a horizontal resolution of 340 takes into account overscan
+#define DEFAULT_PIX_SKIP 15
+
+extern uint8 _romfs; // Defined by linker (used to calculate position of romfs image)
+
+inline uint16 colBGR888toRGB555(byte r, byte g, byte b);
+
+static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
+ { "320x240 (PAL) fix overscan", "340x240 PAL", OVERS_PAL_340X240 },
+ { "320x240 (PAL) overscan", "320x240 PAL", NORM_PAL_320X240 },
+ { "320x240 (MPAL) fix overscan", "340x240 MPAL", OVERS_MPAL_340X240 },
+ { "320x240 (MPAL) overscan", "320x240 MPAL", NORM_MPAL_320X240 },
+ { "340x240 (NTSC) fix overscan", "340x240 NTSC", OVERS_NTSC_340X240 },
+ { "320x240 (NTSC) overscan", "320x240 NTSC", NORM_NTSC_320X240 },
+ { 0, 0, 0 }
+};
+
+OSystem_N64::OSystem_N64() {
+ // Enable Mips interrupts
+ set_MI_interrupt(1);
+
+ // Initialize display: NTSC 340x240 (16 bit)
+ initDisplay(NTSC_340X240_16BIT);
+
+ // Prepare virtual text layer for debugging purposes
+ initTextLayer();
+
+ // Init PI interface
+ PI_Init();
+
+ // Init Controller Pak
+ initPakFs();
+
+ // Use the first save pak found
+ uint8 ctrl_num;
+ for (ctrl_num = 0; ctrl_num < 4; ctrl_num++) {
+ int8 pak_type = identifyPak(ctrl_num);
+ if (pak_type == 1) {
+ loadPakData(ctrl_num);
+ break;
+ }
+ }
+
+ // Screen size
+ _screenWidth = DEFAULT_SCREEN_WIDTH;
+ _screenHeight = DEFAULT_SCREEN_HEIGHT;
+
+ // Game screen size
+ _gameHeight = DEFAULT_SCREEN_WIDTH;
+ _gameWidth = DEFAULT_SCREEN_HEIGHT;
+
+ // Overlay size
+ _overlayWidth = DEFAULT_SCREEN_WIDTH;
+ _overlayHeight = DEFAULT_SCREEN_HEIGHT;
+
+ // Framebuffer width
+ _frameBufferWidth = DEFAULT_FRAMEBUFFER_WIDTH;
+
+ // Pixels to skip
+ _offscrPixels = DEFAULT_PIX_SKIP;
+
+ // Video clock
+ _viClockRate = VI_NTSC_CLOCK;
+
+ _maxFps = N64_NTSC_FPS;
+
+ _overlayVisible = false;
+
+ _shakeOffset = 0;
+
+ // Allocate memory for offscreen buffers
+ _offscreen_hic = (uint16*)memalign(8, DEFAULT_SCREEN_WIDTH * DEFAULT_SCREEN_HEIGHT * 2);
+ _offscreen_pal = (uint8*)memalign(8, DEFAULT_SCREEN_WIDTH * DEFAULT_SCREEN_HEIGHT);
+ _overlayBuffer = (uint16*)memalign(8, DEFAULT_SCREEN_WIDTH * DEFAULT_SCREEN_HEIGHT * sizeof(OverlayColor));
+
+ _cursor_pal = NULL;
+
+ _cursorWidth = -1;
+ _cursorHeight = -1;
+ _cursorKeycolor = -1;
+ _mouseHotspotX = _mouseHotspotY = -1;
+
+ // Clean offscreen buffers
+ memset(_offscreen_hic, 0, _screenWidth * _screenHeight * 2);
+ memset(_offscreen_pal, 0, _screenWidth * _screenHeight);
+ memset(_overlayBuffer, 0, _overlayWidth * _overlayHeight * sizeof(OverlayColor));
+
+ // Default graphic mode
+ _graphicMode = OVERS_NTSC_340X240;
+
+ // Clear palette array
+ _screenPalette = (uint16*)memalign(8, 256 * sizeof(uint16));
+ memset(_screenPalette, 0, 256 * sizeof(uint16));
+ memset(_cursorPalette, 0, 256 * sizeof(uint16));
+
+ _dirtyPalette = false;
+ _cursorPaletteDisabled = false;
+
+ _audioEnabled = false;
+
+ // Initialize ROMFS access interface
+ initRomFSmanager((uint8*)(((uint32)&_romfs + (uint32)0xc00) | (uint32)0xB0000000));
+
+ // Register vblank callback
+ registerVIhandler(vblCallback);
+
+ _mouseVisible = false;
+
+ _mouseX = _overlayWidth / 2;
+ _mouseY = _overlayHeight / 2;
+ _mouseMaxX = _overlayWidth;
+ _mouseMaxY = _overlayHeight;
+
+ _savefile = 0;
+ _mixer = 0;
+ _timer = 0;
+
+ _dirtyOffscreen = false;
+
+ _ctrlData = (controller_data_buttons*)memalign(8, sizeof(controller_data_buttons));
+
+ _fsFactory = new N64FilesystemFactory();
+
+}
+
+OSystem_N64::~OSystem_N64() {
+ delete _savefile;
+ delete _mixer;
+ delete _timer;
+ delete _fsFactory;
+}
+
+void OSystem_N64::initBackend() {
+ ConfMan.setInt("autosave_period", 0);
+ ConfMan.setBool("FM_high_quality", false);
+ ConfMan.setBool("FM_medium_quality", true);
+ ConfMan.set("gui_theme", "modern"); // In case of modern theme being present, use it.
+
+ _savefile = new PAKSaveManager();
+
+ _mixer = new Audio::MixerImpl(this);
+ _mixer->setReady(false);
+
+ _timer = new DefaultTimerManager();
+
+ setTimerCallback(&timer_handler, 10);
+
+ setupMixer();
+
+ OSystem::initBackend();
+
+}
+
+bool OSystem_N64::hasFeature(Feature f) {
+ return (f == kFeatureCursorHasPalette);
+}
+
+void OSystem_N64::setFeatureState(Feature f, bool enable) {
+ return;
+}
+
+bool OSystem_N64::getFeatureState(Feature f) {
+ return false;
+}
+
+const OSystem::GraphicsMode* OSystem_N64::getSupportedGraphicsModes() const {
+ return s_supportedGraphicsModes;
+}
+
+
+int OSystem_N64::getDefaultGraphicsMode() const {
+ return OVERS_NTSC_340X240;
+}
+
+bool OSystem_N64::setGraphicsMode(const char *mode) {
+ int i = 0;
+ while (s_supportedGraphicsModes[i].name) {
+ if (!strcmpi(s_supportedGraphicsModes[i].name, mode)) {
+ _graphicMode = s_supportedGraphicsModes[i].id;
+
+ switchGraphicModeId(_graphicMode);
+
+ return true;
+ }
+ i++;
+ }
+
+ return true;
+}
+
+bool OSystem_N64::setGraphicsMode(int mode) {
+ _graphicMode = mode;
+ switchGraphicModeId(_graphicMode);
+
+ return true;
+}
+
+void OSystem_N64::switchGraphicModeId(int mode) {
+ switch (mode) {
+ case NORM_PAL_320X240:
+ disableAudioPlayback();
+ _viClockRate = VI_PAL_CLOCK;
+ _maxFps = N64_PAL_FPS;
+ initDisplay(PAL_320X240_16BIT);
+ _frameBufferWidth = 320;
+ _screenWidth = DEFAULT_SCREEN_WIDTH;
+ _screenHeight = DEFAULT_SCREEN_HEIGHT;
+ _offscrPixels = 0;
+ _graphicMode = NORM_PAL_320X240;
+ enableAudioPlayback();
+ break;
+
+ case OVERS_PAL_340X240:
+ disableAudioPlayback();
+ _viClockRate = VI_PAL_CLOCK;
+ _maxFps = N64_PAL_FPS;
+ initDisplay(PAL_340X240_16BIT);
+ _frameBufferWidth = DEFAULT_FRAMEBUFFER_WIDTH;
+ _screenWidth = DEFAULT_SCREEN_WIDTH;
+ _screenHeight = DEFAULT_SCREEN_HEIGHT;
+ _offscrPixels = DEFAULT_PIX_SKIP;
+ _graphicMode = OVERS_PAL_340X240;
+ enableAudioPlayback();
+ break;
+
+ case NORM_MPAL_320X240:
+ disableAudioPlayback();
+ _viClockRate = VI_MPAL_CLOCK;
+ _maxFps = N64_NTSC_FPS;
+ initDisplay(MPAL_320X240_16BIT);
+ _frameBufferWidth = 320;
+ _screenWidth = DEFAULT_SCREEN_WIDTH;
+ _screenHeight = DEFAULT_SCREEN_HEIGHT;
+ _offscrPixels = 0;
+ _graphicMode = NORM_MPAL_320X240;
+ enableAudioPlayback();
+ break;
+
+ case OVERS_MPAL_340X240:
+ disableAudioPlayback();
+ _viClockRate = VI_MPAL_CLOCK;
+ _maxFps = N64_NTSC_FPS;
+ initDisplay(MPAL_340X240_16BIT);
+ _frameBufferWidth = DEFAULT_FRAMEBUFFER_WIDTH;
+ _screenWidth = DEFAULT_SCREEN_WIDTH;
+ _screenHeight = DEFAULT_SCREEN_HEIGHT;
+ _offscrPixels = DEFAULT_PIX_SKIP;
+ _graphicMode = OVERS_MPAL_340X240;
+ enableAudioPlayback();
+ break;
+
+ case NORM_NTSC_320X240:
+ disableAudioPlayback();
+ _viClockRate = VI_NTSC_CLOCK;
+ _maxFps = N64_NTSC_FPS;
+ initDisplay(NTSC_320X240_16BIT);
+ _frameBufferWidth = 320;
+ _screenWidth = DEFAULT_SCREEN_WIDTH;
+ _screenHeight = DEFAULT_SCREEN_HEIGHT;
+ _offscrPixels = 0;
+ _graphicMode = NORM_NTSC_320X240;
+ enableAudioPlayback();
+ break;
+
+ case OVERS_NTSC_340X240:
+ default:
+ disableAudioPlayback();
+ _viClockRate = VI_NTSC_CLOCK;
+ _maxFps = N64_NTSC_FPS;
+ initDisplay(NTSC_340X240_16BIT);
+ _frameBufferWidth = DEFAULT_FRAMEBUFFER_WIDTH;
+ _screenWidth = DEFAULT_SCREEN_WIDTH;
+ _screenHeight = DEFAULT_SCREEN_HEIGHT;
+ _offscrPixels = DEFAULT_PIX_SKIP;
+ _graphicMode = OVERS_NTSC_340X240;
+ enableAudioPlayback();
+ break;
+ }
+}
+
+int OSystem_N64::getGraphicsMode() const {
+ return _graphicMode;
+}
+
+void OSystem_N64::initSize(uint width, uint height, const Graphics::PixelFormat *format) {
+ _gameWidth = width;
+ _gameHeight = height;
+
+ if (_gameWidth > _screenWidth)
+ _gameWidth = _screenWidth;
+ if (_gameHeight > _screenHeight)
+ _gameHeight = _screenHeight;
+
+ _mouseMaxX = _gameWidth;
+ _mouseMaxY = _gameHeight;
+}
+
+int16 OSystem_N64::getHeight() {
+ return _screenHeight;
+}
+
+int16 OSystem_N64::getWidth() {
+ return _screenWidth;
+}
+
+void OSystem_N64::setPalette(const byte *colors, uint start, uint num) {
+ for (int i = 0; i < num; ++i) {
+ uint8 c[4];
+ _screenPalette[start + i] = colBGR888toRGB555(colors[2], colors[1], colors[0]);
+ colors += 4;
+ }
+
+ _dirtyPalette = true;
+ _dirtyOffscreen = true;
+}
+
+void OSystem_N64::rebuildOffscreenGameBuffer(void) {
+ // Regenerate hi-color offscreen buffer
+ uint32 two_col_hi;
+ uint32 four_col_pal;
+ for (int h = 0; h < _gameHeight; h++)
+ for (int w = 0; w < _gameWidth; w += 4) {
+ four_col_pal = *(uint32*)(_offscreen_pal + ((h * _screenWidth) + w));
+
+ two_col_hi = 0;
+ two_col_hi = _screenPalette[((four_col_pal >> (8 * 3)) & 0xFF)] | (two_col_hi << (16 * 0));
+ two_col_hi = _screenPalette[((four_col_pal >> (8 * 2)) & 0xFF)] | (two_col_hi << (16 * 1));
+
+ *(uint32*)(_offscreen_hic + (h * _screenWidth) + w + 0) = two_col_hi;
+
+ two_col_hi = 0;
+ two_col_hi = _screenPalette[((four_col_pal >> (8 * 1)) & 0xFF)] | (two_col_hi << (16 * 0));
+ two_col_hi = _screenPalette[((four_col_pal >> (8 * 0)) & 0xFF)] | (two_col_hi << (16 * 1));
+
+ *(uint32*)(_offscreen_hic + (h * _screenWidth) + w + 2) = two_col_hi;
+ }
+}
+
+void OSystem_N64::grabPalette(byte *colors, uint start, uint num) {
+ uint32 i;
+ uint16 color;
+
+ for (i = start; i < start + num; i++) {
+ color = _screenPalette[i];
+
+ // Color format on the n64 is RGB - 1555
+ *colors++ = ((color & 0x1F) << 3);
+ *colors++ = (((color >> 5) & 0x1F) << 3);
+ *colors++ = (((color >> 10) & 0x1F) << 3);
+ *colors++ = 0;
+ }
+
+ return;
+}
+
+void OSystem_N64::setCursorPalette(const byte *colors, uint start, uint num) {
+ for (int i = 0; i < num; ++i) {
+ _cursorPalette[start + i] = colBGR888toRGB555(colors[2], colors[1], colors[0]);
+ colors += 4;
+ }
+
+ _cursorPaletteDisabled = false;
+ _dirtyOffscreen = true;
+}
+
+void OSystem_N64::disableCursorPalette(bool disable) {
+ _cursorPaletteDisabled = disable;
+
+ _dirtyOffscreen = true;
+}
+
+void OSystem_N64::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) {
+ //Clip the coordinates
+ if (x < 0) {
+ w += x;
+ buf -= x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ h += y;
+ buf -= y * pitch;
+ y = 0;
+ }
+
+ if (w > _screenWidth - x) {
+ w = _screenWidth - x;
+ }
+
+ if (h > _screenHeight - y) {
+ h = _screenHeight - y;
+ }
+
+ if (w <= 0 || h <= 0)
+ return;
+
+ uint8 *dst_pal = _offscreen_pal + ((y * _screenWidth) + x);
+ uint16 *dst_hicol = _offscreen_hic + ((y * _screenWidth) + x);
+
+ do {
+ for (int hor = 0; hor < w; hor++) {
+ if (dst_pal[hor] != buf[hor]) {
+ uint16 color = _screenPalette[buf[hor]];
+ dst_hicol[hor] = color; // Save image converted to 16-bit
+ dst_pal[hor] = buf[hor]; // Save palettized display
+ }
+ }
+
+ buf += pitch;
+ dst_pal += _screenWidth;
+ dst_hicol += _screenWidth;
+ } while (--h);
+
+ _dirtyOffscreen = true;
+
+ return;
+}
+
+void OSystem_N64::updateScreen() {
+#ifdef LIMIT_FPS
+ static uint32 _lastScreenUpdate = 0;
+ uint32 now = getMillis();
+ if (now - _lastScreenUpdate < 1000 / _maxFps)
+ return;
+
+ _lastScreenUpdate = now;
+#endif
+
+ // Check if audio buffer needs refill
+ // Done here because this gets called regularly
+ refillAudioBuffers();
+
+ if (!_dirtyOffscreen && !_dirtyPalette) return; // The offscreen is clean
+
+ uint8 skip_lines = (_screenHeight - _gameHeight) / 4;
+ uint8 skip_pixels = (_screenWidth - _gameWidth) / 2; // Center horizontally the image
+
+ if (_dirtyPalette)
+ rebuildOffscreenGameBuffer();
+
+ while (!(_dc = lockDisplay()));
+
+ uint16 *overlay_framebuffer = (uint16*)_dc->conf.framebuffer; // Current screen framebuffer
+ uint16 *game_framebuffer = overlay_framebuffer + (_frameBufferWidth * skip_lines * 2); // Skip some lines to center the image vertically
+
+ uint16 currentHeight;
+ uint16 *tmpDst;
+ uint16 *tmpSrc;
+
+ // Copy the game buffer to screen
+ if (!_overlayVisible) {
+ tmpDst = game_framebuffer;
+ tmpSrc = _offscreen_hic + (_shakeOffset * _screenWidth);
+ for (currentHeight = _shakeOffset; currentHeight < _gameHeight; currentHeight++) {
+ memcpy((tmpDst + skip_pixels + _offscrPixels), tmpSrc, _screenWidth * 2);
+ tmpDst += _frameBufferWidth;
+ tmpSrc += _screenWidth;
+ }
+
+ uint16 _clearLines = _shakeOffset; // When shaking we must take care of remaining lines to clear
+ while (_clearLines--) {
+ memset(tmpDst + skip_pixels + _offscrPixels, 0, _screenWidth * 2);
+ tmpDst += _frameBufferWidth;
+ }
+ } else { // If the overlay is enabled, draw it on top of game screen
+ tmpDst = overlay_framebuffer;
+ tmpSrc = _overlayBuffer;
+ for (currentHeight = 0; currentHeight < _overlayHeight; currentHeight++) {
+ memcpy((tmpDst + _offscrPixels), tmpSrc, _overlayWidth * 2);
+ tmpDst += _frameBufferWidth;
+ tmpSrc += _overlayWidth;
+ }
+ }
+
+ // Draw mouse cursor
+ if ((_mouseVisible || _overlayVisible) && _cursorHeight > 0 && _cursorWidth > 0) {
+ uint16 *mouse_framebuffer;
+ uint16 horiz_pix_skip = 0;
+
+ if (_overlayVisible) {
+ mouse_framebuffer = overlay_framebuffer;
+ } else {
+ mouse_framebuffer = game_framebuffer;
+ horiz_pix_skip = skip_pixels;
+ }
+
+ int mX = _mouseX - _mouseHotspotX;
+ int mY = _mouseY - _mouseHotspotY;
+
+ uint16 *_cursorSource = _cursorPaletteDisabled ? _screenPalette : _cursorPalette;
+ for (int h = 0; h < _cursorHeight; h++)
+ for (int w = 0; w < _cursorWidth; w++) {
+ uint8 index = _cursor_pal[(h * _cursorWidth) + w];
+
+ // Draw pixel
+ if ((index != _cursorKeycolor) && ((mY + h) >= 0) && ((mY + h) < _mouseMaxY) && ((mX + w) >= 0) && ((mX + w) < _mouseMaxX))
+ mouse_framebuffer[((mY + h) * _frameBufferWidth) + ((mX + w) + _offscrPixels + horiz_pix_skip)] = _cursorSource[index];
+ }
+ }
+
+#ifndef _ENABLE_DEBUG_
+ showDisplay(_dc);
+#else
+ showDisplayAndText(_dc);
+#endif
+
+ _dc = NULL;
+ _dirtyOffscreen = false;
+ _dirtyPalette = false;
+
+ return;
+}
+
+Graphics::Surface *OSystem_N64::lockScreen() {
+ _framebuffer.pixels = _offscreen_pal;
+ _framebuffer.w = _gameWidth;
+ _framebuffer.h = _gameHeight;
+ _framebuffer.pitch = _screenWidth;
+ _framebuffer.bytesPerPixel = 1;
+
+ return &_framebuffer;
+}
+
+void OSystem_N64::unlockScreen() {
+ _dirtyPalette = true;
+ _dirtyOffscreen = true;
+}
+
+void OSystem_N64::setShakePos(int shakeOffset) {
+ _shakeOffset = shakeOffset;
+ _dirtyOffscreen = true;
+
+ return;
+}
+
+void OSystem_N64::showOverlay() {
+ // Change min/max mouse coords
+ _mouseMaxX = _overlayWidth;
+ _mouseMaxY = _overlayHeight;
+
+ // Relocate the mouse cursor given the new limitations
+ warpMouse(_mouseX, _mouseY);
+
+ _overlayVisible = true;
+ _dirtyOffscreen = true;
+}
+
+void OSystem_N64::hideOverlay() {
+ // Change min/max mouse coords
+ _mouseMaxX = _gameWidth;
+ _mouseMaxY = _gameHeight;
+
+ // Relocate the mouse cursor given the new limitations
+ warpMouse(_mouseX, _mouseY);
+
+ _overlayVisible = false;
+
+ // Clear double buffered display
+ clearAllVideoBuffers();
+
+ _dirtyOffscreen = true;
+}
+
+void OSystem_N64::clearOverlay() {
+ memset(_overlayBuffer, 0, _overlayWidth * _overlayHeight * sizeof(OverlayColor));
+
+ uint8 skip_lines = (_screenHeight - _gameHeight) / 4;
+ uint8 skip_pixels = (_screenWidth - _gameWidth) / 2; // Center horizontally the image
+
+ uint16 *tmpDst = _overlayBuffer + (_overlayWidth * skip_lines * 2);
+ uint16 *tmpSrc = _offscreen_hic + (_shakeOffset * _screenWidth);
+ for (uint16 currentHeight = _shakeOffset; currentHeight < _gameHeight; currentHeight++) {
+ memcpy((tmpDst + skip_pixels), tmpSrc, _gameWidth * 2);
+ tmpDst += _overlayWidth;
+ tmpSrc += _screenWidth;
+ }
+
+ _dirtyOffscreen = true;
+}
+
+void OSystem_N64::grabOverlay(OverlayColor *buf, int pitch) {
+ int h = _overlayHeight;
+ OverlayColor *src = _overlayBuffer;
+
+ do {
+ memcpy(buf, src, _overlayWidth * sizeof(OverlayColor));
+ src += _overlayWidth;
+ buf += pitch;
+ } while (--h);
+}
+
+void OSystem_N64::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
+ //Clip the coordinates
+ if (x < 0) {
+ w += x;
+ buf -= x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ h += y;
+ buf -= y * pitch;
+ y = 0;
+ }
+
+ if (w > _overlayWidth - x) {
+ w = _overlayWidth - x;
+ }
+
+ if (h > _overlayHeight - y) {
+ h = _overlayHeight - y;
+ }
+
+ if (w <= 0 || h <= 0)
+ return;
+
+
+ OverlayColor *dst = _overlayBuffer + (y * _overlayWidth + x);
+
+ if (_overlayWidth == pitch && pitch == w) {
+ memcpy(dst, buf, h * w * sizeof(OverlayColor));
+ } else {
+ do {
+ memcpy(dst, buf, w * sizeof(OverlayColor));
+ buf += pitch;
+ dst += _overlayWidth;
+ } while (--h);
+ }
+
+ _dirtyOffscreen = true;
+
+ return;
+}
+
+int16 OSystem_N64::getOverlayHeight() {
+ return _overlayHeight;
+}
+
+int16 OSystem_N64::getOverlayWidth() {
+ return _overlayWidth;
+}
+
+
+bool OSystem_N64::showMouse(bool visible) {
+ bool last = _mouseVisible;
+ _mouseVisible = visible;
+
+ _dirtyOffscreen = true;
+
+ return last;
+}
+
+void OSystem_N64::warpMouse(int x, int y) {
+
+ if (x < 0)
+ _mouseX = 0;
+ else if (x >= _mouseMaxX)
+ _mouseX = _mouseMaxX - 1;
+ else
+ _mouseX = x;
+
+ if (y < 0)
+ _mouseY = 0;
+ else if (y >= _mouseMaxY)
+ _mouseY = _mouseMaxY - 1;
+ else
+ _mouseY = y;
+
+ _dirtyOffscreen = true;
+}
+
+void OSystem_N64::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) {
+ if (!w || !h) return;
+
+ _mouseHotspotX = hotspotX;
+ _mouseHotspotY = hotspotY;
+
+ if (_cursor_pal && ((w != _cursorWidth) || (h != _cursorHeight))) {
+ free(_cursor_pal);
+ _cursor_pal = NULL;
+ }
+
+ if (!_cursor_pal) {
+ _cursor_pal = (uint8*)malloc(w * h);
+ }
+
+ _cursorWidth = w;
+ _cursorHeight = h;
+
+ memcpy(_cursor_pal, buf, w * h); // Copy the palettized cursor
+
+ _cursorKeycolor = keycolor & 0xFF;
+
+ _dirtyOffscreen = true;
+
+ return;
+}
+
+uint32 OSystem_N64::getMillis() {
+ return getMilliTick();
+}
+
+void OSystem_N64::delayMillis(uint msecs) {
+ delay(msecs);
+}
+
+OSystem::MutexRef OSystem_N64::createMutex(void) {
+ return NULL;
+}
+
+void OSystem_N64::lockMutex(MutexRef mutex) {
+ return;
+}
+
+void OSystem_N64::unlockMutex(MutexRef mutex) {
+ return;
+}
+
+void OSystem_N64::deleteMutex(MutexRef mutex) {
+ return;
+}
+
+void OSystem_N64::quit() {
+ // Not much to do...
+ return;
+}
+
+Common::SaveFileManager *OSystem_N64::getSavefileManager() {
+ assert(_savefile);
+ return _savefile;
+}
+
+Audio::Mixer *OSystem_N64::getMixer() {
+ assert(_mixer);
+ return _mixer;
+}
+
+Common::TimerManager *OSystem_N64::getTimerManager() {
+ assert(_timer);
+ return _timer;
+}
+
+void OSystem_N64::getTimeAndDate(TimeDate &t) const {
+ // No clock inside the N64
+ // TODO: use getMillis to provide some kind of time-counting feature?
+ t.tm_sec = 0;
+ t.tm_min = 0;
+ t.tm_hour = 0;
+ t.tm_mday = 0;
+ t.tm_mon = 0;
+ t.tm_year = 0;
+
+ return;
+}
+
+FilesystemFactory *OSystem_N64::getFilesystemFactory() {
+ return _fsFactory;
+}
+
+void OSystem_N64::setTimerCallback(TimerProc callback, int interval) {
+ if (callback != NULL) {
+ _timerCallbackTimer = interval;
+ _timerCallbackNext = getMillis() + interval;
+ _timerCallback = callback;
+ } else
+ _timerCallback = NULL;
+}
+
+void OSystem_N64::setupMixer(void) {
+ enableAudioPlayback();
+}
+
+inline uint16 colBGR888toRGB555(byte r, byte g, byte b) {
+ return ((r >> 3) << 1) | ((g >> 3) << 6) | ((b >> 3) << 11);
+}
+
diff --git a/backends/platform/n64/osys_n64_events.cpp b/backends/platform/n64/osys_n64_events.cpp
new file mode 100644
index 0000000000..3cda46ce5c
--- /dev/null
+++ b/backends/platform/n64/osys_n64_events.cpp
@@ -0,0 +1,243 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ */
+
+#include "osys_n64.h"
+
+// Pad buttons
+#define START_BUTTON(a) (a & 0x1000)
+#define A_BUTTON(a) (a & 0x8000)
+#define B_BUTTON(a) (a & 0x4000)
+#define Z_BUTTON(a) (a & 0x2000)
+
+// Triggers
+#define TL_BUTTON(a) (a & 0x0020)
+#define TR_BUTTON(a) (a & 0x0010)
+
+// D-Pad
+#define DL_BUTTON(a) (a & 0x0200)
+#define DR_BUTTON(a) (a & 0x0100)
+#define DU_BUTTON(a) (a & 0x0800)
+#define DD_BUTTON(a) (a & 0x0400)
+
+// Yellow C buttons
+#define CL_BUTTON(a) (a & 0x0002)
+#define CR_BUTTON(a) (a & 0x0001)
+#define CU_BUTTON(a) (a & 0x0008)
+#define CD_BUTTON(a) (a & 0x0004)
+
+#define PAD_DEADZONE 5
+#define PAD_ACCELERATION 10
+#define PAD_CHECK_TIME 40
+
+bool OSystem_N64::pollEvent(Common::Event &event) {
+ // Check Timers. Not the best place, but checking in interrupts proved to be unsafe
+ checkTimers();
+
+ // Refill audio buffers, doing this inside interrupts could be harmful
+ refillAudioBuffers();
+
+ // Read current controller status
+ controller_Read_Buttons(_ctrlData);
+
+ static uint16 oldButtons = 0; // old button data... used for button press/release
+ uint16 newButtons = _ctrlData->c[0].buttons; // Read from controller 0
+
+ bool buttonPressed = false;
+ static bool left_digital = false;
+ static bool right_digital = false;
+ static bool up_digital = false;
+ static bool down_digital = false;
+
+ int8 analogX = (_ctrlData->c[0].throttle >> 8) & 0xFF;
+ int8 analogY = (_ctrlData->c[0].throttle >> 0) & 0xFF;
+
+ if (newButtons != oldButtons) {
+ if (DL_BUTTON(newButtons) && !DL_BUTTON(oldButtons)) // Pressed LEFT
+ left_digital = true;
+ else if (!DL_BUTTON(newButtons) && DL_BUTTON(oldButtons)) // Released LEFT
+ left_digital = false;
+
+ if (DR_BUTTON(newButtons) && !DR_BUTTON(oldButtons)) // Pressed RIGHT
+ right_digital = true;
+ else if (!DR_BUTTON(newButtons) && DR_BUTTON(oldButtons)) // Released RIGHT
+ right_digital = false;
+
+ if (DU_BUTTON(newButtons) && !DU_BUTTON(oldButtons)) // Pressed UP
+ up_digital = true;
+ else if (!DU_BUTTON(newButtons) && DU_BUTTON(oldButtons)) // Released UP
+ up_digital = false;
+
+ if (DD_BUTTON(newButtons) && !DD_BUTTON(oldButtons)) // Pressed DOWN
+ down_digital = true;
+ else if (!DD_BUTTON(newButtons) && DD_BUTTON(oldButtons)) // Released DOWN
+ down_digital = false;
+
+ if (B_BUTTON(newButtons) && !B_BUTTON(oldButtons)) { // Pressed B - Right Mouse Button
+ buttonPressed = true;
+ event.type = Common::EVENT_RBUTTONDOWN;
+ } else if (!B_BUTTON(newButtons) && B_BUTTON(oldButtons)) { // Released B
+ buttonPressed = true;
+ event.type = Common::EVENT_RBUTTONUP;
+ } else if (A_BUTTON(newButtons) && !A_BUTTON(oldButtons)) { // Pressed A - Period
+ buttonPressed = true;
+ event.kbd.keycode = Common::KEYCODE_PERIOD;
+ event.kbd.ascii = '.';
+ event.type = Common::EVENT_KEYDOWN;
+ } else if (!A_BUTTON(newButtons) && A_BUTTON(oldButtons)) { // Released A
+ buttonPressed = true;
+ event.kbd.keycode = Common::KEYCODE_PERIOD;
+ event.kbd.ascii = '.';
+ event.type = Common::EVENT_KEYUP;
+ } else if (START_BUTTON(newButtons) && !START_BUTTON(oldButtons)) { // Pressed START - F5
+ buttonPressed = true;
+ event.kbd.keycode = Common::KEYCODE_F5;
+ event.kbd.ascii = Common::ASCII_F5;
+ event.type = Common::EVENT_KEYDOWN;
+ } else if (!START_BUTTON(newButtons) && START_BUTTON(oldButtons)) { // Released START
+ buttonPressed = true;
+ event.kbd.keycode = Common::KEYCODE_F5;
+ event.kbd.ascii = Common::ASCII_F5;
+ event.type = Common::EVENT_KEYUP;
+ } else if (CU_BUTTON(newButtons) && !CU_BUTTON(oldButtons)) { // Pressed Yellow Up - UP
+ buttonPressed = true;
+ event.kbd.keycode = Common::KEYCODE_UP;
+ event.type = Common::EVENT_KEYDOWN;
+ } else if (!CU_BUTTON(newButtons) && CU_BUTTON(oldButtons)) { // Released Yellow Up
+ buttonPressed = true;
+ event.kbd.keycode = Common::KEYCODE_UP;
+ event.type = Common::EVENT_KEYUP;
+ } else if (CD_BUTTON(newButtons) && !CD_BUTTON(oldButtons)) { // Pressed Yellow Down - DOWN
+ buttonPressed = true;
+ event.kbd.keycode = Common::KEYCODE_DOWN;
+ event.type = Common::EVENT_KEYDOWN;
+ } else if (!CD_BUTTON(newButtons) && CD_BUTTON(oldButtons)) { // Released Yellow Down
+ buttonPressed = true;
+ event.kbd.keycode = Common::KEYCODE_DOWN;
+ event.type = Common::EVENT_KEYUP;
+ } else if (CL_BUTTON(newButtons) && !CL_BUTTON(oldButtons)) { // Pressed Yellow Left - LEFT
+ buttonPressed = true;
+ event.kbd.keycode = Common::KEYCODE_LEFT;
+ event.type = Common::EVENT_KEYDOWN;
+ } else if (!CL_BUTTON(newButtons) && CL_BUTTON(oldButtons)) { // Released Yellow Left
+ buttonPressed = true;
+ event.kbd.keycode = Common::KEYCODE_LEFT;
+ event.type = Common::EVENT_KEYUP;
+ } else if (CR_BUTTON(newButtons) && !CR_BUTTON(oldButtons)) { // Pressed Yellow Right - RIGHT
+ buttonPressed = true;
+ event.kbd.keycode = Common::KEYCODE_RIGHT;
+ event.type = Common::EVENT_KEYDOWN;
+ } else if (!CR_BUTTON(newButtons) && CR_BUTTON(oldButtons)) { // Released Yellow Right
+ buttonPressed = true;
+ event.kbd.keycode = Common::KEYCODE_RIGHT;
+ event.type = Common::EVENT_KEYUP;
+ } else if (TL_BUTTON(newButtons) && !TL_BUTTON(oldButtons)) { // Pressed Trigger Left - ESC
+ buttonPressed = true;
+ event.kbd.keycode = Common::KEYCODE_ESCAPE;
+ event.kbd.ascii = 27;
+ event.type = Common::EVENT_KEYDOWN;
+ } else if (!TL_BUTTON(newButtons) && TL_BUTTON(oldButtons)) { // Released Trigger Left
+ buttonPressed = true;
+ event.kbd.keycode = Common::KEYCODE_ESCAPE;
+ event.kbd.ascii = 27;
+ event.type = Common::EVENT_KEYUP;
+ } else if (TR_BUTTON(newButtons) && !TR_BUTTON(oldButtons)) { // Pressed Trigger Right - F7
+ buttonPressed = true;
+ event.kbd.keycode = Common::KEYCODE_F7;
+ event.kbd.ascii = Common::ASCII_F7;
+ event.type = Common::EVENT_KEYDOWN;
+ } else if (!TR_BUTTON(newButtons) && TR_BUTTON(oldButtons)) { // Released Trigger Right
+ buttonPressed = true;
+ event.kbd.keycode = Common::KEYCODE_F7;
+ event.kbd.ascii = Common::ASCII_F7;
+ event.type = Common::EVENT_KEYUP;
+ } else if (Z_BUTTON(newButtons) && !Z_BUTTON(oldButtons)) { // Pressed Z - Left Mouse Button
+ buttonPressed = true;
+ event.type = Common::EVENT_LBUTTONDOWN;
+ } else if (!Z_BUTTON(newButtons) && Z_BUTTON(oldButtons)) { // Released Z
+ buttonPressed = true;
+ event.type = Common::EVENT_LBUTTONUP;
+ }
+
+ oldButtons = newButtons; // Save current button status
+
+ if (buttonPressed) {
+ event.mouse.x = _mouseX;
+ event.mouse.y = _mouseY;
+ return true;
+ }
+ }
+
+ static uint32 _lastPadCheck = 0;
+ uint32 curTime = getMillis();
+
+ if ((curTime - _lastPadCheck) > PAD_CHECK_TIME) {
+ _lastPadCheck = curTime;
+
+ int32 mx = _mouseX;
+ int32 my = _mouseY;
+
+ if (left_digital || right_digital || up_digital || down_digital) {
+ if (left_digital)
+ mx -= 5;
+ else if (right_digital)
+ mx += 5;
+ if (up_digital)
+ my -= 5;
+ else if (down_digital)
+ my += 5;
+ }
+
+ if (abs(analogX) > PAD_DEADZONE)
+ mx += analogX / (PAD_ACCELERATION - (abs(analogX) / 20));
+
+ if (abs(analogY) > PAD_DEADZONE)
+ my -= analogY / (PAD_ACCELERATION - (abs(analogY) / 20));
+
+ if (mx < 0)
+ mx = 0;
+
+ if (mx >= _mouseMaxX)
+ mx = _mouseMaxX - 1;
+
+ if (my < 0)
+ my = 0;
+
+ if (my >= _mouseMaxY)
+ my = _mouseMaxY - 1;
+
+ if ((mx != _mouseX) || (my != _mouseY)) {
+
+ event.type = Common::EVENT_MOUSEMOVE;
+ event.mouse.x = _mouseX = mx;
+ event.mouse.y = _mouseY = my;
+
+ _dirtyOffscreen = true;
+
+ return true;
+ }
+
+ }
+
+ return false;
+}
+
diff --git a/backends/platform/n64/osys_n64_utilities.cpp b/backends/platform/n64/osys_n64_utilities.cpp
new file mode 100644
index 0000000000..ae309638ac
--- /dev/null
+++ b/backends/platform/n64/osys_n64_utilities.cpp
@@ -0,0 +1,123 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ */
+
+#include "osys_n64.h"
+
+void checkTimers(void) {
+ OSystem_N64 *osys = (OSystem_N64*)g_system;
+
+ uint32 curTime = osys->getMillis();
+
+ // Timer checking & firing
+ if (osys->_timerCallback && (curTime >= osys->_timerCallbackNext)) {
+ osys->_timerCallback(osys->_timerCallbackTimer);
+ osys->_timerCallbackNext = curTime + osys->_timerCallbackTimer;
+ }
+}
+
+void disableAudioPlayback(void) {
+ if (!_audioEnabled) return;
+
+ _audioEnabled = false;
+
+ OSystem_N64 *osys = (OSystem_N64*)g_system;
+ Audio::MixerImpl *_localmixer = (Audio::MixerImpl*)osys->getMixer();
+
+ while (AI_busy()); // Wait for audio to stop
+}
+
+void enableAudioPlayback(void) {
+ static bool _firstRun = true;
+
+ OSystem_N64 *osys = (OSystem_N64*)g_system;
+ Audio::MixerImpl *_localmixer = (Audio::MixerImpl*)osys->getMixer();
+
+ uint32 samples = 4096; // 4096 bytes -> 2048 samples.
+
+ initAudioInterface(osys->_viClockRate, DEFAULT_SOUND_SAMPLE_RATE, 16, samples);
+ osys->_audioBufferSize = getAIBufferSize();
+
+ if (_firstRun) {
+ _localmixer->setOutputRate(DEFAULT_SOUND_SAMPLE_RATE);
+ _localmixer->setReady(true);
+ _firstRun = false;
+ }
+
+ disable_interrupts();
+
+ _audioEnabled = true;
+
+ sndCallback();
+ sndCallback();
+
+ registerAIhandler(sndCallback); // Lib checks if i try to register it multiple times
+
+ enable_interrupts();
+}
+
+static volatile Uint32 _requiredSoundSlots = 0;
+
+void vblCallback(void) {
+ // Switch display buffer
+ switchDisplayBuffer();
+
+#if 1
+ // If audio buffer got depleted, refill it.
+ if (_audioEnabled && !AI_busy() && !_requiredSoundSlots) {
+ sndCallback();
+ sndCallback();
+ }
+#endif
+
+}
+
+void sndCallback() {
+ // Signal that an audio buffer finished playing and that we need more samples
+ if (_requiredSoundSlots < 2)
+ _requiredSoundSlots++;
+}
+
+void refillAudioBuffers(void) {
+ if (!_audioEnabled) return;
+
+ OSystem_N64 *osys = (OSystem_N64*)g_system;
+ byte *sndBuf;
+ Audio::MixerImpl *_localmixer = (Audio::MixerImpl*)osys->getMixer();
+
+ while (_requiredSoundSlots) {
+ sndBuf = (byte*)getAIBuffer();
+
+ _localmixer->mixCallback((byte*)sndBuf, osys->_audioBufferSize);
+
+ putAIBuffer();
+
+ _requiredSoundSlots--;
+ }
+}
+
+int timer_handler(int t) {
+ DefaultTimerManager *tm = (DefaultTimerManager *)g_system->getTimerManager();
+ tm->handler();
+ return t;
+}
+
diff --git a/backends/platform/n64/pad_rom.sh b/backends/platform/n64/pad_rom.sh
new file mode 100644
index 0000000000..0660f6c204
--- /dev/null
+++ b/backends/platform/n64/pad_rom.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+TARGET="scummvm"
+BASESIZE=2097152
+
+CARTSIZE=`ls -l $TARGET.v64 | cut -d" " -f5`
+
+REMAINDER=`echo $CARTSIZE % $BASESIZE | bc`
+REMAINDER=`echo $BASESIZE - $REMAINDER | bc`
+CARTSIZE=`echo $CARTSIZE + $REMAINDER | bc`
+
+ucon64 -q --n64 --v64 --chk --padn=$CARTSIZE $TARGET.v64
+
diff --git a/backends/platform/n64/pakfs_save_manager.cpp b/backends/platform/n64/pakfs_save_manager.cpp
new file mode 100644
index 0000000000..3fbf55a199
--- /dev/null
+++ b/backends/platform/n64/pakfs_save_manager.cpp
@@ -0,0 +1,92 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <n64utils.h>
+#include "pakfs_save_manager.h"
+
+static bool matches(const char *glob, const char *name);
+
+bool deleteSaveGame(const char *filename) {
+ int res = removeFileOnPak(filename);
+ flushCurrentPakData();
+
+ return (res == 0);
+}
+
+uint32 InPAKSave::read(void *buf, uint32 cnt) {
+ return pakfs_read(buf, 1, cnt, fd);
+}
+
+bool InPAKSave::seek(int32 offs, int whence) {
+ pakfs_seek(fd, offs, whence);
+
+ return true;
+}
+
+bool InPAKSave::skip(uint32 offset) {
+ pakfs_seek(fd, offset, SEEK_CUR);
+
+ return true;
+}
+
+uint32 OutPAKSave::write(const void *buf, uint32 cnt) {
+ return pakfs_write(buf, 1, cnt, fd);
+}
+
+Common::StringList PAKSaveManager::listSavefiles(const Common::String &pattern) {
+ PAKDIR *dirp = pakfs_opendir();
+ pakfs_dirent *dp;
+ Common::StringList list;
+
+ while ((dp = pakfs_readdir(dirp)) != NULL) {
+ if (matches(pattern.c_str(), dp->entryname))
+ list.push_back(dp->entryname);
+
+ free(dp);
+ }
+
+ pakfs_closedir(dirp);
+
+ return list;
+}
+
+static bool matches(const char *glob, const char *name) {
+ while (*glob)
+ if (*glob == '*') {
+ while (*glob == '*')
+ glob++;
+ do {
+ if ((*name == *glob || *glob == '?') &&
+ matches(glob, name))
+ return true;
+ } while (*name++);
+ return false;
+ } else if (!*name)
+ return false;
+ else if (*glob == '?' || *glob == *name) {
+ glob++;
+ name++;
+ } else
+ return false;
+ return !*name;
+}
+
diff --git a/backends/platform/n64/pakfs_save_manager.h b/backends/platform/n64/pakfs_save_manager.h
new file mode 100644
index 0000000000..d3e4b94d39
--- /dev/null
+++ b/backends/platform/n64/pakfs_save_manager.h
@@ -0,0 +1,124 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __PAKFS_SAVE_MANAGER__
+#define __PAKFS_SAVE_MANAGER__
+
+#include <common/savefile.h>
+#include <common/zlib.h>
+
+#include <pakfs.h> // N64 PakFS library
+
+bool deleteSaveGame(const char *filename);
+
+class InPAKSave : public Common::InSaveFile {
+private:
+ PAKFILE *fd;
+
+ uint32 read(void *buf, uint32 cnt);
+ bool skip(uint32 offset);
+ bool seek(int32 offs, int whence);
+
+public:
+ InPAKSave() : fd(0) { }
+
+ ~InPAKSave() {
+ if (fd != NULL)
+ pakfs_close(fd);
+ }
+
+ bool eos() const {
+ return pakfs_eof(fd);
+ }
+ void clearErr() {
+ pakfs_clearerr(fd);
+ }
+ int32 pos() const {
+ return pakfs_tell(fd);
+ }
+ int32 size() const {
+ return fd->size;
+ }
+
+ bool readSaveGame(const char *filename) {
+ fd = pakfs_open(filename, "r");
+ return (fd != NULL);
+ }
+};
+
+class OutPAKSave : public Common::OutSaveFile {
+private:
+ PAKFILE *fd;
+
+public:
+ uint32 write(const void *buf, uint32 cnt);
+
+ OutPAKSave(const char *_filename) {
+ fd = pakfs_open(_filename, "w");
+ }
+
+ ~OutPAKSave() {
+ if (fd != NULL) {
+ finalize();
+ pakfs_close(fd);
+ flushCurrentPakData();
+ }
+ }
+
+ bool err() const {
+ return pakfs_error(fd);
+ }
+ void clearErr() {
+ pakfs_clearerr(fd);
+ }
+ void finalize() {
+ pakfs_flush(fd);
+ }
+};
+
+class PAKSaveManager : public Common::SaveFileManager {
+public:
+
+ virtual Common::OutSaveFile *openForSaving(const Common::String &filename) {
+ return Common::wrapCompressedWriteStream(new OutPAKSave(filename.c_str()));
+ }
+
+ virtual Common::InSaveFile *openForLoading(const Common::String &filename) {
+ InPAKSave *s = new InPAKSave();
+ if (s->readSaveGame(filename.c_str())) {
+ return Common::wrapCompressedReadStream(s);
+ } else {
+ delete s;
+ return NULL;
+ }
+ }
+
+ virtual bool removeSavefile(const Common::String &filename) {
+ return ::deleteSaveGame(filename.c_str());
+ }
+
+ virtual Common::StringList listSavefiles(const Common::String &pattern);
+};
+
+
+#endif
+
diff --git a/backends/platform/n64/portdefs.h b/backends/platform/n64/portdefs.h
new file mode 100644
index 0000000000..fd6d295b0c
--- /dev/null
+++ b/backends/platform/n64/portdefs.h
@@ -0,0 +1,46 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef __N64_PORTDEFS__
+#define __N64_PORTDEFS__
+
+#include <n64utils.h>
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <ctype.h>
+#include <math.h>
+#include <malloc.h>
+
+#undef assert
+#define assert(x) ((x) ? 0 : (print_error("["#x"] (%s:%d)", __FILE__, __LINE__)))
+
+#endif
+
diff --git a/common/debug.cpp b/common/debug.cpp
index 11b36e7d12..afdb794273 100644
--- a/common/debug.cpp
+++ b/common/debug.cpp
@@ -45,6 +45,13 @@
#define fflush(file) DS::std_fflush(file)
#endif
+#ifdef __N64__
+ #include <n64utils.h>
+
+ #define fputs(str, file) asm("nop");
+ #define fflush(a) asm("nop");
+ #define OutputDebugString addLineTextLayer
+#endif
// TODO: Move gDebugLevel into namespace Common.
diff --git a/common/scummsys.h b/common/scummsys.h
index aa801afd03..98dd47e171 100644
--- a/common/scummsys.h
+++ b/common/scummsys.h
@@ -301,6 +301,31 @@
#define SCUMM_LITTLE_ENDIAN
#define SCUMM_NEED_ALIGNMENT
+#elif defined(__N64__)
+
+ #define scumm_stricmp strcasecmp
+ #define scumm_strnicmp strncasecmp
+
+ #define SCUMM_BIG_ENDIAN
+ #define SCUMM_NEED_ALIGNMENT
+
+ #define STRINGBUFLEN 256
+
+ #define SCUMMVM_DONT_DEFINE_TYPES
+ typedef unsigned char byte;
+
+ typedef unsigned char uint8;
+ typedef signed char int8;
+
+ typedef unsigned short int uint16;
+ typedef signed short int int16;
+
+ typedef unsigned int uint32;
+ typedef signed int int32;
+
+ typedef unsigned long long uint64;
+ typedef signed long long int64;
+
#elif defined(__PSP__)
#include <malloc.h>
diff --git a/common/util.cpp b/common/util.cpp
index 94f5906b80..d131064e6c 100644
--- a/common/util.cpp
+++ b/common/util.cpp
@@ -46,6 +46,9 @@ extern bool isSmartphone();
#define fputs(str, file) DS::std_fwrite(str, strlen(str), 1, file)
#endif
+#ifdef __N64__
+ #define fputs(str, file) asm("nop");
+#endif
namespace Common {
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index 825c9fb777..f29bb6d283 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -163,7 +163,7 @@ bool ScummEngine::saveState(Common::OutSaveFile *out, bool writeHeader) {
memcpy(hdr.name, _saveLoadName, sizeof(hdr.name));
saveSaveGameHeader(out, hdr);
}
-#if !defined(__DS__) /* && !defined(__PLAYSTATION2__) */
+#if !defined(__DS__) && !defined(__N64__) /* && !defined(__PLAYSTATION2__) */
Graphics::saveThumbnail(*out);
#endif
saveInfos(out);
diff --git a/graphics/colormasks.h b/graphics/colormasks.h
index e14b32251e..b6cd9dcee4 100644
--- a/graphics/colormasks.h
+++ b/graphics/colormasks.h
@@ -117,10 +117,17 @@ struct ColorMasks<555> {
kGreenBits = 5,
kBlueBits = 5,
+#ifdef __N64__
+ kAlphaShift = 0,
+ kRedShift = kBlueBits+kGreenBits+1,
+ kGreenShift = kBlueBits + 1,
+ kBlueShift = 1,
+#else
kAlphaShift = 0,
kRedShift = kGreenBits+kBlueBits,
kGreenShift = kBlueBits,
kBlueShift = 0,
+#endif
kAlphaMask = ((1 << kAlphaBits) - 1) << kAlphaShift,
kRedMask = ((1 << kRedBits) - 1) << kRedShift,
diff --git a/sound/softsynth/opl/mame.cpp b/sound/softsynth/opl/mame.cpp
index 06ea8692ee..eaeda7846c 100644
--- a/sound/softsynth/opl/mame.cpp
+++ b/sound/softsynth/opl/mame.cpp
@@ -33,7 +33,7 @@
#include "mame.h"
-#if defined (_WIN32_WCE) || defined (__SYMBIAN32__) || defined(PALMOS_MODE) || defined(__GP32__) || defined(GP2X) || defined (__MAEMO__) || defined(__DS__) || defined (__MINT__)
+#if defined (_WIN32_WCE) || defined (__SYMBIAN32__) || defined(PALMOS_MODE) || defined(__GP32__) || defined(GP2X) || defined (__MAEMO__) || defined(__DS__) || defined (__MINT__) || defined(__N64__)
#include "common/config-manager.h"
#endif
@@ -1212,7 +1212,7 @@ FM_OPL *makeAdlibOPL(int rate) {
// We need to emulate one YM3812 chip
int env_bits = FMOPL_ENV_BITS_HQ;
int eg_ent = FMOPL_EG_ENT_HQ;
-#if defined (_WIN32_WCE) || defined(__SYMBIAN32__) || defined(PALMOS_MODE) || defined(__GP32__) || defined (GP2X) || defined(__MAEMO__) || defined(__DS__) || defined (__MINT__)
+#if defined (_WIN32_WCE) || defined(__SYMBIAN32__) || defined(PALMOS_MODE) || defined(__GP32__) || defined (GP2X) || defined(__MAEMO__) || defined(__DS__) || defined (__MINT__) || defined(__N64__)
if (ConfMan.hasKey("FM_high_quality") && ConfMan.getBool("FM_high_quality")) {
env_bits = FMOPL_ENV_BITS_HQ;
eg_ent = FMOPL_EG_ENT_HQ;