diff options
Diffstat (limited to 'backends')
-rw-r--r-- | backends/fs/n64/n64-fs-factory.cpp | 47 | ||||
-rw-r--r-- | backends/fs/n64/n64-fs-factory.h | 42 | ||||
-rw-r--r-- | backends/fs/n64/n64-fs.cpp | 213 | ||||
-rw-r--r-- | backends/fs/stdiostream.cpp | 22 | ||||
-rw-r--r-- | backends/module.mk | 1 | ||||
-rw-r--r-- | backends/platform/n64/Makefile | 93 | ||||
-rw-r--r-- | backends/platform/n64/module.mk | 10 | ||||
-rw-r--r-- | backends/platform/n64/nintendo64.cpp | 35 | ||||
-rw-r--r-- | backends/platform/n64/osys_n64.h | 206 | ||||
-rw-r--r-- | backends/platform/n64/osys_n64_base.cpp | 804 | ||||
-rw-r--r-- | backends/platform/n64/osys_n64_events.cpp | 243 | ||||
-rw-r--r-- | backends/platform/n64/osys_n64_utilities.cpp | 123 | ||||
-rw-r--r-- | backends/platform/n64/pad_rom.sh | 13 | ||||
-rw-r--r-- | backends/platform/n64/pakfs_save_manager.cpp | 92 | ||||
-rw-r--r-- | backends/platform/n64/pakfs_save_manager.h | 124 | ||||
-rw-r--r-- | backends/platform/n64/portdefs.h | 46 |
16 files changed, 2114 insertions, 0 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 + |