scummvm/backends/platform/ds/arm9/source/dsmain.cpp
Yotam Barnoy 13b904d282 Merge from gsoc2010-plugins
This merge was extremely difficult to carry out. It wasn't entirely SVN's fault -- there were several merges to the branch that were done by hand. Please check for any issues and regressions. Also note that the DS makefile was not copied over since the "one at a time" plugin mode currently has too much fragmentation ie. it doesn't work.

svn-id: r54051
2010-11-03 22:01:01 +00:00

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.
*
* $URL$
* $Id$
*
*/
// - 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?
#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 (!stricmp(gameName, gameList[r].gameId)) {
s_currentGame = &gameList[r];
// consolePrintf("Game list num: %d\n", s_currentGame);
}
}
}
/* 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() {
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->touchZ1 > 0) && (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->touchZ1 > 0) && (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->touchZ1 > 0) || ((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 (24000)
#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);
}