Add Nintendo 64 port to trunk.

svn-id: r46773
This commit is contained in:
Fabio Battaglia 2009-12-30 21:11:38 +00:00
parent 0de5bac349
commit a108df30a7
22 changed files with 2159 additions and 3 deletions

View file

@ -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

View file

@ -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*/

213
backends/fs/n64/n64-fs.cpp Normal file
View file

@ -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__

View file

@ -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);
}

View file

@ -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 \

View file

@ -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

View file

@ -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)

View file

@ -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;
}

View file

@ -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__ */

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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>

View file

@ -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 {

View file

@ -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);

View file

@ -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,

View file

@ -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;