mirror of
https://github.com/libretro/scummvm.git
synced 2025-04-03 07:11:49 +00:00
3260 lines
73 KiB
C++
3260 lines
73 KiB
C++
/* 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.
|
|
*
|
|
*/
|
|
|
|
|
|
// - Remove scummconsole.c
|
|
// - Delete files
|
|
// - Fatlib conversion?
|
|
|
|
// - libcartreset
|
|
// - Alternative controls - tap for left click, double for right
|
|
// - Inherit the Earth?
|
|
// - Stereo audio?
|
|
// - Delete saves?
|
|
// - Software scaler?
|
|
// - 100% scale
|
|
|
|
// - Arrow keys cause key events when keyboard enabled - Done
|
|
// - Mouse cursor display - Done
|
|
// - Disable scaler on options menu - Done
|
|
// - Fix scale icons on top screen - Done
|
|
// - Fseek optimisation? - No need
|
|
// - Fix agi hack to be cleaner - done
|
|
// - Fix not typing looong words - Done
|
|
// - Show keyboard by default in AGI games
|
|
// - Fix mouse moving when cursor on keyboard screen - Done
|
|
// - Fix 'fit' thingy always appearing - Done
|
|
// - check cine backbuffer code - Done
|
|
// - Add long filename support - Done
|
|
// - New icons
|
|
// - Add key config for gob engine: Start:F1, Shift-numbers: F keys - Done
|
|
// - Fix [ds] appearing in game menu
|
|
|
|
// - Find out what's going wrong when you turn the console off
|
|
// - enable console when asserting
|
|
|
|
// - Alternative controls?
|
|
|
|
|
|
// - Fix 512x256 backbuffer to 320x240 - Done
|
|
// - Fix keyboard appearing on wrong screen - Done
|
|
// - Volume amplify option
|
|
// - Make save/restore game screen use scaler buffer
|
|
|
|
|
|
// 1.0.0!
|
|
// - Fix text on tabs on config screen
|
|
// - Remove ini file debug msg
|
|
// - Memory size for ite
|
|
// - Try discworld?
|
|
|
|
|
|
// Allow use of stuff in <nds.h>
|
|
#define FORBIDDEN_SYMBOL_EXCEPTION_printf
|
|
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
|
|
|
|
|
|
#include <nds.h>
|
|
#include <nds/registers_alt.h>
|
|
#include <nds/arm9/exceptions.h>
|
|
#include <nds/arm9/console.h>
|
|
|
|
//#include <ARM9/console.h> //basic print funcionality
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "NDS/scummvm_ipc.h"
|
|
#include "dsmain.h"
|
|
#include "osystem_ds.h"
|
|
#include "icons_raw.h"
|
|
#include "fat/gba_nds_fat.h"
|
|
#include "fat/disc_io.h"
|
|
#include "keyboard_raw.h"
|
|
#include "keyboard_pal_raw.h"
|
|
#define V16(a, b) ((a << 12) | b)
|
|
#include "touchkeyboard.h"
|
|
//#include "compact_flash.h"
|
|
#include "dsoptions.h"
|
|
#ifdef USE_DEBUGGER
|
|
#include "user_debugger.h"
|
|
#endif
|
|
#include "blitters.h"
|
|
#include "keys.h"
|
|
#ifdef USE_PROFILER
|
|
#include "profiler/cyg-profile.h"
|
|
#endif
|
|
#include "engine.h"
|
|
|
|
#include "backends/plugins/ds/ds-provider.h"
|
|
#include "backends/fs/ds/ds-fs.h"
|
|
#include "base/version.h"
|
|
#include "common/util.h"
|
|
|
|
extern "C" void OurIntrMain(void);
|
|
extern "C" u32 getExceptionAddress(u32 opcodeAddress, u32 thumbState);
|
|
|
|
extern const char __itcm_start[];
|
|
static const char *registerNames[] =
|
|
{ "r0","r1","r2","r3","r4","r5","r6","r7",
|
|
"r8 ","r9 ","r10","r11","r12","sp ","lr ","pc" };
|
|
|
|
#ifdef WRAP_MALLOC
|
|
|
|
extern "C" void *__real_malloc(size_t size);
|
|
|
|
static int s_total_malloc = 0;
|
|
|
|
void *operator new (size_t size) {
|
|
register unsigned int reg asm("lr");
|
|
volatile unsigned int poo = reg;
|
|
|
|
void *res = __real_malloc(size);
|
|
s_total_malloc += size;
|
|
|
|
if (!res) {
|
|
// *((u8 *) NULL) = 0;
|
|
consolePrintf("Failed alloc (new) %d (%d)\n", size, s_total_malloc);
|
|
return NULL;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
extern "C" void *__wrap_malloc(size_t size) {
|
|
/* u32 addr;
|
|
|
|
asm("mov %0, lr"
|
|
: "=r" (addr)
|
|
:
|
|
: );*/
|
|
|
|
register unsigned int reg asm("lr");
|
|
volatile unsigned int poo = reg;
|
|
|
|
|
|
if (size == 0) {
|
|
static int zeroSize = 0;
|
|
consolePrintf("0 size malloc (%d)", zeroSize++);
|
|
}
|
|
|
|
void *res = __real_malloc(size);
|
|
if (res) {
|
|
if (size > 50 * 1024) {
|
|
consolePrintf("Allocated %d (%x)\n", size, poo);
|
|
}
|
|
s_total_malloc += size;
|
|
return res;
|
|
} else {
|
|
|
|
// *((u8 *) NULL) = 0;
|
|
consolePrintf("Failed alloc %d (%d)\n", size, s_total_malloc);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
namespace DS {
|
|
|
|
// From console.c in NDSLib
|
|
|
|
//location of cursor
|
|
extern u8 row;
|
|
extern u8 col;
|
|
|
|
// Mouse mode
|
|
enum MouseMode {
|
|
MOUSE_LEFT, MOUSE_RIGHT, MOUSE_HOVER, MOUSE_NUM_MODES
|
|
};
|
|
|
|
// Defines
|
|
#define FRAME_TIME 17
|
|
#define SCUMM_GAME_HEIGHT 142
|
|
#define SCUMM_GAME_WIDTH 227
|
|
|
|
static int frameCount;
|
|
static int currentTimeMillis;
|
|
|
|
// Timer Callback
|
|
static int callbackInterval;
|
|
static int callbackTimer;
|
|
static OSystem_DS::TimerProc callback;
|
|
|
|
// Scaled
|
|
static bool scaledMode;
|
|
static int scX;
|
|
static int scY;
|
|
|
|
static int subScX;
|
|
static int subScY;
|
|
static int subScTargetX;
|
|
static int subScTargetY;
|
|
static int subScreenWidth = SCUMM_GAME_WIDTH;
|
|
static int subScreenHeight = SCUMM_GAME_HEIGHT;
|
|
static int subScreenScale = 256;
|
|
|
|
|
|
|
|
// Sound
|
|
static int bufferSize;
|
|
static s16 *soundBuffer;
|
|
static int bufferFrame;
|
|
static int bufferRate;
|
|
static int bufferSamples;
|
|
static bool soundHiPart;
|
|
static int soundFrequency;
|
|
|
|
// Events
|
|
static int lastEventFrame;
|
|
static bool indyFightState;
|
|
static bool indyFightRight;
|
|
|
|
static OSystem_DS::SoundProc soundCallback;
|
|
static int lastCallbackFrame;
|
|
static bool bufferFirstHalf;
|
|
static bool bufferSecondHalf;
|
|
|
|
// Saved buffers
|
|
static bool highBuffer;
|
|
static bool displayModeIs8Bit = false;
|
|
|
|
// Game id
|
|
static u8 gameID;
|
|
|
|
static bool snapToBorder = false;
|
|
static bool consoleEnable = false;
|
|
static bool gameScreenSwap = false;
|
|
bool isCpuScalerEnabled();
|
|
//#define HEAVY_LOGGING
|
|
|
|
static MouseMode mouseMode = MOUSE_LEFT;
|
|
|
|
static int storedMouseX = 0;
|
|
static int storedMouseY = 0;
|
|
|
|
// Sprites
|
|
static SpriteEntry sprites[128];
|
|
static SpriteEntry spritesMain[128];
|
|
static int tweak;
|
|
|
|
// Shake
|
|
static int s_shakePos = 0;
|
|
|
|
// Keyboard
|
|
static bool keyboardEnable = false;
|
|
static bool leftHandedMode = false;
|
|
static bool keyboardIcon = false;
|
|
|
|
// Touch
|
|
static int touchScX, touchScY, touchX, touchY;
|
|
static int mouseHotspotX, mouseHotspotY;
|
|
static bool cursorEnable = false;
|
|
static bool mouseCursorVisible = true;
|
|
static bool leftButtonDown = false;
|
|
static bool rightButtonDown = false;
|
|
static bool touchPadStyle = false;
|
|
static int touchPadSensitivity = 8;
|
|
static bool tapScreenClicks = true;
|
|
|
|
static int tapCount = 0;
|
|
static int tapTimeout = 0;
|
|
static int tapComplete = 0;
|
|
|
|
// Dragging
|
|
static int dragStartX, dragStartY;
|
|
static bool dragging = false;
|
|
static int dragScX, dragScY;
|
|
|
|
// Interface styles
|
|
static char gameName[32];
|
|
|
|
// 8-bit surface size
|
|
static int gameWidth = 320;
|
|
static int gameHeight = 200;
|
|
|
|
// Scale
|
|
static bool twoHundredPercentFixedScale = false;
|
|
static bool cpuScalerEnable = false;
|
|
|
|
// 100 256
|
|
// 150 192
|
|
// 200 128
|
|
|
|
// (256 << 8) / scale
|
|
|
|
|
|
|
|
#ifdef USE_PROFILER
|
|
static int hBlankCount = 0;
|
|
#endif
|
|
|
|
static u8 *scalerBackBuffer = NULL;
|
|
|
|
#define NUM_SUPPORTED_GAMES 21
|
|
|
|
static const gameListType gameList[NUM_SUPPORTED_GAMES] = {
|
|
// Unknown game - use normal SCUMM controls
|
|
{"unknown", CONT_SCUMM_ORIGINAL},
|
|
|
|
// SCUMM games
|
|
{"maniac", CONT_SCUMM_ORIGINAL},
|
|
{"zak", CONT_SCUMM_ORIGINAL},
|
|
{"loom", CONT_SCUMM_ORIGINAL},
|
|
{"indy3", CONT_SCUMM_ORIGINAL},
|
|
{"atlantis", CONT_SCUMM_ORIGINAL},
|
|
{"monkey", CONT_SCUMM_ORIGINAL},
|
|
{"monkey2", CONT_SCUMM_ORIGINAL},
|
|
{"tentacle", CONT_SCUMM_ORIGINAL},
|
|
{"samnmax", CONT_SCUMM_SAMNMAX},
|
|
|
|
// Non-SCUMM games
|
|
{"sky", CONT_SKY},
|
|
{"simon1", CONT_SIMON},
|
|
{"simon2", CONT_SIMON},
|
|
{"gob", CONT_GOBLINS},
|
|
{"queen", CONT_SCUMM_ORIGINAL},
|
|
{"cine", CONT_FUTURE_WARS},
|
|
{"agi", CONT_AGI},
|
|
{"elvira2", CONT_SIMON},
|
|
{"elvira1", CONT_SIMON},
|
|
{"waxworks", CONT_SIMON},
|
|
{"parallaction", CONT_NIPPON},
|
|
};
|
|
|
|
static const gameListType *s_currentGame = NULL;
|
|
|
|
// Stylus
|
|
static bool penDown = FALSE;
|
|
static bool penHeld = FALSE;
|
|
static bool penReleased = FALSE;
|
|
static bool penDownLastFrame = FALSE;
|
|
static s32 penX = 0, penY = 0;
|
|
static s32 penDownX = 0, penDownY = 0;
|
|
static int keysDownSaved = 0;
|
|
static int keysReleasedSaved = 0;
|
|
static int keysChangedSaved = 0;
|
|
|
|
static bool penDownSaved = FALSE;
|
|
static bool penReleasedSaved = FALSE;
|
|
static int penDownFrames = 0;
|
|
static int touchXOffset = 0;
|
|
static int touchYOffset = 0;
|
|
|
|
static int triggeredIcon = 0;
|
|
static int triggeredIconTimeout = 0;
|
|
|
|
static u16 savedPalEntry255 = RGB15(31, 31, 31);
|
|
|
|
|
|
extern "C" int scummvm_main(int argc, char *argv[]);
|
|
Common::EventType getKeyEvent(int key);
|
|
int getKeysChanged();
|
|
|
|
void updateStatus();
|
|
void triggerIcon(int imageNum);
|
|
void setIcon(int num, int x, int y, int imageNum, int flags, bool enable);
|
|
void setIconMain(int num, int x, int y, int imageNum, int flags, bool enable);
|
|
void uploadSpriteGfx();
|
|
|
|
static TransferSound soundControl;
|
|
|
|
static bool isScrollingWithDPad() {
|
|
return (getKeysHeld() & (KEY_L | KEY_R)) != 0;
|
|
}
|
|
|
|
bool isCpuScalerEnabled() {
|
|
return cpuScalerEnable || !displayModeIs8Bit;
|
|
}
|
|
|
|
|
|
void setCpuScalerEnable(bool enable) {
|
|
cpuScalerEnable = enable;
|
|
}
|
|
|
|
void setTrackPadStyleEnable(bool enable) {
|
|
touchPadStyle = enable;
|
|
}
|
|
|
|
void setTapScreenClicksEnable(bool enable) {
|
|
tapScreenClicks = enable;
|
|
}
|
|
|
|
void setGameScreenSwap(bool enable) {
|
|
gameScreenSwap = enable;
|
|
}
|
|
|
|
void setSensitivity(int sensitivity) {
|
|
touchPadSensitivity = sensitivity;
|
|
}
|
|
|
|
void setGamma(int gamma) {
|
|
OSystem_DS::instance()->setGammaValue(gamma);
|
|
}
|
|
|
|
void setTopScreenZoom(int percentage) {
|
|
// 100 256
|
|
// 150 192
|
|
// 200 128
|
|
|
|
// (256 << 8) / scale
|
|
|
|
s32 scale = (percentage << 8) / 100;
|
|
subScreenScale = (256 * 256) / scale;
|
|
|
|
// consolePrintf("Scale is %d %%\n", percentage);
|
|
}
|
|
|
|
// return (ConfMan.hasKey("cpu_scaler", "ds") && ConfMan.getBool("cpu_scaler", "ds"));
|
|
|
|
controlType getControlType() {
|
|
return s_currentGame->control;
|
|
}
|
|
|
|
|
|
//plays an 8 bit mono sample at 11025Hz
|
|
void playSound(const void *data, u32 length, bool loop, bool adpcm, int rate) {
|
|
|
|
if (!IPC->soundData) {
|
|
soundControl.count = 0;
|
|
}
|
|
|
|
soundControl.data[soundControl.count].data = data;
|
|
soundControl.data[soundControl.count].len = length | (loop ? 0x80000000 : 0x00000000);
|
|
soundControl.data[soundControl.count].rate = rate; // 367 samples per frame
|
|
soundControl.data[soundControl.count].pan = 64;
|
|
soundControl.data[soundControl.count].vol = 127;
|
|
soundControl.data[soundControl.count].format = adpcm ? 2 : 0;
|
|
|
|
soundControl.count++;
|
|
|
|
DC_FlushAll();
|
|
IPC->soundData = &soundControl;
|
|
}
|
|
|
|
void stopSound(int channel) {
|
|
playSound(NULL, 0, false, false, -channel);
|
|
}
|
|
|
|
void updateOAM() {
|
|
DC_FlushAll();
|
|
|
|
if (gameScreenSwap) {
|
|
dmaCopy(sprites, OAM, 128 * sizeof(SpriteEntry));
|
|
dmaCopy(spritesMain, OAM_SUB, 128 * sizeof(SpriteEntry));
|
|
} else {
|
|
dmaCopy(sprites, OAM_SUB, 128 * sizeof(SpriteEntry));
|
|
dmaCopy(spritesMain, OAM, 128 * sizeof(SpriteEntry));
|
|
}
|
|
}
|
|
|
|
void setGameSize(int width, int height) {
|
|
gameWidth = width;
|
|
gameHeight = height;
|
|
}
|
|
|
|
int getGameWidth() {
|
|
return gameWidth;
|
|
}
|
|
|
|
int getGameHeight() {
|
|
return gameHeight;
|
|
}
|
|
|
|
void initSprites() {
|
|
for (int i = 0; i < 128; i++) {
|
|
sprites[i].attribute[0] = ATTR0_DISABLED;
|
|
sprites[i].attribute[1] = 0;
|
|
sprites[i].attribute[2] = 0;
|
|
sprites[i].filler = 0;
|
|
}
|
|
|
|
for (int i = 0; i < 128; i++) {
|
|
spritesMain[i].attribute[0] = ATTR0_DISABLED;
|
|
spritesMain[i].attribute[1] = 0;
|
|
spritesMain[i].attribute[2] = 0;
|
|
spritesMain[i].filler = 0;
|
|
}
|
|
|
|
updateOAM();
|
|
}
|
|
|
|
|
|
void saveGameBackBuffer() {
|
|
|
|
// Sometimes the only copy of the game screen is in video memory.
|
|
// So, I lock the video memory here, as if I'm going to modify it. This
|
|
// forces OSystem_DS to create a system memory copy if one doesn't exist.
|
|
// This will be automatially restored by OSystem_DS::updateScreen().
|
|
|
|
OSystem_DS::instance()->lockScreen();
|
|
OSystem_DS::instance()->unlockScreen();
|
|
}
|
|
|
|
|
|
|
|
void startSound(int freq, int buffer) {
|
|
bufferRate = freq * 2;
|
|
bufferFrame = 0;
|
|
bufferSamples = 4096;
|
|
|
|
bufferFirstHalf = false;
|
|
bufferSecondHalf = true;
|
|
|
|
int bytes = (2 * (bufferSamples)) + 100;
|
|
|
|
soundBuffer = (s16 *) malloc(bytes * 2);
|
|
if (!soundBuffer)
|
|
consolePrintf("Sound buffer alloc failed\n");
|
|
|
|
|
|
soundHiPart = true;
|
|
|
|
for (int r = 0; r < bytes; r++) {
|
|
soundBuffer[r] = 0;
|
|
}
|
|
|
|
soundFrequency = freq;
|
|
|
|
|
|
swiWaitForVBlank();
|
|
swiWaitForVBlank();
|
|
playSound(soundBuffer, (bufferSamples * 2), true, false, freq * 2);
|
|
swiWaitForVBlank();
|
|
swiWaitForVBlank();
|
|
swiWaitForVBlank();
|
|
}
|
|
|
|
int getSoundFrequency() {
|
|
return soundFrequency;
|
|
}
|
|
|
|
void exitGame() {
|
|
s_currentGame = NULL;
|
|
}
|
|
|
|
void initGame() {
|
|
// This is a good time to check for left handed mode since the mode change is done as the game starts.
|
|
// There's probably a better way, but hey.
|
|
#ifdef HEAVY_LOGGING
|
|
consolePrintf("initing game...");
|
|
#endif
|
|
|
|
// static bool firstTime = true;
|
|
|
|
setOptions();
|
|
|
|
//strcpy(gameName, ConfMan.getActiveDomain().c_str());
|
|
if (s_currentGame == NULL) {
|
|
|
|
strcpy(gameName, ConfMan.get("gameid").c_str());
|
|
// consolePrintf("\n\n\n\nCurrent game: '%s' %d\n", gameName, gameName[0]);
|
|
|
|
s_currentGame = &gameList[0]; // Default game
|
|
|
|
for (int r = 0; r < NUM_SUPPORTED_GAMES; r++) {
|
|
if (!scumm_stricmp(gameName, gameList[r].gameId)) {
|
|
s_currentGame = &gameList[r];
|
|
// consolePrintf("Game list num: %d\n", r);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* if (firstTime) {
|
|
firstTime = false;
|
|
|
|
|
|
}
|
|
*/
|
|
#ifdef HEAVY_LOGGING
|
|
consolePrintf("done\n");
|
|
#endif
|
|
|
|
}
|
|
|
|
void setLeftHanded(bool enable) {
|
|
leftHandedMode = enable;
|
|
}
|
|
|
|
void setSnapToBorder(bool enable) {
|
|
snapToBorder = enable;
|
|
}
|
|
|
|
void setTouchXOffset(int x) {
|
|
touchXOffset = x;
|
|
}
|
|
|
|
void setTouchYOffset(int y) {
|
|
touchYOffset = y;
|
|
}
|
|
|
|
void set200PercentFixedScale(bool on) {
|
|
twoHundredPercentFixedScale = on;
|
|
}
|
|
|
|
void setUnscaledMode(bool enable) {
|
|
scaledMode = !enable;
|
|
}
|
|
|
|
void displayMode8Bit() {
|
|
|
|
#ifdef HEAVY_LOGGING
|
|
consolePrintf("displayMode8Bit...");
|
|
#endif
|
|
u16 buffer[32 * 32];
|
|
|
|
initGame();
|
|
|
|
setKeyboardEnable(false);
|
|
|
|
if (!displayModeIs8Bit) {
|
|
for (int r = 0; r < 32 * 32; r++) {
|
|
buffer[r] = ((u16 *) SCREEN_BASE_BLOCK_SUB(4))[r];
|
|
}
|
|
} else {
|
|
for (int r = 0; r < 32 * 32; r++) {
|
|
buffer[r] = ((u16 *) SCREEN_BASE_BLOCK(2))[r];
|
|
}
|
|
}
|
|
|
|
displayModeIs8Bit = true;
|
|
|
|
if (isCpuScalerEnabled()) {
|
|
videoSetMode(MODE_5_2D | (consoleEnable ? DISPLAY_BG0_ACTIVE : 0) | DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP);
|
|
videoSetModeSub(MODE_3_2D /*| DISPLAY_BG0_ACTIVE*/ | DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP); //sub bg 0 will be used to print text
|
|
|
|
vramSetBankA(VRAM_A_MAIN_BG_0x06000000);
|
|
vramSetBankB(VRAM_B_MAIN_BG_0x06020000);
|
|
|
|
vramSetBankC(VRAM_C_SUB_BG_0x06200000);
|
|
vramSetBankD(VRAM_D_SUB_SPRITE);
|
|
|
|
vramSetBankH(VRAM_H_LCD);
|
|
|
|
BG3_CR = BG_BMP16_256x256 | BG_BMP_BASE(8);
|
|
|
|
BG3_XDX = 256;
|
|
BG3_XDY = 0;
|
|
BG3_YDX = 0;
|
|
BG3_YDY = (int) ((200.0f / 192.0f) * 256);
|
|
|
|
} else {
|
|
videoSetMode(MODE_5_2D | (consoleEnable ? DISPLAY_BG0_ACTIVE : 0) | DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP);
|
|
videoSetModeSub(MODE_3_2D /*| DISPLAY_BG0_ACTIVE*/ | DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP); //sub bg 0 will be used to print text
|
|
|
|
vramSetBankA(VRAM_A_MAIN_BG_0x06000000);
|
|
vramSetBankB(VRAM_B_MAIN_BG_0x06020000);
|
|
|
|
vramSetBankC(VRAM_C_SUB_BG_0x06200000);
|
|
vramSetBankD(VRAM_D_SUB_SPRITE);
|
|
|
|
vramSetBankH(VRAM_H_LCD);
|
|
|
|
BG3_CR = BG_BMP8_512x256 | BG_BMP_BASE(8);
|
|
|
|
BG3_XDX = (int) (((float) (gameWidth) / 256.0f) * 256);
|
|
BG3_XDY = 0;
|
|
BG3_YDX = 0;
|
|
BG3_YDY = (int) ((200.0f / 192.0f) * 256);
|
|
}
|
|
|
|
SUB_BG3_CR = BG_BMP8_512x256;
|
|
|
|
SUB_BG3_XDX = (int) (subScreenWidth / 256.0f * 256);
|
|
SUB_BG3_XDY = 0;
|
|
SUB_BG3_YDX = 0;
|
|
SUB_BG3_YDY = (int) (subScreenHeight / 192.0f * 256);
|
|
|
|
|
|
|
|
consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 2, 0, true, true);
|
|
|
|
// Set this again because consoleinit resets it
|
|
videoSetMode(MODE_5_2D | (consoleEnable ? DISPLAY_BG0_ACTIVE : 0) | DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP);
|
|
|
|
// Move the cursor to the bottom of the screen using ANSI escape code
|
|
consolePrintf("\033[23;0f");
|
|
|
|
|
|
for (int r = 0; r < 32 * 32; r++) {
|
|
((u16 *) SCREEN_BASE_BLOCK(2))[r] = buffer[r];
|
|
// dmaCopyHalfWords(3, (u16 *) SCREEN_BASE_BLOCK(0), buffer, 32 * 32 * 2);
|
|
}
|
|
|
|
// ConsoleInit destroys the hardware palette :-(
|
|
if (OSystem_DS::instance()) {
|
|
OSystem_DS::instance()->restoreHardwarePalette();
|
|
}
|
|
|
|
// BG_PALETTE_SUB[255] = RGB15(31,31,31);//by default font will be rendered with color 255
|
|
|
|
// Do text stuff
|
|
// console chars at 1C000 (7), map at 1D000 (74)
|
|
|
|
// BG0_CR = BG_MAP_BASE(2) | BG_TILE_BASE(0);
|
|
// BG0_Y0 = 0;
|
|
|
|
// Restore palette entry used by text in the front-end
|
|
// PALETTE_SUB[255] = savedPalEntry255;
|
|
|
|
|
|
#ifdef HEAVY_LOGGING
|
|
consolePrintf("done\n");
|
|
#endif
|
|
|
|
if (gameScreenSwap) {
|
|
POWER_CR |= POWER_SWAP_LCDS;
|
|
} else {
|
|
POWER_CR &= ~POWER_SWAP_LCDS;
|
|
}
|
|
|
|
uploadSpriteGfx();
|
|
|
|
keyboardEnable = false;
|
|
|
|
}
|
|
|
|
void setGameID(int id) {
|
|
gameID = id;
|
|
}
|
|
|
|
void dummyHandler() {
|
|
REG_IF = IRQ_VBLANK;
|
|
}
|
|
|
|
void checkSleepMode() {
|
|
if (IPC->performArm9SleepMode) {
|
|
|
|
consolePrintf("ARM9 Entering sleep mode\n");
|
|
|
|
int intSave = REG_IE;
|
|
irqSet(IRQ_VBLANK, dummyHandler);
|
|
// int irqHandlerSave = (int) IRQ_HANDLER;
|
|
REG_IE = IRQ_VBLANK;
|
|
//IRQ_HANDLER = dummyHandler;
|
|
|
|
int powerSave = POWER_CR;
|
|
POWER_CR &= ~POWER_ALL;
|
|
|
|
while (IPC->performArm9SleepMode) {
|
|
swiWaitForVBlank();
|
|
}
|
|
|
|
POWER_CR = powerSave;
|
|
// IRQ_HANDLER = (void (*)()) irqHandlerSave;
|
|
irqSet(IRQ_VBLANK, VBlankHandler);
|
|
REG_IE = intSave;
|
|
|
|
consolePrintf("ARM9 Waking from sleep mode\n");
|
|
}
|
|
}
|
|
|
|
void setShowCursor(bool enable) {
|
|
if ((s_currentGame) && (s_currentGame->control == CONT_SCUMM_SAMNMAX)) {
|
|
if (cursorEnable) {
|
|
sprites[1].attribute[0] = ATTR0_BMP | 150;
|
|
} else {
|
|
sprites[1].attribute[0] = ATTR0_DISABLED;
|
|
}
|
|
|
|
}
|
|
|
|
cursorEnable = enable;
|
|
}
|
|
|
|
void setMouseCursorVisible(bool enable) {
|
|
mouseCursorVisible = enable;
|
|
}
|
|
|
|
void setCursorIcon(const u8 *icon, uint w, uint h, byte keycolor, int hotspotX, int hotspotY) {
|
|
|
|
int off;
|
|
|
|
mouseHotspotX = hotspotX;
|
|
mouseHotspotY = hotspotY;
|
|
|
|
//consolePrintf("Set cursor icon %d, %d\n", w, h);
|
|
|
|
off = 128*64;
|
|
|
|
|
|
memset(SPRITE_GFX + off, 0, 32 * 32 * 2);
|
|
memset(SPRITE_GFX_SUB + off, 0, 32 * 32 * 2);
|
|
|
|
|
|
for (uint y=0; y<h; y++) {
|
|
for (uint x=0; x<w; x++) {
|
|
int color = icon[y*w+x];
|
|
|
|
//consolePrintf("%d:%d ", color, OSystem_DS::instance()->getDSPaletteEntry(color));
|
|
|
|
if (color == keycolor) {
|
|
SPRITE_GFX[off+(y)*32+x] = 0x0000; // black background
|
|
SPRITE_GFX_SUB[off+(y)*32+x] = 0x0000; // black background
|
|
} else {
|
|
SPRITE_GFX[off+(y)*32+x] = OSystem_DS::instance()->getDSCursorPaletteEntry(color) | 0x8000;
|
|
SPRITE_GFX_SUB[off+(y)*32+x] = OSystem_DS::instance()->getDSCursorPaletteEntry(color) | 0x8000;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (s_currentGame->control != CONT_SCUMM_SAMNMAX)
|
|
return;
|
|
|
|
uint16 border = RGB15(24,24,24) | 0x8000;
|
|
|
|
|
|
off = 176*64;
|
|
memset(SPRITE_GFX_SUB+off, 0, 64*64*2);
|
|
memset(SPRITE_GFX+off, 0, 64*64*2);
|
|
|
|
int pos = 190 - (w+2);
|
|
|
|
|
|
|
|
// make border
|
|
for (uint i=0; i<w+2; i++) {
|
|
SPRITE_GFX[off+i] = border;
|
|
SPRITE_GFX[off+(31)*64+i] = border;
|
|
|
|
SPRITE_GFX_SUB[off+i] = border;
|
|
SPRITE_GFX_SUB[off+(31)*64+i] = border;
|
|
}
|
|
for (uint i=1; i<31; i++) {
|
|
SPRITE_GFX[off+(i*64)] = border;
|
|
SPRITE_GFX[off+(i*64)+(w+1)] = border;
|
|
|
|
SPRITE_GFX_SUB[off+(i*64)] = border;
|
|
SPRITE_GFX_SUB[off+(i*64)+(w+1)] = border;
|
|
}
|
|
|
|
int offset = (32 - h) >> 1;
|
|
|
|
for (uint y=0; y<h; y++) {
|
|
for (uint x=0; x<w; x++) {
|
|
int color = icon[y*w+x];
|
|
|
|
if (color == keycolor) {
|
|
SPRITE_GFX[off+(y+1+offset)*64+(x+1)] = 0x8000; // black background
|
|
SPRITE_GFX_SUB[off+(y+1+offset)*64+(x+1)] = 0x8000; // black background
|
|
} else {
|
|
SPRITE_GFX[off+(y+1+offset)*64+(x+1)] = BG_PALETTE[color] | 0x8000;
|
|
SPRITE_GFX_SUB[off+(y+1+offset)*64+(x+1)] = BG_PALETTE[color] | 0x8000;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (cursorEnable) {
|
|
sprites[1].attribute[0] = ATTR0_BMP | 150;
|
|
sprites[1].attribute[1] = ATTR1_SIZE_64 | pos;
|
|
sprites[1].attribute[2] = ATTR2_ALPHA(1) | 176;
|
|
} else {
|
|
sprites[1].attribute[0] = ATTR0_DISABLED | 150;
|
|
sprites[1].attribute[1] = ATTR1_SIZE_64 | pos;
|
|
sprites[1].attribute[2] = ATTR2_ALPHA(1) | 176;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void displayMode16Bit() {
|
|
#ifdef HEAVY_LOGGING
|
|
consolePrintf("displayMode16Bit...");
|
|
#endif
|
|
|
|
u16 buffer[32 * 32 * 2];
|
|
|
|
releaseAllKeys();
|
|
|
|
setKeyboardEnable(false);
|
|
|
|
if (!displayModeIs8Bit) {
|
|
for (int r = 0; r < 32 * 32; r++) {
|
|
buffer[r] = ((u16 *) SCREEN_BASE_BLOCK_SUB(4))[r];
|
|
}
|
|
} else {
|
|
saveGameBackBuffer();
|
|
for (int r = 0; r < 32 * 32; r++) {
|
|
buffer[r] = ((u16 *) SCREEN_BASE_BLOCK(2))[r];
|
|
}
|
|
}
|
|
|
|
|
|
videoSetMode(MODE_5_2D | /*DISPLAY_BG0_ACTIVE |*/ DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP);
|
|
videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE |/* DISPLAY_BG1_ACTIVE |*/ DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP); //sub bg 0 will be used to print text
|
|
|
|
vramSetBankA(VRAM_A_MAIN_BG);
|
|
vramSetBankB(VRAM_B_MAIN_BG);
|
|
vramSetBankC(VRAM_C_MAIN_BG);
|
|
vramSetBankD(VRAM_D_MAIN_BG);
|
|
vramSetBankH(VRAM_H_SUB_BG);
|
|
|
|
BG3_CR = BG_BMP16_512x256;
|
|
highBuffer = false;
|
|
|
|
|
|
memset(BG_GFX, 0, 512 * 256 * 2);
|
|
|
|
savedPalEntry255 = BG_PALETTE_SUB[255];
|
|
BG_PALETTE_SUB[255] = RGB15(31,31,31);//by default font will be rendered with color 255
|
|
|
|
// Do text stuff
|
|
SUB_BG0_CR = BG_MAP_BASE(4) | BG_TILE_BASE(0);
|
|
SUB_BG0_Y0 = 0;
|
|
|
|
consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 4, 0, false, true);
|
|
// consoleInitDefault((u16 *)SCREEN_BASE_BLOCK_SUB(4), (u16 *)CHAR_BASE_BLOCK_SUB(0), 16);
|
|
|
|
for (int r = 0; r < 32 * 32; r++) {
|
|
((u16 *) SCREEN_BASE_BLOCK_SUB(4))[r] = buffer[r];
|
|
}
|
|
|
|
consoleSetWindow(NULL, 0, 0, 32, 24);
|
|
// consolePrintSet(0, 23);
|
|
// consolePrintf("Hello world!\n\n");
|
|
// consolePrintf("\n");
|
|
|
|
// Show keyboard
|
|
SUB_BG1_CR = BG_TILE_BASE(1) | BG_MAP_BASE(12);
|
|
//drawKeyboard(1, 12);
|
|
|
|
POWER_CR &= ~POWER_SWAP_LCDS;
|
|
|
|
displayModeIs8Bit = false;
|
|
|
|
// ConsoleInit destroys the hardware palette :-(
|
|
OSystem_DS::instance()->restoreHardwarePalette();
|
|
|
|
BG3_XDX = isCpuScalerEnabled() ? 256 : (int) (1.25f * 256);
|
|
BG3_XDY = 0;
|
|
BG3_YDX = 0;
|
|
BG3_YDY = (int) ((200.0f / 192.0f) * 256);
|
|
|
|
#ifdef HEAVY_LOGGING
|
|
consolePrintf("done\n");
|
|
#endif
|
|
|
|
BG_PALETTE_SUB[255] = RGB15(31,31,31);//by default font will be rendered with color 255
|
|
|
|
}
|
|
|
|
|
|
void displayMode16BitFlipBuffer() {
|
|
#ifdef HEAVY_LOGGING
|
|
consolePrintf("Flip %s...", displayModeIs8Bit ? "8bpp" : "16bpp");
|
|
#endif
|
|
if (!displayModeIs8Bit) {
|
|
u16 *back = get16BitBackBuffer();
|
|
|
|
// highBuffer = !highBuffer;
|
|
// BG3_CR = BG_BMP16_512x256 | BG_BMP_RAM(highBuffer ? 1 : 0);
|
|
|
|
if (isCpuScalerEnabled()) {
|
|
Rescale_320x256x1555_To_256x256x1555(BG_GFX, back, 512, 512);
|
|
} else {
|
|
for (int r = 0; r < 512 * 256; r++) {
|
|
*(BG_GFX + r) = *(back + r);
|
|
}
|
|
}
|
|
} else if (isCpuScalerEnabled()) {
|
|
//#define SCALER_PROFILE
|
|
|
|
#ifdef SCALER_PROFILE
|
|
TIMER1_CR = TIMER_ENABLE | TIMER_DIV_1024;
|
|
u16 t0 = TIMER1_DATA;
|
|
#endif
|
|
const u8 *back = (const u8*)get8BitBackBuffer();
|
|
u16 *base = BG_GFX + 0x10000;
|
|
Rescale_320x256xPAL8_To_256x256x1555(
|
|
base,
|
|
back,
|
|
256,
|
|
get8BitBackBufferStride(),
|
|
BG_PALETTE,
|
|
getGameHeight() );
|
|
|
|
#ifdef SCALER_PROFILE
|
|
// 10 pixels : 1ms
|
|
u16 t1 = TIMER1_DATA;
|
|
TIMER1_CR &= ~TIMER_ENABLE;
|
|
u32 dt = t1 - t0;
|
|
u32 dt_us = (dt * 10240) / 334;
|
|
u32 dt_10ms = dt_us / 100;
|
|
int i;
|
|
for(i=0; i<dt_10ms; ++i)
|
|
base[i] = ((i/10)&1) ? 0xFFFF : 0x801F;
|
|
for(; i<256; ++i)
|
|
base[i] = 0x8000;
|
|
#endif
|
|
}
|
|
#ifdef HEAVY_LOGGING
|
|
consolePrintf("done\n");
|
|
#endif
|
|
}
|
|
|
|
void setShakePos(int shakePos) {
|
|
s_shakePos = shakePos;
|
|
}
|
|
|
|
|
|
u16 *get16BitBackBuffer() {
|
|
return BG_GFX + 0x20000;
|
|
}
|
|
|
|
s32 get8BitBackBufferStride() {
|
|
// When the CPU scaler is enabled, the back buffer is in system RAM and is
|
|
// 320 pixels wide. When the CPU scaler is disabled, the back buffer is in
|
|
// video memory and therefore must have a 512 pixel stride.
|
|
|
|
if (isCpuScalerEnabled()){
|
|
return 320;
|
|
} else {
|
|
return 512;
|
|
}
|
|
}
|
|
|
|
u16 *getScalerBuffer() {
|
|
return (u16 *) scalerBackBuffer;
|
|
}
|
|
|
|
u16 *get8BitBackBuffer() {
|
|
if (isCpuScalerEnabled())
|
|
return (u16 *) scalerBackBuffer;
|
|
else
|
|
return BG_GFX + 0x10000; // 16bit qty!
|
|
}
|
|
|
|
// The sound system in ScummVM seems to always return stereo interleaved samples.
|
|
// Here, I'm treating an 11Khz stereo stream as a 22Khz mono stream, which works sorta ok, but is
|
|
// a horrible bodge. Any advice on how to change the engine to output mono would be greatly
|
|
// appreciated.
|
|
void doSoundCallback() {
|
|
#ifdef HEAVY_LOGGING
|
|
consolePrintf("doSoundCallback...");
|
|
#endif
|
|
|
|
if (OSystem_DS::instance())
|
|
if (OSystem_DS::instance()->getMixerImpl()) {
|
|
lastCallbackFrame = frameCount;
|
|
|
|
for (int r = IPC->playingSection; r < IPC->playingSection + 4; r++) {
|
|
int chunk = r & 3;
|
|
|
|
if (IPC->fillNeeded[chunk]) {
|
|
IPC->fillNeeded[chunk] = false;
|
|
DC_FlushAll();
|
|
OSystem_DS::instance()->getMixerImpl()->mixCallback((byte *) (soundBuffer + ((bufferSamples >> 2) * chunk)), bufferSamples >> 1);
|
|
IPC->fillNeeded[chunk] = false;
|
|
DC_FlushAll();
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
#ifdef HEAVY_LOGGING
|
|
consolePrintf("done\n");
|
|
#endif
|
|
}
|
|
|
|
void doTimerCallback() {
|
|
if (callback) {
|
|
if (callbackTimer <= 0) {
|
|
callbackTimer += callbackInterval;
|
|
callback(callbackInterval);
|
|
}
|
|
}
|
|
}
|
|
|
|
void soundUpdate() {
|
|
if ((bufferFrame == 0)) {
|
|
// playSound(soundBuffer, (bufferSamples * 2), true);
|
|
}
|
|
// consolePrintf("%x\n", IPC->test);
|
|
|
|
|
|
if (bufferFrame == 0) {
|
|
// bufferFirstHalf = true;
|
|
}
|
|
if (bufferFrame == bufferSize >> 1) {
|
|
//bufferSecondHalf = true;
|
|
}
|
|
|
|
bufferFrame++;
|
|
if (bufferFrame == bufferSize) {
|
|
bufferFrame = 0;
|
|
}
|
|
}
|
|
|
|
void memoryReport() {
|
|
int r = 0;
|
|
int *p;
|
|
do {
|
|
p = (int *) malloc(r * 8192);
|
|
free(p);
|
|
r++;
|
|
} while ((p) && (r < 512));
|
|
|
|
int t = -1;
|
|
void *block[1024];
|
|
do {
|
|
t++;
|
|
block[t] = (int *) malloc(4096);
|
|
} while ((t < 1024) && (block[t]));
|
|
|
|
for (int q = 0; q < t; q++) {
|
|
free(block[q]);
|
|
}
|
|
|
|
consolePrintf("Free: %dK, Largest: %dK\n", t * 4, r * 8);
|
|
}
|
|
|
|
|
|
void addIndyFightingKeys() {
|
|
OSystem_DS *system = OSystem_DS::instance();
|
|
Common::Event event;
|
|
|
|
event.type = Common::EVENT_KEYDOWN;
|
|
event.kbd.flags = 0;
|
|
|
|
// consolePrintf("Fight keys\n");
|
|
|
|
if ((getKeysDown() & KEY_L)) {
|
|
indyFightRight = false;
|
|
}
|
|
|
|
if ((getKeysDown() & KEY_R)) {
|
|
indyFightRight = true;
|
|
}
|
|
|
|
// consolePrintf("ifr:%d\n", indyFightRight);
|
|
|
|
if ((getKeysChanged() & KEY_UP)) {
|
|
event.type = getKeyEvent(KEY_UP);
|
|
event.kbd.keycode = Common::KEYCODE_8;
|
|
event.kbd.ascii = '8';
|
|
system->addEvent(event);
|
|
}
|
|
if ((getKeysChanged() & KEY_LEFT)) {
|
|
event.type = getKeyEvent(KEY_LEFT);
|
|
event.kbd.keycode = Common::KEYCODE_4;
|
|
event.kbd.ascii = '4';
|
|
system->addEvent(event);
|
|
}
|
|
if ((getKeysChanged() & KEY_RIGHT)) {
|
|
event.type = getKeyEvent(KEY_RIGHT);
|
|
event.kbd.keycode = Common::KEYCODE_6;
|
|
event.kbd.ascii = '6';
|
|
system->addEvent(event);
|
|
}
|
|
if ((getKeysChanged() & KEY_DOWN)) {
|
|
event.type = getKeyEvent(KEY_DOWN);
|
|
event.kbd.keycode = Common::KEYCODE_2;
|
|
event.kbd.ascii = '2';
|
|
system->addEvent(event);
|
|
}
|
|
|
|
if (indyFightRight) {
|
|
|
|
if ((getKeysChanged() & KEY_X)) {
|
|
event.type = getKeyEvent(KEY_X);
|
|
event.kbd.keycode = Common::KEYCODE_9;
|
|
event.kbd.ascii = '9';
|
|
system->addEvent(event);
|
|
}
|
|
if ((getKeysChanged() & KEY_A)) {
|
|
event.type = getKeyEvent(KEY_A);
|
|
event.kbd.keycode = Common::KEYCODE_6;
|
|
event.kbd.ascii = '6';
|
|
system->addEvent(event);
|
|
}
|
|
if ((getKeysChanged() & KEY_B)) {
|
|
event.type = getKeyEvent(KEY_B);
|
|
event.kbd.keycode = Common::KEYCODE_3;
|
|
event.kbd.ascii = '3';
|
|
system->addEvent(event);
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((getKeysChanged() & KEY_X)) {
|
|
event.type = getKeyEvent(KEY_X);
|
|
event.kbd.keycode = Common::KEYCODE_7;
|
|
event.kbd.ascii = '7';
|
|
system->addEvent(event);
|
|
}
|
|
if ((getKeysChanged() & KEY_A)) {
|
|
event.type = getKeyEvent(KEY_A);
|
|
event.kbd.keycode = Common::KEYCODE_4;
|
|
event.kbd.ascii = '4';
|
|
system->addEvent(event);
|
|
}
|
|
if ((getKeysChanged() & KEY_B)) {
|
|
event.type = getKeyEvent(KEY_B);
|
|
event.kbd.keycode = Common::KEYCODE_1;
|
|
event.kbd.ascii = '1';
|
|
system->addEvent(event);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if ((getKeysChanged() & KEY_Y)) {
|
|
event.type = getKeyEvent(KEY_Y);
|
|
event.kbd.keycode = Common::KEYCODE_5;
|
|
event.kbd.ascii = '5';
|
|
system->addEvent(event);
|
|
}
|
|
}
|
|
|
|
|
|
void setKeyboardEnable(bool en) {
|
|
if (en == keyboardEnable) return;
|
|
keyboardEnable = en;
|
|
u16 *backupBank = (u16 *) 0x6040000;
|
|
|
|
if (keyboardEnable) {
|
|
|
|
|
|
DS::drawKeyboard(1, 15, backupBank);
|
|
|
|
|
|
SUB_BG1_CR = BG_TILE_BASE(1) | BG_MAP_BASE(15);
|
|
|
|
if (displayModeIs8Bit) {
|
|
SUB_DISPLAY_CR |= DISPLAY_BG1_ACTIVE; // Turn on keyboard layer
|
|
SUB_DISPLAY_CR &= ~DISPLAY_BG3_ACTIVE; // Turn off game layer
|
|
} else {
|
|
SUB_DISPLAY_CR |= DISPLAY_BG1_ACTIVE; // Turn on keyboard layer
|
|
SUB_DISPLAY_CR &= ~DISPLAY_BG0_ACTIVE; // Turn off console layer
|
|
}
|
|
|
|
// Ensure the keyboard is on the lower screen
|
|
POWER_CR |= POWER_SWAP_LCDS;
|
|
|
|
|
|
} else {
|
|
|
|
DS::releaseAllKeys();
|
|
// Restore the palette that the keyboard has used
|
|
for (int r = 0; r < 256; r++) {
|
|
BG_PALETTE_SUB[r] = BG_PALETTE[r];
|
|
}
|
|
|
|
|
|
//restoreVRAM(1, 12, backupBank);
|
|
|
|
if (displayModeIs8Bit) {
|
|
// Copy the sub screen VRAM from the top screen - they should always be
|
|
// the same.
|
|
u16 *buffer = get8BitBackBuffer();
|
|
s32 stride = get8BitBackBufferStride();
|
|
|
|
for (int y = 0; y < gameHeight; y++) {
|
|
for (int x = 0; x < gameWidth; x++) {
|
|
BG_GFX_SUB[y * 256 + x] = buffer[(y * (stride / 2)) + x];
|
|
}
|
|
}
|
|
/*
|
|
for (int r = 0; r < (512 * 256) >> 1; r++)
|
|
BG_GFX_SUB[r] = buffer[r];
|
|
*/
|
|
SUB_DISPLAY_CR &= ~DISPLAY_BG1_ACTIVE; // Turn off keyboard layer
|
|
SUB_DISPLAY_CR |= DISPLAY_BG3_ACTIVE; // Turn on game layer
|
|
} else {
|
|
SUB_DISPLAY_CR &= ~DISPLAY_BG1_ACTIVE; // Turn off keyboard layer
|
|
SUB_DISPLAY_CR |= DISPLAY_BG0_ACTIVE; // Turn on console layer
|
|
}
|
|
|
|
// Restore the screens so they're the right way round
|
|
if (gameScreenSwap) {
|
|
POWER_CR |= POWER_SWAP_LCDS;
|
|
} else {
|
|
POWER_CR &= ~POWER_SWAP_LCDS;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool getKeyboardEnable() {
|
|
return keyboardEnable;
|
|
}
|
|
|
|
bool getIsDisplayMode8Bit() {
|
|
return displayModeIs8Bit;
|
|
}
|
|
|
|
void doScreenTapMode(OSystem_DS *system) {
|
|
Common::Event event;
|
|
static bool left = false, right = false;
|
|
|
|
if (left) {
|
|
event.type = Common::EVENT_LBUTTONUP;
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
left = false;
|
|
}
|
|
|
|
if (right) {
|
|
event.type = Common::EVENT_RBUTTONUP;
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
right = false;
|
|
}
|
|
|
|
|
|
if (tapComplete == 1) {
|
|
event.type = Common::EVENT_LBUTTONDOWN;
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
tapComplete = 0;
|
|
left = true;
|
|
} else if (tapComplete == 2) {
|
|
event.type = Common::EVENT_RBUTTONDOWN;
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
tapComplete = 0;
|
|
right = true;
|
|
}
|
|
|
|
if (!isScrollingWithDPad()) {
|
|
|
|
if (getKeysDown() & KEY_LEFT) {
|
|
event.type = Common::EVENT_LBUTTONDOWN;
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
}
|
|
|
|
if (getKeysReleased() & KEY_LEFT) {
|
|
event.type = Common::EVENT_LBUTTONUP;
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
}
|
|
|
|
|
|
if (getKeysDown() & KEY_RIGHT) {
|
|
event.type = Common::EVENT_RBUTTONDOWN;
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
}
|
|
|
|
if (getKeysReleased() & KEY_RIGHT) {
|
|
event.type = Common::EVENT_RBUTTONUP;
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
}
|
|
}
|
|
|
|
event.type = Common::EVENT_MOUSEMOVE;
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
}
|
|
|
|
void doButtonSelectMode(OSystem_DS *system) {
|
|
Common::Event event;
|
|
|
|
|
|
if (!isScrollingWithDPad()) {
|
|
event.type = Common::EVENT_MOUSEMOVE;
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
//consolePrintf("x=%d y=%d \n", getPenX(), getPenY());
|
|
}
|
|
|
|
if (getPenReleased() && (leftButtonDown || rightButtonDown)) {
|
|
if (leftButtonDown) {
|
|
event.type = Common::EVENT_LBUTTONUP;
|
|
leftButtonDown = false;
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
} else if (rightButtonDown) {
|
|
event.type = Common::EVENT_RBUTTONUP;
|
|
rightButtonDown = false;
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
}
|
|
}
|
|
|
|
|
|
if ((mouseMode != MOUSE_HOVER) || (!displayModeIs8Bit)) {
|
|
if (getPenDown() && !isScrollingWithDPad()) {
|
|
if (mouseMode == MOUSE_LEFT) {
|
|
event.type = Common::EVENT_LBUTTONDOWN;
|
|
leftButtonDown = true;
|
|
} else {
|
|
event.type = Common::EVENT_RBUTTONDOWN;
|
|
rightButtonDown = true;
|
|
}
|
|
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
}
|
|
|
|
} else {
|
|
// In hover mode, D-pad left and right click the mouse when the pen is on the screen
|
|
|
|
if (getPenHeld()) {
|
|
if (getKeysDown() & KEY_LEFT) {
|
|
event.type = Common::EVENT_LBUTTONDOWN;
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
}
|
|
if (getKeysReleased() & KEY_LEFT) {
|
|
event.type = Common::EVENT_LBUTTONUP;
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
}
|
|
|
|
|
|
if (getKeysDown() & KEY_RIGHT) {
|
|
event.type = Common::EVENT_RBUTTONDOWN;
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
}
|
|
if (getKeysReleased() & KEY_RIGHT) {
|
|
event.type = Common::EVENT_RBUTTONUP;
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
system->addEvent(event);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!isScrollingWithDPad() && !getIndyFightState() && !getKeyboardEnable()) {
|
|
|
|
if (!getPenHeld() || (mouseMode != MOUSE_HOVER)) {
|
|
if (getKeysDown() & KEY_LEFT) {
|
|
mouseMode = MOUSE_LEFT;
|
|
}
|
|
|
|
if (rightButtonDown) {
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
event.type = Common::EVENT_RBUTTONUP;
|
|
system->addEvent(event);
|
|
rightButtonDown = false;
|
|
}
|
|
|
|
|
|
if (getKeysDown() & KEY_RIGHT) {
|
|
if ((s_currentGame->control != CONT_SCUMM_SAMNMAX) && (s_currentGame->control != CONT_FUTURE_WARS) && (s_currentGame->control != CONT_GOBLINS)) {
|
|
mouseMode = MOUSE_RIGHT;
|
|
} else {
|
|
// If we're playing sam and max, click and release the right mouse
|
|
// button to change verb
|
|
|
|
if (s_currentGame->control == CONT_FUTURE_WARS) {
|
|
event.mouse = Common::Point(320 - 128, 200 - 128);
|
|
event.type = Common::EVENT_MOUSEMOVE;
|
|
system->addEvent(event);
|
|
} else {
|
|
event.mouse = Common::Point(getPenX(), getPenY());
|
|
}
|
|
|
|
rightButtonDown = true;
|
|
|
|
|
|
event.type = Common::EVENT_RBUTTONDOWN;
|
|
system->addEvent(event);
|
|
|
|
//event.type = Common::EVENT_RBUTTONUP;
|
|
//system->addEvent(event);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (getKeysDown() & KEY_UP) {
|
|
mouseMode = MOUSE_HOVER;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void addEventsToQueue() {
|
|
#ifdef HEAVY_LOGGING
|
|
consolePrintf("addEventsToQueue\n");
|
|
#endif
|
|
OSystem_DS *system = OSystem_DS::instance();
|
|
Common::Event event;
|
|
|
|
#ifdef USE_PROFILER
|
|
/*
|
|
if (keysDown() & KEY_R) {
|
|
cygprofile_begin();
|
|
cygprofile_enable();
|
|
}
|
|
if (keysDown() & KEY_L) {
|
|
cygprofile_disable();
|
|
cygprofile_end();
|
|
}
|
|
*/
|
|
#endif
|
|
|
|
|
|
|
|
if (system->isEventQueueEmpty()) {
|
|
|
|
/*
|
|
if (getKeysDown() & KEY_L) {
|
|
tweak--;
|
|
consolePrintf("Tweak: %d\n", tweak);
|
|
IPC->tweakChanged = true;
|
|
}
|
|
|
|
|
|
if (getKeysDown() & KEY_R) {
|
|
tweak++;
|
|
consolePrintf("Tweak: %d\n", tweak);
|
|
IPC->tweakChanged = true;
|
|
}
|
|
*/
|
|
if ((keysHeld() & KEY_L) && (keysHeld() & KEY_R)) {
|
|
memoryReport();
|
|
}
|
|
|
|
if (displayModeIs8Bit) {
|
|
|
|
if (!indyFightState) {
|
|
|
|
if (!isScrollingWithDPad() && (getKeysDown() & KEY_B)) {
|
|
if (s_currentGame->control == CONT_AGI) {
|
|
event.kbd.keycode = Common::KEYCODE_RETURN;
|
|
event.kbd.ascii = 13;
|
|
event.kbd.flags = 0;
|
|
} else {
|
|
event.kbd.keycode = Common::KEYCODE_ESCAPE;
|
|
event.kbd.ascii = 27;
|
|
event.kbd.flags = 0;
|
|
}
|
|
|
|
event.type = Common::EVENT_KEYDOWN;
|
|
system->addEvent(event);
|
|
|
|
event.type = Common::EVENT_KEYUP;
|
|
system->addEvent(event);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((!getIndyFightState()) && (getKeysDown() & KEY_Y)) {
|
|
consoleEnable = !consoleEnable;
|
|
consolePrintf("Console enable: %d\n", consoleEnable);
|
|
if (displayModeIs8Bit) {
|
|
displayMode8Bit();
|
|
} else {
|
|
displayMode16Bit();
|
|
}
|
|
}
|
|
|
|
if ((getKeyboardEnable())) {
|
|
event.kbd.flags = 0;
|
|
|
|
bool down = getKeysDown() & (KEY_LEFT | KEY_RIGHT | KEY_UP | KEY_DOWN);
|
|
bool release = getKeysReleased() & (KEY_LEFT | KEY_RIGHT | KEY_UP | KEY_DOWN);
|
|
bool shoulders = getKeysHeld() & (KEY_L | KEY_R);
|
|
|
|
if ( (down && (!shoulders)) || release) {
|
|
|
|
if (getKeysChanged() & KEY_LEFT) {
|
|
event.kbd.keycode = Common::KEYCODE_LEFT;
|
|
event.kbd.ascii = 0;
|
|
event.type = getKeyEvent(KEY_LEFT);
|
|
system->addEvent(event);
|
|
}
|
|
|
|
if (getKeysChanged() & KEY_RIGHT) {
|
|
event.kbd.keycode = Common::KEYCODE_RIGHT;
|
|
event.kbd.ascii = 0;
|
|
event.type = getKeyEvent(KEY_RIGHT);
|
|
system->addEvent(event);
|
|
}
|
|
|
|
if (getKeysChanged() & KEY_UP) {
|
|
event.kbd.keycode = Common::KEYCODE_UP;
|
|
event.kbd.ascii = 0;
|
|
event.type = getKeyEvent(KEY_UP);
|
|
system->addEvent(event);
|
|
}
|
|
|
|
if (getKeysChanged() & KEY_DOWN) {
|
|
event.kbd.keycode = Common::KEYCODE_DOWN;
|
|
event.kbd.ascii = 0;
|
|
event.type = getKeyEvent(KEY_DOWN);
|
|
system->addEvent(event);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (!isScrollingWithDPad() && !getIndyFightState() && !getKeyboardEnable()) {
|
|
|
|
if ((getKeysDown() & KEY_A) && (!indyFightState)) {
|
|
gameScreenSwap = !gameScreenSwap;
|
|
|
|
if (gameScreenSwap) {
|
|
POWER_CR |= POWER_SWAP_LCDS;
|
|
} else {
|
|
POWER_CR &= ~POWER_SWAP_LCDS;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static int selectTimeDown = -1;
|
|
static const int SELECT_HOLD_TIME = 1000;
|
|
|
|
if (getKeysDown() & KEY_SELECT) {
|
|
selectTimeDown = getMillis();
|
|
}
|
|
|
|
if (selectTimeDown != -1) {
|
|
if (getKeysHeld() & KEY_SELECT) {
|
|
if (getMillis() - selectTimeDown >= SELECT_HOLD_TIME) {
|
|
// Hold select down for one second - show GMM
|
|
g_engine->openMainMenuDialog();
|
|
}
|
|
}
|
|
|
|
if (getKeysReleased() & KEY_SELECT) {
|
|
if (getMillis() - selectTimeDown < SELECT_HOLD_TIME) {
|
|
// Just pressed select - show DS options screen
|
|
showOptionsDialog();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!getIndyFightState() && !isScrollingWithDPad() && (getKeysDown() & KEY_X)) {
|
|
setKeyboardEnable(!keyboardEnable);
|
|
}
|
|
|
|
updateStatus();
|
|
|
|
|
|
if ((tapScreenClicks) && (getIsDisplayMode8Bit())) {
|
|
if ((!keyboardEnable) || (!isInsideKeyboard(penDownX, penDownY))) {
|
|
doScreenTapMode(system);
|
|
}
|
|
} else {
|
|
if (!keyboardEnable) {
|
|
doButtonSelectMode(system);
|
|
} else if ((!keyboardEnable) || (!isInsideKeyboard(penDownX, penDownY))) {
|
|
doScreenTapMode(system);
|
|
}
|
|
}
|
|
|
|
|
|
if (!keyboardEnable) {
|
|
if ((!isScrollingWithDPad() || (indyFightState)) && (displayModeIs8Bit)) {
|
|
// Controls specific to the control method
|
|
|
|
if (s_currentGame->control == CONT_SKY) {
|
|
// Extra controls for Beneath a Steel Sky
|
|
if ((getKeysDown() & KEY_DOWN)) {
|
|
penY = 0;
|
|
penX = 160; // Show inventory by moving mouse onto top line
|
|
}
|
|
}
|
|
|
|
if (s_currentGame->control == CONT_AGI) {
|
|
// Extra controls for Leisure Suit Larry and KQ4
|
|
if ((getKeysHeld() & KEY_UP) && (getKeysHeld() & KEY_START)
|
|
/*&& (!strcmp(gameName, "LLLLL"))*/) {
|
|
consolePrintf("Cheat key!\n");
|
|
event.type = Common::EVENT_KEYDOWN;
|
|
event.kbd.keycode = (Common::KeyCode)'X'; // Skip age test in LSL
|
|
event.kbd.ascii = 'X';
|
|
event.kbd.flags = Common::KBD_ALT;
|
|
system->addEvent(event);
|
|
|
|
event.type = Common::EVENT_KEYUP;
|
|
system->addEvent(event);
|
|
}
|
|
}
|
|
|
|
if (s_currentGame->control == CONT_SIMON) {
|
|
// Extra controls for Simon the Sorcerer
|
|
if ((getKeysDown() & KEY_DOWN)) {
|
|
event.type = Common::EVENT_KEYDOWN;
|
|
event.kbd.keycode = Common::KEYCODE_F10; // F10 or # - show hotspots
|
|
event.kbd.ascii = Common::ASCII_F10;
|
|
event.kbd.flags = 0;
|
|
system->addEvent(event);
|
|
// consolePrintf("F10\n");
|
|
|
|
event.type = Common::EVENT_KEYUP;
|
|
system->addEvent(event);
|
|
}
|
|
}
|
|
|
|
if (s_currentGame->control == CONT_SCUMM_ORIGINAL) {
|
|
// Extra controls for Scumm v1-5 games
|
|
if ((getKeysDown() & KEY_DOWN)) {
|
|
event.type = Common::EVENT_KEYDOWN;
|
|
event.kbd.keycode = Common::KEYCODE_PERIOD; // Full stop - skips current dialogue line
|
|
event.kbd.ascii = '.';
|
|
event.kbd.flags = 0;
|
|
system->addEvent(event);
|
|
|
|
event.type = Common::EVENT_KEYUP;
|
|
system->addEvent(event);
|
|
}
|
|
|
|
if (indyFightState) {
|
|
addIndyFightingKeys();
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if (!displayModeIs8Bit) {
|
|
// Front end controls
|
|
|
|
if (leftHandedSwap(getKeysChanged()) & KEY_UP) {
|
|
event.type = getKeyEvent(leftHandedSwap(KEY_UP));
|
|
event.kbd.keycode = Common::KEYCODE_UP;
|
|
event.kbd.ascii = 0;
|
|
event.kbd.flags = 0;
|
|
system->addEvent(event);
|
|
}
|
|
|
|
if (leftHandedSwap(getKeysChanged()) & KEY_DOWN) {
|
|
event.type = getKeyEvent(leftHandedSwap(KEY_DOWN));
|
|
event.kbd.keycode = Common::KEYCODE_DOWN;
|
|
event.kbd.ascii = 0;
|
|
event.kbd.flags = 0;
|
|
system->addEvent(event);
|
|
}
|
|
|
|
if (leftHandedSwap(getKeysDown()) & KEY_A) {
|
|
event.type = Common::EVENT_KEYDOWN;
|
|
event.kbd.keycode = Common::KEYCODE_RETURN;
|
|
event.kbd.ascii = 0;
|
|
event.kbd.flags = 0;
|
|
system->addEvent(event);
|
|
|
|
event.type = Common::EVENT_KEYUP;
|
|
system->addEvent(event);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if ((getKeysChanged() & KEY_START)) {
|
|
event.kbd.flags = 0;
|
|
event.type = getKeyEvent(KEY_START);
|
|
if (s_currentGame->control == CONT_FUTURE_WARS) {
|
|
event.kbd.keycode = Common::KEYCODE_F10;
|
|
event.kbd.ascii = Common::ASCII_F10;
|
|
} else if (s_currentGame->control == CONT_GOBLINS) {
|
|
event.kbd.keycode = Common::KEYCODE_F1;
|
|
event.kbd.ascii = Common::ASCII_F1;
|
|
// consolePrintf("!!!!!F1!!!!!");
|
|
} else if (s_currentGame->control == CONT_AGI) {
|
|
event.kbd.keycode = Common::KEYCODE_ESCAPE;
|
|
event.kbd.ascii = 27;
|
|
} else {
|
|
event.kbd.keycode = Common::KEYCODE_F5; // F5
|
|
event.kbd.ascii = Common::ASCII_F5;
|
|
// consolePrintf("!!!!!F5!!!!!");
|
|
}
|
|
system->addEvent(event);
|
|
}
|
|
|
|
|
|
if (keyboardEnable) {
|
|
DS::addKeyboardEvents();
|
|
}
|
|
|
|
consumeKeys();
|
|
consumePenEvents();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void triggerIcon(int imageNum) {
|
|
triggeredIcon = imageNum;
|
|
triggeredIconTimeout = 120;
|
|
}
|
|
|
|
|
|
void setIcon(int num, int x, int y, int imageNum, int flags, bool enable) {
|
|
sprites[num].attribute[0] = ATTR0_BMP | (enable ? (y & 0xFF) : 192) | (!enable ? ATTR0_DISABLED : 0);
|
|
sprites[num].attribute[1] = ATTR1_SIZE_32 | (x & 0x1FF) | flags;
|
|
sprites[num].attribute[2] = ATTR2_ALPHA(1)| (imageNum * 16);
|
|
}
|
|
|
|
void setIconMain(int num, int x, int y, int imageNum, int flags, bool enable) {
|
|
spritesMain[num].attribute[0] = ATTR0_BMP | (y & 0xFF) | (!enable ? ATTR0_DISABLED : 0);
|
|
spritesMain[num].attribute[1] = ATTR1_SIZE_32 | (x & 0x1FF) | flags;
|
|
spritesMain[num].attribute[2] = ATTR2_ALPHA(1)| (imageNum * 16);
|
|
}
|
|
|
|
void updateStatus() {
|
|
int offs;
|
|
|
|
if (displayModeIs8Bit) {
|
|
if (!tapScreenClicks) {
|
|
switch (mouseMode) {
|
|
case MOUSE_LEFT:
|
|
offs = 1;
|
|
break;
|
|
case MOUSE_RIGHT:
|
|
offs = 2;
|
|
break;
|
|
case MOUSE_HOVER:
|
|
offs = 0;
|
|
break;
|
|
default:
|
|
// Nothing!
|
|
offs = 0;
|
|
break;
|
|
}
|
|
|
|
setIcon(0, 208, 150, offs, 0, true);
|
|
}
|
|
|
|
if (indyFightState) {
|
|
setIcon(1, (190 - 32), 150, 3, (indyFightRight ? 0 : ATTR1_FLIP_X), true);
|
|
// consolePrintf("%d\n", indyFightRight);
|
|
} else {
|
|
// setIcon(1, 0, 0, 0, 0, false);
|
|
}
|
|
|
|
if (triggeredIconTimeout > 0) {
|
|
triggeredIconTimeout--;
|
|
setIcon(4, 16, 150, triggeredIcon, 0, true);
|
|
} else {
|
|
setIcon(4, 0, 0, 0, 0, false);
|
|
}
|
|
|
|
} else {
|
|
setIcon(0, 0, 0, 0, 0, false);
|
|
setIcon(1, 0, 0, 0, 0, false);
|
|
setIcon(2, 0, 0, 0, 0, false);
|
|
setIcon(3, 0, 0, 0, 0, false);
|
|
setIcon(4, 0, 0, 0, 0, false);
|
|
}
|
|
|
|
if ((keyboardIcon) && (!keyboardEnable) && (!displayModeIs8Bit)) {
|
|
// spritesMain[0].attribute[0] = ATTR0_BMP | 160;
|
|
// spritesMain[0].attribute[1] = ATTR1_SIZE_32 | 0;
|
|
// spritesMain[0].attribute[2] = ATTR2_ALPHA(1) | 64;
|
|
setIconMain(0, 0, 160, 4, 0, true);
|
|
} else {
|
|
// spritesMain[0].attribute[0] = ATTR0_DISABLED;
|
|
// spritesMain[0].attribute[1] = 0;
|
|
// spritesMain[0].attribute[2] = 0;
|
|
// spritesMain[0].filler = 0;
|
|
setIconMain(0, 0, 0, 0, 0, false);
|
|
}
|
|
|
|
}
|
|
|
|
void soundBufferEmptyHandler() {
|
|
REG_IF = IRQ_TIMER2;
|
|
|
|
if (soundHiPart) {
|
|
// bufferSecondHalf = true;
|
|
} else {
|
|
// bufferFirstHalf = true;
|
|
}
|
|
|
|
// TIMER0
|
|
if ((callback) && (callbackTimer > 0)) {
|
|
callbackTimer--;
|
|
}
|
|
currentTimeMillis++;
|
|
// TIMER0 end
|
|
|
|
soundHiPart = !soundHiPart;
|
|
}
|
|
|
|
void setMainScreenScroll(int x, int y) {
|
|
/* if (gameScreenSwap) {
|
|
SUB_BG3_CX = x + (((frameCount & 1) == 0)? 64: 0);
|
|
SUB_BG3_CY = y;
|
|
} else */{
|
|
BG3_CX = x + (((frameCount & 1) == 0)? 64: 0);
|
|
BG3_CY = y;
|
|
|
|
if ((!gameScreenSwap) || (touchPadStyle)) {
|
|
touchX = x >> 8;
|
|
touchY = y >> 8;
|
|
}
|
|
}
|
|
}
|
|
|
|
void setMainScreenScale(int x, int y) {
|
|
/* if (gameScreenSwap) {
|
|
SUB_BG3_XDX = x;
|
|
SUB_BG3_XDY = 0;
|
|
SUB_BG3_YDX = 0;
|
|
SUB_BG3_YDY = y;
|
|
} else*/ {
|
|
if (isCpuScalerEnabled() && (x==320)) {
|
|
BG3_XDX = 256;
|
|
BG3_XDY = 0;
|
|
BG3_YDX = 0;
|
|
BG3_YDY = y;
|
|
} else {
|
|
BG3_XDX = x;
|
|
BG3_XDY = 0;
|
|
BG3_YDX = 0;
|
|
BG3_YDY = y;
|
|
}
|
|
|
|
if ((!gameScreenSwap) || (touchPadStyle)) {
|
|
touchScX = x;
|
|
touchScY = y;
|
|
}
|
|
}
|
|
}
|
|
|
|
void setZoomedScreenScroll(int x, int y, bool shake) {
|
|
/* if (gameScreenSwap) {
|
|
BG3_CX = x + ((shake && ((frameCount & 1) == 0))? 64: 0);
|
|
BG3_CY = y;
|
|
|
|
touchX = x >> 8;
|
|
touchY = y >> 8;
|
|
} else */{
|
|
|
|
if ((gameScreenSwap) && (!touchPadStyle)) {
|
|
touchX = x >> 8;
|
|
touchY = y >> 8;
|
|
}
|
|
|
|
|
|
SUB_BG3_CX = x + ((shake && (frameCount & 1) == 0)? 64: 0);
|
|
SUB_BG3_CY = y;
|
|
}
|
|
}
|
|
|
|
void setZoomedScreenScale(int x, int y) {
|
|
/* if (gameScreenSwap) {
|
|
BG3_XDX = x;
|
|
BG3_XDY = 0;
|
|
BG3_YDX = 0;
|
|
BG3_YDY = y;
|
|
|
|
} else */{
|
|
|
|
if ((gameScreenSwap) && (!touchPadStyle)) {
|
|
touchScX = x;
|
|
touchScY = y;
|
|
}
|
|
|
|
SUB_BG3_XDX = x;
|
|
SUB_BG3_XDY = 0;
|
|
SUB_BG3_YDX = 0;
|
|
SUB_BG3_YDY = y;
|
|
}
|
|
}
|
|
|
|
#ifdef USE_PROFILER
|
|
void VBlankHandler(void) __attribute__ ((no_instrument_function));
|
|
#endif
|
|
|
|
void VBlankHandler(void) {
|
|
// BG_PALETTE[0] = RGB15(31, 31, 31);
|
|
// if (*((int *) (0x023FFF00)) != 0xBEEFCAFE) {
|
|
// consolePrintf("Guard band overwritten!");
|
|
// }
|
|
|
|
//consolePrintf("X:%d Y:%d\n", getPenX(), getPenY());
|
|
/*
|
|
if ((callback) && (callbackTimer > 0)) {
|
|
callbackTimer--;
|
|
}
|
|
currentTimeMillis++;
|
|
*/
|
|
/* static int firstTime = 1;
|
|
|
|
// This is to ensure that the ARM7 vblank handler runs before this one.
|
|
// Fixes the problem with the MMD when the screens swap over on load.
|
|
if (firstTime > 0) {
|
|
REG_IF = IRQ_VBLANK;
|
|
firstTime--;
|
|
return;
|
|
}
|
|
*/
|
|
|
|
IPC->tweak = tweak;
|
|
soundUpdate();
|
|
|
|
|
|
if ((!gameScreenSwap) && !isScrollingWithDPad()) {
|
|
if (s_currentGame) {
|
|
if (s_currentGame->control != CONT_SCUMM_SAMNMAX) {
|
|
if (getPenHeld() && (getPenY() < SCUMM_GAME_HEIGHT)) {
|
|
setTopScreenTarget(getPenX(), getPenY());
|
|
}
|
|
} else {
|
|
if (getPenHeld()) {
|
|
setTopScreenTarget(getPenX(), getPenY());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
penUpdate();
|
|
keysUpdate();
|
|
|
|
|
|
frameCount++;
|
|
|
|
if ((cursorEnable) && (mouseCursorVisible)) {
|
|
storedMouseX = penX;
|
|
storedMouseY = penY;
|
|
|
|
if (gameScreenSwap && touchPadStyle) {
|
|
setIcon(3, storedMouseX - mouseHotspotX, storedMouseY - mouseHotspotY, 8, 0, true);
|
|
setIconMain(3, 0, 0, 0, 0, false);
|
|
} else {
|
|
setIconMain(3, storedMouseX - mouseHotspotX, storedMouseY - mouseHotspotY, 8, 0, true);
|
|
setIcon(3, 0, 0, 0, 0, false);
|
|
}
|
|
} else {
|
|
setIconMain(3, 0, 0, 0, 0, false);
|
|
setIcon(3, 0, 0, 0, 0, false);
|
|
}
|
|
|
|
|
|
if (callback) {
|
|
callbackTimer -= FRAME_TIME;
|
|
}
|
|
|
|
if (isScrollingWithDPad()) {
|
|
|
|
if ((!dragging) && (getPenHeld()) && (penDownFrames > 5)) {
|
|
dragging = true;
|
|
dragStartX = penX;
|
|
dragStartY = penY;
|
|
|
|
if (gameScreenSwap) {
|
|
dragScX = subScTargetX;
|
|
dragScY = subScTargetY;
|
|
} else {
|
|
dragScX = scX;
|
|
dragScY = scY;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
if ((dragging) && (!getPenHeld())) {
|
|
dragging = false;
|
|
}
|
|
|
|
if (dragging) {
|
|
|
|
if (gameScreenSwap) {
|
|
subScTargetX = dragScX + ((dragStartX - penX) << 8);
|
|
subScTargetY = dragScY + ((dragStartY - penY) << 8);
|
|
} else {
|
|
scX = dragScX + ((dragStartX - penX));
|
|
scY = dragScY + ((dragStartY - penY));
|
|
}
|
|
|
|
// consolePrintf("X:%d Y:%d\n", dragStartX - penX, dragStartY - penY);
|
|
}
|
|
}
|
|
|
|
|
|
/* if ((frameCount & 1) == 0) {
|
|
SUB_BG3_CX = subScX;
|
|
} else {
|
|
SUB_BG3_CX = subScX + 64;
|
|
}
|
|
|
|
SUB_BG3_CY = subScY + (s_shakePos << 8);*/
|
|
|
|
/*SUB_BG3_XDX = (int) (subScreenWidth / 256.0f * 256);
|
|
SUB_BG3_XDY = 0;
|
|
SUB_BG3_YDX = 0;
|
|
SUB_BG3_YDY = (int) (subScreenHeight / 192.0f * 256);*/
|
|
|
|
static int ratio = (320 << 8) / SCUMM_GAME_WIDTH;
|
|
|
|
bool zooming = false;
|
|
|
|
if (isScrollingWithDPad()) {
|
|
if ((getKeysHeld() & KEY_A) && (subScreenScale < ratio)) {
|
|
subScreenScale += 1;
|
|
zooming = true;
|
|
}
|
|
|
|
if ((getKeysHeld() & KEY_B) && (subScreenScale > 128)) {
|
|
subScreenScale -=1;
|
|
zooming = true;
|
|
}
|
|
}
|
|
|
|
|
|
int xCenter = subScTargetX + ((subScreenWidth >> 1) << 8);
|
|
int yCenter = subScTargetY + ((subScreenHeight >> 1) << 8);
|
|
|
|
|
|
if (twoHundredPercentFixedScale) {
|
|
subScreenWidth = 256 >> 1;
|
|
subScreenHeight = 192 >> 1;
|
|
} else {
|
|
// subScreenWidth = (((SCUMM_GAME_HEIGHT * 256) / 192) * subScreenScale) >> 8;
|
|
// subScreenHeight = SCUMM_GAME_HEIGHT * subScreenScale >> 8;
|
|
|
|
|
|
subScreenWidth = (256 * subScreenScale) >> 8;
|
|
subScreenHeight = (192 * subScreenScale) >> 8;
|
|
|
|
if ( ((subScreenWidth) > 256 - 8) && ((subScreenWidth) < 256 + 8) ) {
|
|
subScreenWidth = 256;
|
|
subScreenHeight = 192;
|
|
if (zooming) {
|
|
subScX = subScTargetX;
|
|
subScY = subScTargetY;
|
|
triggerIcon(5);
|
|
}
|
|
} else if ( ((subScreenWidth) > 128 - 8) && ((subScreenWidth) < 128 + 8) ) {
|
|
subScreenWidth = 128;
|
|
subScreenHeight = 96;
|
|
if (zooming) {
|
|
subScX = subScTargetX;
|
|
subScY = subScTargetY;
|
|
triggerIcon(6);
|
|
}
|
|
} else if (subScreenWidth > 256) {
|
|
subScreenWidth = 320;
|
|
subScreenHeight = 200;
|
|
if (zooming) {
|
|
subScX = subScTargetX;
|
|
subScY = subScTargetY;
|
|
triggerIcon(7);
|
|
}
|
|
} else {
|
|
//triggerIcon(-1);
|
|
}
|
|
}
|
|
|
|
|
|
subScTargetX = xCenter - ((subScreenWidth >> 1) << 8);
|
|
subScTargetY = yCenter - ((subScreenHeight >> 1) << 8);
|
|
|
|
|
|
|
|
|
|
if (subScTargetX < 0) subScTargetX = 0;
|
|
if (subScTargetX > (gameWidth - subScreenWidth) << 8) subScTargetX = (gameWidth - subScreenWidth) << 8;
|
|
|
|
if (subScTargetY < 0) subScTargetY = 0;
|
|
if (subScTargetY > (gameHeight - subScreenHeight) << 8) subScTargetY = (gameHeight - subScreenHeight) << 8;
|
|
|
|
|
|
|
|
subScX += (subScTargetX - subScX) >> 2;
|
|
subScY += (subScTargetY - subScY) >> 2;
|
|
|
|
if (displayModeIs8Bit) {
|
|
|
|
if (isScrollingWithDPad()) {
|
|
|
|
int offsX = 0, offsY = 0;
|
|
|
|
|
|
if ((getKeysHeld() & KEY_LEFT)) {
|
|
offsX -= 2;
|
|
}
|
|
|
|
if ((getKeysHeld() & KEY_RIGHT)) {
|
|
offsX += 2;
|
|
}
|
|
|
|
if ((getKeysHeld() & KEY_UP)) {
|
|
offsY -= 2;
|
|
}
|
|
|
|
if ((getKeysHeld() & KEY_DOWN)) {
|
|
offsY += 2;
|
|
}
|
|
|
|
if (((gameScreenSwap) && (getKeysHeld() & KEY_L)) || ((!gameScreenSwap) && (getKeysHeld() & KEY_R))) {
|
|
subScTargetX += offsX << 8;
|
|
subScTargetY += offsY << 8;
|
|
} else {
|
|
scX += offsX;
|
|
scY += offsY;
|
|
}
|
|
}
|
|
|
|
if (!scaledMode) {
|
|
|
|
if (scX + 256 > gameWidth - 1) {
|
|
scX = gameWidth - 1 - 256;
|
|
}
|
|
|
|
if (scX < 0) {
|
|
scX = 0;
|
|
}
|
|
|
|
if (scY + 192 > gameHeight - 1) {
|
|
scY = gameHeight - 1 - 192;
|
|
}
|
|
|
|
if (scY < 0) {
|
|
scY = 0;
|
|
}
|
|
|
|
setZoomedScreenScroll(subScX, subScY, (subScreenWidth != 256) && (subScreenWidth != 128));
|
|
setZoomedScreenScale(subScreenWidth, ((subScreenHeight * (256 << 8)) / 192) >> 8);
|
|
|
|
|
|
setMainScreenScroll(scX << 8, (scY << 8) + (s_shakePos << 8));
|
|
setMainScreenScale(256, 256); // 1:1 scale
|
|
|
|
} else {
|
|
|
|
if (scY > gameHeight - 192 - 1) {
|
|
scY = gameHeight - 192 - 1;
|
|
}
|
|
|
|
if (scY < 0) {
|
|
scY = 0;
|
|
}
|
|
|
|
setZoomedScreenScroll(subScX, subScY, (subScreenWidth != 256) && (subScreenWidth != 128));
|
|
setZoomedScreenScale(subScreenWidth, ((subScreenHeight * (256 << 8)) / 192) >> 8);
|
|
|
|
setMainScreenScroll(64, (scY << 8) + (s_shakePos << 8));
|
|
setMainScreenScale(320, 256); // 1:1 scale
|
|
|
|
}
|
|
} else {
|
|
setZoomedScreenScroll(0, 0, true);
|
|
setZoomedScreenScale(320, 256);
|
|
|
|
setMainScreenScroll(0, 0);
|
|
setMainScreenScale(320, 256); // 1:1 scale
|
|
}
|
|
|
|
// Enable on screen keyboard when pen taps icon
|
|
if ((keyboardIcon) && (penX < 32) && (penY > 160) && (penHeld)) {
|
|
setKeyboardEnable(true);
|
|
}
|
|
|
|
if (keyboardEnable) {
|
|
if (DS::getKeyboardClosed()) {
|
|
setKeyboardEnable(false);
|
|
}
|
|
}
|
|
|
|
updateOAM();
|
|
|
|
//PALETTE[0] = RGB15(0, 0, 0);
|
|
//REG_IF = IRQ_VBLANK;
|
|
}
|
|
|
|
int getMillis(bool skipRecord) {
|
|
return currentTimeMillis;
|
|
// return frameCount * FRAME_TIME;
|
|
}
|
|
|
|
void setTimerCallback(OSystem_DS::TimerProc proc, int interval) {
|
|
// consolePrintf("Set timer proc %x, int %d\n", proc, interval);
|
|
callback = proc;
|
|
callbackInterval = interval;
|
|
callbackTimer = interval;
|
|
}
|
|
|
|
void timerTickHandler() {
|
|
// REG_IF = IRQ_TIMER0;
|
|
if ((callback) && (callbackTimer > 0)) {
|
|
callbackTimer--;
|
|
}
|
|
currentTimeMillis++;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void setTalkPos(int x, int y) {
|
|
// if (gameID != Scumm::GID_SAMNMAX) {
|
|
// setTopScreenTarget(x, 0);
|
|
// } else {
|
|
setTopScreenTarget(x, y);
|
|
// }
|
|
}
|
|
|
|
void setTopScreenTarget(int x, int y) {
|
|
subScTargetX = (x - (subScreenWidth >> 1));
|
|
subScTargetY = (y - (subScreenHeight >> 1));
|
|
|
|
if (subScTargetX < 0) subScTargetX = 0;
|
|
if (subScTargetX > gameWidth - subScreenWidth) subScTargetX = gameWidth - subScreenWidth;
|
|
|
|
if (subScTargetY < 0) subScTargetY = 0;
|
|
if (subScTargetY > gameHeight - subScreenHeight) subScTargetY = gameHeight - subScreenHeight;
|
|
|
|
subScTargetX <<=8;
|
|
subScTargetY <<=8;
|
|
}
|
|
|
|
#ifdef USE_PROFILER
|
|
void hBlankHanlder() __attribute__ ((no_instrument_function));
|
|
|
|
void hBlankHandler() {
|
|
hBlankCount++;
|
|
}
|
|
#endif
|
|
|
|
void uploadSpriteGfx() {
|
|
vramSetBankD(VRAM_D_SUB_SPRITE);
|
|
vramSetBankE(VRAM_E_MAIN_SPRITE);
|
|
|
|
// Convert texture from 24bit 888 to 16bit 1555, remembering to set top bit!
|
|
const u8 *srcTex = (const u8 *) ::icons_raw;
|
|
for (int r = 32 * 256 ; r >= 0; r--) {
|
|
SPRITE_GFX_SUB[r] = 0x8000 | (srcTex[r * 3] >> 3) | ((srcTex[r * 3 + 1] >> 3) << 5) | ((srcTex[r * 3 + 2] >> 3) << 10);
|
|
SPRITE_GFX[r] = 0x8000 | (srcTex[r * 3] >> 3) | ((srcTex[r * 3 + 1] >> 3) << 5) | ((srcTex[r * 3 + 2] >> 3) << 10);
|
|
}
|
|
|
|
}
|
|
|
|
void initHardware() {
|
|
// Guard band
|
|
//((int *) (0x023FFF00)) = 0xBEEFCAFE;
|
|
|
|
|
|
penInit();
|
|
|
|
powerOn(POWER_ALL);
|
|
/* vramSetBankA(VRAM_A_MAIN_BG);
|
|
vramSetBankB(VRAM_B_MAIN_BG);
|
|
vramSetBankC(VRAM_C_SUB_BG); */
|
|
vramSetBankD(VRAM_D_SUB_SPRITE);
|
|
vramSetBankE(VRAM_E_MAIN_SPRITE);
|
|
|
|
currentTimeMillis = 0;
|
|
|
|
|
|
/*
|
|
// Set up a millisecond counter
|
|
TIMER0_CR = 0;
|
|
TIMER0_DATA = 0xFFFF;
|
|
TIMER0_CR = TIMER_ENABLE | TIMER_CASCADE;
|
|
*/
|
|
|
|
|
|
for (int r = 0; r < 255; r++) {
|
|
BG_PALETTE[r] = 0;
|
|
}
|
|
|
|
BG_PALETTE[255] = RGB15(0,31,0);
|
|
|
|
|
|
for (int r = 0; r < 255; r++) {
|
|
BG_PALETTE_SUB[r] = 0;
|
|
}
|
|
|
|
BG_PALETTE_SUB[255] = RGB15(0,31,0);
|
|
|
|
// Allocate save buffer for game screen
|
|
// savedBuffer = new u8[320 * 200];
|
|
displayMode16Bit();
|
|
|
|
memset(BG_GFX, 0, 512 * 256 * 2);
|
|
scaledMode = true;
|
|
scX = 0;
|
|
scY = 0;
|
|
subScX = 0;
|
|
subScY = 0;
|
|
subScTargetX = 0;
|
|
subScTargetY = 0;
|
|
|
|
//lcdSwap();
|
|
POWER_CR &= ~POWER_SWAP_LCDS;
|
|
|
|
frameCount = 0;
|
|
callback = NULL;
|
|
|
|
// vramSetBankH(VRAM_H_SUB_BG);
|
|
|
|
|
|
// // Do text stuff
|
|
//BG0_CR = BG_MAP_BASE(0) | BG_TILE_BASE(1);
|
|
// BG0_Y0 = 48;
|
|
|
|
BG_PALETTE[255] = RGB15(31,31,31);//by default font will be rendered with color 255
|
|
|
|
//consoleInit() is a lot more flexible but this gets you up and running quick
|
|
// consoleInitDefault((u16 *)SCREEN_BASE_BLOCK(0), (u16 *)CHAR_BASE_BLOCK(1), 16);
|
|
//consolePrintSet(0, 6);
|
|
|
|
//irqs are nice
|
|
irqInit();
|
|
irqInitHandler(OurIntrMain);
|
|
irqSet(IRQ_VBLANK, VBlankHandler);
|
|
irqSet(IRQ_TIMER0, timerTickHandler);
|
|
irqSet(IRQ_TIMER2, soundBufferEmptyHandler);
|
|
|
|
irqEnable(IRQ_VBLANK);
|
|
irqEnable(IRQ_TIMER0);
|
|
// irqEnable(IRQ_TIMER2);
|
|
|
|
#ifdef USE_PROFILER
|
|
irqSet(IRQ_HBLANK, hBlankHandler);
|
|
irqEnable(IRQ_HBLANK);
|
|
#endif
|
|
|
|
|
|
// Set up a millisecond timer
|
|
#ifdef HEAVY_LOGGING
|
|
consolePrintf("Setting up timer...");
|
|
#endif
|
|
TIMER0_CR = 0;
|
|
TIMER0_DATA = (u32) TIMER_FREQ(1000);
|
|
TIMER0_CR = TIMER_ENABLE | TIMER_DIV_1 | TIMER_IRQ_REQ;
|
|
REG_IME = 1;
|
|
#ifdef HEAVY_LOGGING
|
|
consolePrintf("done\n");
|
|
#endif
|
|
|
|
BG_PALETTE[255] = RGB15(0,0,31);
|
|
|
|
initSprites();
|
|
|
|
// videoSetModeSub(MODE_3_2D | DISPLAY_BG0_ACTIVE | DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP); //sub bg 0 will be used to print text
|
|
|
|
// If the software scaler's back buffer has not been allocated, do it now
|
|
scalerBackBuffer = (u8 *) malloc(320 * 256);
|
|
|
|
|
|
WAIT_CR &= ~(0x0080);
|
|
// REG_WRAM_CNT = 0;
|
|
|
|
uploadSpriteGfx();
|
|
|
|
// This is a bodge to get around the fact that the cursor is turned on before it's image is set
|
|
// during startup in Sam & Max. This bodge moves the cursor offscreen so it is not seen.
|
|
sprites[1].attribute[1] = ATTR1_SIZE_64 | 192;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setKeyboardIcon(bool enable) {
|
|
keyboardIcon = enable;
|
|
}
|
|
|
|
bool getKeyboardIcon() {
|
|
return keyboardIcon;
|
|
}
|
|
|
|
|
|
////////////////////
|
|
// Pen stuff
|
|
////////////////////
|
|
|
|
|
|
void penInit() {
|
|
penDown = false;
|
|
penHeld = false;
|
|
penReleased = false;
|
|
penDownLastFrame = false;
|
|
penDownSaved = false;
|
|
penReleasedSaved = false;
|
|
penDownFrames = 0;
|
|
consumeKeys();
|
|
}
|
|
|
|
void penUpdate() {
|
|
|
|
// if (getKeysHeld() & KEY_L) consolePrintf("%d, %d penX=%d, penY=%d tz=%d\n", IPC->touchXpx, IPC->touchYpx, penX, penY, IPC->touchZ1);
|
|
|
|
bool penDownThisFrame = (!(IPC->buttons & 0x40)) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0);
|
|
static bool moved = false;
|
|
|
|
if (( (tapScreenClicks) || getKeyboardEnable() ) && (getIsDisplayMode8Bit())) {
|
|
|
|
|
|
if ((tapTimeout >= 0)) {
|
|
tapTimeout++;
|
|
|
|
if (((tapTimeout > 15) || (tapCount == 2)) && (tapCount > 0)) {
|
|
tapComplete = tapCount;
|
|
tapCount = 0;
|
|
// consolePrintf("Taps: %d\n", tapComplete);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if ((penHeld) && (!penDownThisFrame)) {
|
|
if ((touchPadStyle) || (getKeyboardEnable() && (!isInsideKeyboard(penDownX, penDownY))) || (moved) || (tapCount == 1)) {
|
|
if ((penDownFrames > 0) && (penDownFrames < 6) && ((tapTimeout == -1) || (tapTimeout > 2))) {
|
|
tapCount++;
|
|
tapTimeout = 0;
|
|
// consolePrintf("Tap! %d\n", penDownFrames);
|
|
moved = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ( ((keyboardEnable) || (touchPadStyle)) && (getIsDisplayMode8Bit()) ) {
|
|
// Relative positioning mode
|
|
|
|
|
|
if ((penDownFrames > 0) ) {
|
|
|
|
if ((penHeld)) {
|
|
|
|
if (penDownThisFrame) {
|
|
if (penDownFrames >= 2) {
|
|
|
|
if ((!keyboardEnable) || (!isInsideKeyboard(IPC->touchXpx, IPC->touchYpx))) {
|
|
int diffX = IPC->touchXpx - penDownX;
|
|
int diffY = IPC->touchYpx - penDownY;
|
|
|
|
int speed = ABS(diffX) + ABS(diffY);
|
|
|
|
if ((ABS(diffX) < 35) && (ABS(diffY) < 35)) {
|
|
|
|
if (speed >= 8) {
|
|
diffX *= ((speed >> 3) * touchPadSensitivity) >> 3;
|
|
diffY *= ((speed >> 3) * touchPadSensitivity) >> 3;
|
|
}
|
|
|
|
penX += diffX;
|
|
penY += diffY;
|
|
|
|
if (penX > 255) {
|
|
scX -= 255 - penX;
|
|
penX = 255;
|
|
}
|
|
|
|
if (penX < 0) {
|
|
scX -= -penX;
|
|
penX = 0;
|
|
}
|
|
|
|
if (penY > 191) {
|
|
scY += penY - 191;
|
|
penY = 191;
|
|
}
|
|
|
|
if (penY < 0) {
|
|
scY -= -penY;
|
|
penY = 0;
|
|
}
|
|
}
|
|
|
|
// consolePrintf("x: %d y: %d\n", IPC->touchYpx - penDownY, IPC->touchYpx - penDownY);
|
|
}
|
|
penDownX = IPC->touchXpx;
|
|
penDownY = IPC->touchYpx;
|
|
|
|
}
|
|
}
|
|
|
|
} else {
|
|
penDown = true;
|
|
penHeld = true;
|
|
penDownSaved = true;
|
|
|
|
// First frame, so save pen positions
|
|
if (penDownThisFrame) {
|
|
penDownX = IPC->touchXpx;
|
|
penDownY = IPC->touchYpx;
|
|
}
|
|
}
|
|
} else {
|
|
if (penHeld) {
|
|
penReleased = true;
|
|
penReleasedSaved = true;
|
|
} else {
|
|
penReleased = false;
|
|
}
|
|
|
|
penDown = false;
|
|
penHeld = false;
|
|
}
|
|
|
|
|
|
} else { // Absolute positioning mode
|
|
if ((penDownFrames > 1)) { // Is this right? Dunno, but it works for me.
|
|
|
|
if ((penHeld)) {
|
|
penHeld = true;
|
|
penDown = false;
|
|
} else {
|
|
if (penDownFrames == 2) {
|
|
penDownX = IPC->touchXpx;
|
|
penDownY = IPC->touchYpx;
|
|
}
|
|
penDown = true;
|
|
penHeld = true;
|
|
penDownSaved = true;
|
|
}
|
|
|
|
if ((!(IPC->buttons & 0x40)) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0)) {
|
|
penX = IPC->touchXpx + touchXOffset;
|
|
penY = IPC->touchYpx + touchYOffset;
|
|
moved = true;
|
|
}
|
|
|
|
|
|
} else {
|
|
if (penHeld) {
|
|
penReleased = true;
|
|
penReleasedSaved = true;
|
|
} else {
|
|
penReleased = false;
|
|
}
|
|
|
|
penDown = false;
|
|
penHeld = false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if ((!(IPC->buttons & 0x40)) || ((penDownFrames == 2)) ) {
|
|
penDownLastFrame = true;
|
|
penDownFrames++;
|
|
} else {
|
|
penDownLastFrame = false;
|
|
penDownFrames = 0;
|
|
}
|
|
}
|
|
|
|
int leftHandedSwap(int keys) {
|
|
// Start and select are unchanged
|
|
if (leftHandedMode) {
|
|
int result = keys & (~(KEY_R | KEY_L | KEY_Y | KEY_A | KEY_B | KEY_X | KEY_LEFT | KEY_RIGHT | KEY_UP | KEY_DOWN));
|
|
|
|
if (keys & KEY_L) result |= KEY_R;
|
|
if (keys & KEY_R) result |= KEY_L;
|
|
|
|
if (keys & KEY_LEFT) result |= KEY_Y;
|
|
if (keys & KEY_RIGHT) result |= KEY_A;
|
|
if (keys & KEY_DOWN) result |= KEY_B;
|
|
if (keys & KEY_UP) result |= KEY_X;
|
|
|
|
if (keys & KEY_Y) result |= KEY_LEFT;
|
|
if (keys & KEY_A) result |= KEY_RIGHT;
|
|
if (keys & KEY_B) result |= KEY_DOWN;
|
|
if (keys & KEY_X) result |= KEY_UP;
|
|
|
|
return result;
|
|
} else {
|
|
return keys;
|
|
}
|
|
}
|
|
|
|
void keysUpdate() {
|
|
scanKeys();
|
|
keysDownSaved |= leftHandedSwap(keysDown());
|
|
keysReleasedSaved |= leftHandedSwap(keysUp());
|
|
keysChangedSaved = keysDownSaved | keysReleasedSaved;
|
|
}
|
|
|
|
int getKeysDown() {
|
|
return keysDownSaved;
|
|
}
|
|
|
|
int getKeysHeld() {
|
|
return leftHandedSwap(keysHeld());
|
|
}
|
|
|
|
int getKeysReleased() {
|
|
return keysReleasedSaved;
|
|
}
|
|
|
|
int getKeysChanged() {
|
|
return keysChangedSaved;
|
|
}
|
|
|
|
Common::EventType getKeyEvent(int key) {
|
|
if (getKeysDown() & key) {
|
|
return Common::EVENT_KEYDOWN;
|
|
} else if (getKeysReleased() & key) {
|
|
return Common::EVENT_KEYUP;
|
|
} else {
|
|
return (Common::EventType) 0;
|
|
}
|
|
}
|
|
|
|
void consumeKeys() {
|
|
keysDownSaved = 0;
|
|
keysReleasedSaved = 0;
|
|
keysChangedSaved = 0;
|
|
}
|
|
|
|
bool getPenDown() {
|
|
return penDownSaved;
|
|
}
|
|
|
|
bool getPenHeld() {
|
|
return penHeld;
|
|
}
|
|
|
|
bool getPenReleased() {
|
|
return penReleasedSaved;
|
|
}
|
|
|
|
void consumePenEvents() {
|
|
penDownSaved = false;
|
|
penReleasedSaved = false;
|
|
}
|
|
|
|
int getPenX() {
|
|
int x = ((penX * touchScX) >> 8) + touchX;
|
|
x = x < 0? 0: (x > gameWidth - 1? gameWidth - 1: x);
|
|
|
|
if (snapToBorder) {
|
|
if (x < 8) x = 0;
|
|
if (x > gameWidth - 8) x = gameWidth - 1;
|
|
}
|
|
|
|
return x;
|
|
}
|
|
|
|
int getPenY() {
|
|
int y = ((penY * touchScY) >> 8) + touchY;
|
|
y = y < 0? 0: (y > gameHeight - 1? gameHeight - 1: y);
|
|
|
|
if (snapToBorder) {
|
|
if (y < 8) y = 0;
|
|
if (y > gameHeight - 8) y = gameHeight - 1;
|
|
}
|
|
|
|
return y;
|
|
}
|
|
|
|
GLvector getPenPos() {
|
|
GLvector v;
|
|
|
|
v.x = (penX * inttof32(1)) / SCREEN_WIDTH;
|
|
v.y = (penY * inttof32(1)) / SCREEN_HEIGHT;
|
|
|
|
return v;
|
|
}
|
|
|
|
void setIndyFightState(bool st) {
|
|
indyFightState = st;
|
|
indyFightRight = true;
|
|
}
|
|
|
|
bool getIndyFightState() {
|
|
return indyFightState;
|
|
}
|
|
|
|
///////////////////
|
|
// Fast Ram
|
|
///////////////////
|
|
|
|
#define FAST_RAM_SIZE (22500)
|
|
#define ITCM_DATA __attribute__((section(".itcm")))
|
|
|
|
u8 *fastRamPointer;
|
|
u8 fastRamData[FAST_RAM_SIZE] ITCM_DATA;
|
|
|
|
void *fastRamAlloc(int size) {
|
|
void *result = (void *) fastRamPointer;
|
|
fastRamPointer += size;
|
|
if(fastRamPointer > fastRamData + FAST_RAM_SIZE) {
|
|
consolePrintf("FastRam (ITCM) allocation failed!\n");
|
|
return malloc(size);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void fastRamReset() {
|
|
fastRamPointer = &fastRamData[0];
|
|
}
|
|
|
|
|
|
/////////////////
|
|
// GBAMP
|
|
/////////////////
|
|
|
|
bool GBAMPAvail = false;
|
|
|
|
bool initGBAMP(int mode) {
|
|
if (FAT_InitFiles()) {
|
|
if (mode == 2) {
|
|
disc_IsInserted();
|
|
}
|
|
GBAMPAvail = true;
|
|
// consolePrintf("Found flash card reader!\n");
|
|
return true;
|
|
} else {
|
|
GBAMPAvail = false;
|
|
// consolePrintf("Flash card reader not found!\n");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool isGBAMPAvailable() {
|
|
return GBAMPAvail;
|
|
}
|
|
|
|
|
|
#ifdef USE_DEBUGGER
|
|
void initDebugger() {
|
|
set_verbosity(VERBOSE_INFO | VERBOSE_ERROR);
|
|
wireless_init(0);
|
|
wireless_connect();
|
|
|
|
// This is where the address of the computer running the Java
|
|
// stub goes.
|
|
debugger_connect_tcp(192, 168, 0, 1);
|
|
debugger_init();
|
|
|
|
// Update function - should really call every frame
|
|
user_debugger_update();
|
|
}
|
|
|
|
|
|
// Ensure the function is processed with C linkage
|
|
extern "C" void debug_print_stub(char *string);
|
|
|
|
void debug_print_stub(char *string) {
|
|
consolePrintf(string);
|
|
}
|
|
#endif
|
|
|
|
|
|
void powerOff() {
|
|
while (keysHeld() != 0) { // Wait for all keys to be released.
|
|
swiWaitForVBlank(); // Allow you to read error before the power
|
|
} // is turned off.
|
|
|
|
for (int r = 0; r < 60; r++) {
|
|
swiWaitForVBlank();
|
|
}
|
|
|
|
if (ConfMan.hasKey("disablepoweroff", "ds") && ConfMan.getBool("disablepoweroff", "ds")) {
|
|
while (true);
|
|
} else {
|
|
|
|
IPC->reset = true; // Send message to ARM7 to turn power off
|
|
while (true) {
|
|
// Stop the program from continuing beyond this point
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////
|
|
// Main
|
|
/////////////////
|
|
|
|
|
|
|
|
void dsExceptionHandler() {
|
|
consolePrintf("Blue screen of death");
|
|
setExceptionHandler(NULL);
|
|
|
|
u32 currentMode = getCPSR() & 0x1f;
|
|
u32 thumbState = ((*(u32 *)0x027FFD90) & 0x20);
|
|
|
|
u32 codeAddress, exceptionAddress = 0;
|
|
|
|
int offset = 8;
|
|
|
|
if (currentMode == 0x17) {
|
|
consolePrintf("\x1b[10Cdata abort!\n\n");
|
|
codeAddress = exceptionRegisters[15] - offset;
|
|
if ( (codeAddress > 0x02000000 && codeAddress < 0x02400000) ||
|
|
(codeAddress > (u32)__itcm_start && codeAddress < (u32)(__itcm_start + 32768)) )
|
|
exceptionAddress = getExceptionAddress( codeAddress, thumbState);
|
|
else
|
|
exceptionAddress = codeAddress;
|
|
|
|
} else {
|
|
if (thumbState)
|
|
offset = 2;
|
|
else
|
|
offset = 4;
|
|
consolePrintf("\x1b[5Cundefined instruction!\n\n");
|
|
codeAddress = exceptionRegisters[15] - offset;
|
|
exceptionAddress = codeAddress;
|
|
}
|
|
|
|
consolePrintf(" pc: %08X addr: %08X\n\n",codeAddress,exceptionAddress);
|
|
|
|
|
|
int i;
|
|
for (i = 0; i < 8; i++) {
|
|
consolePrintf(" %s: %08X %s: %08X\n",
|
|
registerNames[i], exceptionRegisters[i],
|
|
registerNames[i+8],exceptionRegisters[i+8]);
|
|
}
|
|
|
|
while(1)
|
|
; // endles loop
|
|
|
|
u32 *stack = (u32 *)exceptionRegisters[13];
|
|
|
|
|
|
for (i = 0; i < 10; i++) {
|
|
consolePrintf("%08X %08X %08X\n", stack[i*3], stack[i*3+1], stack[(i*3)+2] );
|
|
}
|
|
|
|
memoryReport();
|
|
|
|
while(1);
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(void) {
|
|
|
|
soundCallback = NULL;
|
|
|
|
initHardware();
|
|
|
|
setExceptionHandler(dsExceptionHandler);
|
|
|
|
#ifdef USE_DEBUGGER
|
|
for (int r = 0; r < 150; r++) {
|
|
swiWaitForVBlank();
|
|
}
|
|
if (!(keysHeld() & KEY_Y)) {
|
|
initDebugger();
|
|
}
|
|
#endif
|
|
|
|
|
|
// Let arm9 read cartridge
|
|
*((u16 *) (0x04000204)) &= ~0x0080;
|
|
|
|
lastCallbackFrame = 0;
|
|
tweak = 0;
|
|
|
|
indyFightState = false;
|
|
indyFightRight = true;
|
|
|
|
|
|
// CPU speed = 67108864
|
|
// 8 frames = 2946 368.5 bytes per fr
|
|
|
|
// playSound(stretch, 47619, false);
|
|
// playSound(twang, 11010, true); // 18640
|
|
|
|
// bufferSize = 10;
|
|
|
|
|
|
/*bufferRate = 44100;
|
|
bufferFrame = 0;
|
|
bufferSamples = 8192;
|
|
|
|
bufferFirstHalf = false;
|
|
bufferSecondHalf = true;
|
|
|
|
int bytes = (2 * (bufferSamples)) + 100;
|
|
|
|
soundBuffer = (s16 *) malloc(bytes * 2);
|
|
|
|
|
|
soundHiPart = true;
|
|
|
|
for (int r = 0; r < bytes; r++) {
|
|
soundBuffer[r] = 0;
|
|
}
|
|
|
|
|
|
swiWaitForVBlank();
|
|
swiWaitForVBlank();
|
|
playSound(soundBuffer, (bufferSamples * 2), true);
|
|
swiWaitForVBlank();
|
|
swiWaitForVBlank();
|
|
swiWaitForVBlank();
|
|
*/
|
|
|
|
|
|
lastEventFrame = 0;
|
|
mouseMode = MOUSE_LEFT;
|
|
|
|
|
|
/*
|
|
TIMER1_CR = 0;
|
|
TIMER1_DATA = TIMER_FREQ(bufferRate);
|
|
TIMER1_CR = TIMER_ENABLE | TIMER_DIV_1;
|
|
|
|
TIMER2_CR = 0;
|
|
TIMER2_DATA = 0xFFFF - (bufferSamples / 2);
|
|
TIMER2_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_CASCADE;
|
|
*/
|
|
// 2945 - 2947
|
|
|
|
|
|
|
|
// for (int r = 2946; r < 3000; r++) {
|
|
// soundBuffer[r] = 30000;
|
|
// }
|
|
|
|
|
|
//2372
|
|
consolePrintf("-------------------------------\n");
|
|
consolePrintf("ScummVM DS\n");
|
|
consolePrintf("Ported by Neil Millstone\n");
|
|
consolePrintf("Version %s ", gScummVMVersion);
|
|
#if defined(DS_BUILD_A)
|
|
consolePrintf("build A\n");
|
|
consolePrintf("Lucasarts SCUMM games (SCUMM)\n");
|
|
#elif defined(DS_BUILD_B)
|
|
consolePrintf("build B\n");
|
|
consolePrintf("BASS, QUEEN\n");
|
|
#elif defined(DS_BUILD_C)
|
|
consolePrintf("build C\n");
|
|
consolePrintf("Simon/Elvira/Waxworks (AGOS)\n");
|
|
#elif defined(DS_BUILD_D)
|
|
consolePrintf("build D\n");
|
|
consolePrintf("AGI, CINE, GOB\n");
|
|
#elif defined(DS_BUILD_E)
|
|
consolePrintf("build E\n");
|
|
consolePrintf("Inherit the Earth (SAGA)\n");
|
|
#elif defined(DS_BUILD_F)
|
|
consolePrintf("build F\n");
|
|
consolePrintf("The Legend of Kyrandia (KYRA)\n");
|
|
#elif defined(DS_BUILD_G)
|
|
consolePrintf("build G\n");
|
|
consolePrintf("Lure of the Tempress (LURE)\n");
|
|
#elif defined(DS_BUILD_H)
|
|
consolePrintf("build H\n");
|
|
consolePrintf("Nippon Safes (PARALLATION)\n");
|
|
#elif defined(DS_BUILD_I)
|
|
consolePrintf("build I\n");
|
|
consolePrintf("Activision Games (MADE)\n");
|
|
#elif defined(DS_BUILD_K)
|
|
consolePrintf("build K\n");
|
|
consolePrintf("Cruise for a Corpse (Cruise)\n");
|
|
#endif
|
|
consolePrintf("-------------------------------\n");
|
|
consolePrintf("L/R + D-pad/pen: Scroll view\n");
|
|
consolePrintf("D-pad left: Left mouse button\n");
|
|
consolePrintf("D-pad right: Right mouse button\n");
|
|
consolePrintf("D-pad up: Hover mouse\n");
|
|
consolePrintf("B button: Skip cutscenes\n");
|
|
consolePrintf("Select: DS Options menu\n");
|
|
consolePrintf("Start: Game menu (some games)\n");
|
|
consolePrintf("Y (in game): Toggle console\n");
|
|
consolePrintf("X: Toggle keyboard\n");
|
|
consolePrintf("A: Swap screens\n");
|
|
consolePrintf("L+R (on start): Clear SRAM\n");
|
|
|
|
|
|
#if defined(DS_BUILD_A)
|
|
consolePrintf("For a complete key list see the\n");
|
|
consolePrintf("help screen.\n\n");
|
|
#else
|
|
consolePrintf("\n");
|
|
#endif
|
|
|
|
|
|
#ifdef USE_BUILT_IN_DRIVER_SELECTION
|
|
// Do M3 detection selectioon
|
|
int extraData = DSSaveFileManager::getExtraData();
|
|
bool present = DSSaveFileManager::isExtraDataPresent();
|
|
|
|
for (int r = 0; r < 30; r++) {
|
|
swiWaitForVBlank();
|
|
}
|
|
|
|
int mode = extraData & 0x03;
|
|
|
|
if (mode == 0) {
|
|
if ((keysHeld() & KEY_L) && !(keysHeld() & KEY_R)) {
|
|
mode = 1;
|
|
} else if (!(keysHeld() & KEY_L) && (keysHeld() & KEY_R)) {
|
|
mode = 2;
|
|
}
|
|
} else {
|
|
if ((keysHeld() & KEY_L) && !(keysHeld() & KEY_R)) {
|
|
mode = 0;
|
|
}
|
|
}
|
|
|
|
|
|
if (mode == 0) {
|
|
consolePrintf("On startup hold L if you have\n");
|
|
consolePrintf("an M3 SD or R for an SC SD\n");
|
|
} else if (mode == 1) {
|
|
consolePrintf("Using M3 SD Mode.\n");
|
|
consolePrintf("Hold L on startup to disable.\n");
|
|
} else if (mode == 2) {
|
|
consolePrintf("Using SC SD Mode.\n");
|
|
consolePrintf("Hold L on startup to disable.\n");
|
|
}
|
|
|
|
disc_setEnable(mode);
|
|
DSSaveFileManager::setExtraData(mode);
|
|
#else
|
|
|
|
int mode = 0;
|
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
if ((present) && (extraData & 0x00000001)) {
|
|
|
|
if (keysHeld() & KEY_L) {
|
|
extraData &= ~0x00000001;
|
|
consolePrintf("M3 SD Detection: OFF\n");
|
|
DSSaveFileManager::setExtraData(extraData);
|
|
} else {
|
|
consolePrintf("M3 SD Detection: ON\n");
|
|
consolePrintf("Hold L on startup to disable.\n");
|
|
}
|
|
|
|
} else if (keysHeld() & KEY_L) {
|
|
consolePrintf("M3 SD Detection: ON\n");
|
|
extraData |= 0x00000001;
|
|
DSSaveFileManager::setExtraData(extraData);
|
|
} else {
|
|
consolePrintf("M3 SD Detection: OFF\n");
|
|
consolePrintf("Hold L on startup to enable.\n");
|
|
}
|
|
|
|
disc_setM3SDEnable(extraData & 0x00000001);
|
|
*/
|
|
// Create a file system node to force search for a zip file in GBA rom space
|
|
|
|
DSFileSystemNode *node = new DSFileSystemNode();
|
|
if (!node->getZip() || (!node->getZip()->isReady())) {
|
|
// If not found, init CF/SD driver
|
|
initGBAMP(mode);
|
|
|
|
if (!initGBAMP(mode)) {
|
|
consolePrintf("\nNo file system was found.\n");
|
|
consolePrintf("View the readme file\n");
|
|
consolePrintf("for more information.\n");
|
|
|
|
while (1);
|
|
}
|
|
}
|
|
delete node;
|
|
|
|
|
|
|
|
updateStatus();
|
|
|
|
|
|
// OSystem_DS::instance();
|
|
|
|
g_system = new OSystem_DS();
|
|
assert(g_system);
|
|
|
|
IPC->adpcm.semaphore = false;
|
|
|
|
// printf("'%s'", Common::ConfigManager::kTransientDomain.c_str());
|
|
//printf("'%s'", Common::ConfigManager::kApplicationDomain.c_str());
|
|
|
|
#if defined(DS_BUILD_A)
|
|
const char *argv[] = {"/scummvmds"};
|
|
#elif defined(DS_BUILD_B)
|
|
const char *argv[] = {"/scummvmds", "--config=scummvmb.ini"};
|
|
#elif defined(DS_BUILD_C)
|
|
const char *argv[] = {"/scummvmds", "--config=scummvmc.ini"};
|
|
#elif defined(DS_BUILD_D)
|
|
const char *argv[] = {"/scummvmds", "--config=scummvmd.ini"};
|
|
#elif defined(DS_BUILD_E)
|
|
const char *argv[] = {"/scummvmds", "--config=scummvme.ini"};
|
|
#elif defined(DS_BUILD_F)
|
|
const char *argv[] = {"/scummvmds", "--config=scummvmf.ini"};
|
|
#elif defined(DS_BUILD_G)
|
|
const char *argv[] = {"/scummvmds", "--config=scummvmg.ini"};
|
|
#elif defined(DS_BUILD_H)
|
|
const char *argv[] = {"/scummvmds", "--config=scummvmh.ini"};
|
|
#elif defined(DS_BUILD_I)
|
|
const char *argv[] = {"/scummvmds", "--config=scummvmi.ini"};
|
|
#elif defined(DS_BUILD_J)
|
|
const char *argv[] = {"/scummvmds", "--config=scummvmj.ini"};
|
|
#elif defined(DS_BUILD_K)
|
|
const char *argv[] = {"/scummvmds", "--config=scummvmk.ini"};
|
|
#else
|
|
// Use the default config file if no build was specified. This currently
|
|
// only happens with builds made using the regular ScummVM build system (as
|
|
// opposed to the nds specific build system).
|
|
const char *argv[] = {"/scummvmds"};
|
|
#endif
|
|
|
|
#ifdef DYNAMIC_MODULES
|
|
PluginManager::instance().addPluginProvider(new DSPluginProvider());
|
|
#endif
|
|
|
|
while (1) {
|
|
scummvm_main(ARRAYSIZE(argv), (char **) &argv);
|
|
powerOff();
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
} // End of namespace DS
|
|
|
|
|
|
int main() {
|
|
#ifndef DISABLE_TEXT_CONSOLE
|
|
consoleDebugInit(DebugDevice_NOCASH);
|
|
nocashMessage("startup\n");
|
|
#endif
|
|
DS::main();
|
|
}
|
|
|
|
|
|
#ifdef USE_PROFILER
|
|
int cygprofile_getHBlanks() __attribute__ ((no_instrument_function));
|
|
|
|
|
|
int cygprofile_getHBlanks() {
|
|
return DS::hBlankCount;
|
|
}
|
|
|
|
|
|
extern "C" void consolePrintf(char * format, ...) __attribute__ ((no_instrument_function));
|
|
#endif
|
|
|
|
|
|
extern "C" void consolePrintf(const char * format, ...) {
|
|
va_list args;
|
|
va_start(args, format);
|
|
viprintf(format, args);
|
|
va_end(args);
|
|
}
|