Import 0.3.2

This commit is contained in:
Gregory Montoir 2016-08-08 00:00:00 +08:00
parent 577fec920a
commit 5addfc699a
14 changed files with 269 additions and 168 deletions

View File

@ -1,6 +1,6 @@
REminiscence README
Release version: 0.3.1
Release version: 0.3.2
-------------------------------------------------------------------------------
@ -23,8 +23,6 @@ Data Files:
-----------
You will need the original files of the PC (DOS or CD) or Amiga release.
If you have a version distributed by SSI, you'll have to rename the files
and drop the 'ssi' suffix (ie. logosssi.cmd -> logos.cmd).
To hear background music during polygonal cutscenes with the PC version,
you'll need to copy the .mod files of the Amiga version :
@ -83,8 +81,6 @@ In-game hotkeys :
Ctrl S save game state
Ctrl L load game state
Ctrl + and - change game state slot
Ctrl R toggle input keys record
Ctrl P toggle input keys replay
Debug hotkeys :

View File

@ -40,7 +40,7 @@ void Game::col_clearState() {
}
void Game::col_preparePiegeState(LivePGE *pge) {
debug(DBG_COL, "Game::col_preparePiegeState() pge_num=%d", pge - &_pgeLive[0]);
debug(DBG_COL, "Game::col_preparePiegeState() pge_num=%ld", pge - &_pgeLive[0]);
CollisionSlot *ct_slot1, *ct_slot2;
if (pge->init_PGE->unk1C == 0) {
pge->collision_slot = 0xFF;

View File

@ -31,6 +31,7 @@ struct Cutscene {
static const char *_namesTable[];
static const uint16_t _offsetsTable[];
static const uint8_t _amigaDemoOffsetsTable[];
static const uint8_t _ssiOffsetsTable[];
static const uint16_t _cosTable[];
static const uint16_t _sinTable[];
static const uint8_t _creditsDataDOS[];

185
game.cpp
View File

@ -13,31 +13,47 @@
#include "unpack.h"
#include "util.h"
Game::Game(SystemStub *stub, FileSystem *fs, const char *savePath, int level, ResourceType ver, Language lang)
Game::Game(SystemStub *stub, FileSystem *fs, const char *savePath, int level, int demo, ResourceType ver, Language lang)
: _cut(&_res, stub, &_vid), _menu(&_res, stub, &_vid),
_mix(fs, stub), _res(fs, ver, lang), _seq(stub, &_mix), _vid(&_res, stub),
_stub(stub), _fs(fs), _savePath(savePath) {
_stateSlot = 1;
_inp_demo = 0;
_inp_record = false;
_inp_replay = false;
_inp_demPos = 0;
_skillLevel = _menu._skill = 1;
_currentLevel = _menu._level = level;
_demoBin = demo;
}
void Game::run() {
_randSeed = time(0);
if (_demoBin != -1) {
if (_demoBin < (int)ARRAYSIZE(_demoInputs)) {
const char *fn = _demoInputs[_demoBin].name;
debug(DBG_INFO, "Loading inputs from '%s'", fn);
_res.load_DEM(fn);
}
if (_res._demLen == 0) {
return;
}
}
_res.init();
_res.load_TEXT();
switch (_res._type) {
case kResourceTypeAmiga:
_res.load("FONT8", Resource::OT_FNT, "SPR");
if (_res._isDemo) {
_cut._patchedOffsetsTable = Cutscene::_amigaDemoOffsetsTable;
}
break;
case kResourceTypeDOS:
_res.load("FB_TXT", Resource::OT_FNT);
_res._hasSeqData = _fs->exists("INTRO.SEQ");
if (_fs->exists("logosssi.cmd")) {
_cut._patchedOffsetsTable = Cutscene::_ssiOffsetsTable;
}
break;
}
@ -51,8 +67,10 @@ void Game::run() {
_mix.init();
_mix._mod._isAmiga = _res.isAmiga();
playCutscene(0x40);
playCutscene(0x0D);
if (_demoBin == -1) {
playCutscene(0x40);
playCutscene(0x0D);
}
switch (_res._type) {
case kResourceTypeAmiga:
@ -70,25 +88,30 @@ void Game::run() {
}
while (!_stub->_pi.quit) {
switch (_res._type) {
case kResourceTypeDOS:
_mix.playMusic(1);
_menu.handleTitleScreen();
if (_menu._selectedOption == Menu::MENU_OPTION_ITEM_QUIT || _stub->_pi.quit) {
_stub->_pi.quit = true;
if (_demoBin != -1) {
_currentLevel = _demoInputs[_demoBin].level;
_randSeed = 0;
} else {
switch (_res._type) {
case kResourceTypeDOS:
_mix.playMusic(1);
_menu.handleTitleScreen();
if (_menu._selectedOption == Menu::MENU_OPTION_ITEM_QUIT || _stub->_pi.quit) {
_stub->_pi.quit = true;
break;
}
_skillLevel = _menu._skill;
_currentLevel = _menu._level;
_mix.stopMusic();
break;
case kResourceTypeAmiga:
displayTitleScreenAmiga();
_stub->setScreenSize(Video::GAMESCREEN_W, Video::GAMESCREEN_H);
break;
}
if (_stub->_pi.quit) {
break;
}
_skillLevel = _menu._skill;
_currentLevel = _menu._level;
_mix.stopMusic();
break;
case kResourceTypeAmiga:
displayTitleScreenAmiga();
_stub->setScreenSize(Video::GAMESCREEN_W, Video::GAMESCREEN_H);
break;
}
if (_stub->_pi.quit) {
break;
}
if (_currentLevel == 7) {
_vid.fadeOut();
@ -107,6 +130,10 @@ void Game::run() {
_frameTimestamp = _stub->getTimeStamp();
while (!_stub->_pi.quit && !_endLoop) {
mainLoop();
if (_demoBin != -1 && _inp_demPos >= _res._demLen) {
debug(DBG_INFO, "End of demo");
_stub->_pi.quit = true;
}
}
}
}
@ -370,52 +397,6 @@ void Game::inp_handleSpecialKeys() {
}
_stub->_pi.stateSlot = 0;
}
if (_stub->_pi.inpRecord || _stub->_pi.inpReplay) {
bool replay = false;
bool record = false;
char demoFile[20];
makeGameDemoName(demoFile);
if (_inp_demo) {
_inp_demo->close();
delete _inp_demo;
}
_inp_demo = new File;
if (_stub->_pi.inpRecord) {
if (_inp_record) {
debug(DBG_INFO, "Stop recording input keys");
} else {
if (_inp_demo->open(demoFile, "zwb", _savePath)) {
debug(DBG_INFO, "Recording input keys");
static const uint32_t TAG_FBDM = 0x4642444D;
_inp_demo->writeUint32BE(TAG_FBDM);
_inp_demo->writeUint16BE(0);
_inp_demo->writeUint32BE(_randSeed);
record = true;
} else {
warning("Unable to save demo file '%s'", demoFile);
}
}
}
if (_stub->_pi.inpReplay) {
if (_inp_replay) {
debug(DBG_INFO, "Stop replaying input keys");
} else {
if (_inp_demo->open(demoFile, "zrb", _savePath)) {
debug(DBG_INFO, "Replaying input keys");
_inp_demo->readUint32BE();
_inp_demo->readUint16BE();
_randSeed = _inp_demo->readUint32BE();
replay = true;
} else {
warning("Unable to open demo file '%s'", demoFile);
}
}
}
_inp_record = record;
_inp_replay = replay;
_stub->_pi.inpReplay = false;
_stub->_pi.inpRecord = false;
}
}
void Game::drawCurrentInventoryItem() {
@ -838,7 +819,7 @@ void Game::prepareAnims() {
}
void Game::prepareAnimsHelper(LivePGE *pge, int16_t dx, int16_t dy) {
debug(DBG_GAME, "Game::prepareAnimsHelper() dx=0x%X dy=0x%X pge_num=%d pge->flags=0x%X pge->anim_number=0x%X", dx, dy, pge - &_pgeLive[0], pge->flags, pge->anim_number);
debug(DBG_GAME, "Game::prepareAnimsHelper() dx=0x%X dy=0x%X pge_num=%ld pge->flags=0x%X pge->anim_number=0x%X", dx, dy, pge - &_pgeLive[0], pge->flags, pge->anim_number);
if (!(pge->flags & 8)) {
if (pge->index != 0 && loadMonsterSprites(pge) == 0) {
return;
@ -980,7 +961,7 @@ void Game::drawObject(const uint8_t *dataPtr, int16_t x, int16_t y, uint8_t flag
}
void Game::drawObjectFrame(const uint8_t *bankDataPtr, const uint8_t *dataPtr, int16_t x, int16_t y, uint8_t flags) {
debug(DBG_GAME, "Game::drawObjectFrame(0x%X, %d, %d, 0x%X)", dataPtr, x, y, flags);
debug(DBG_GAME, "Game::drawObjectFrame(%p, %d, %d, 0x%X)", dataPtr, x, y, flags);
const uint8_t *src = bankDataPtr + dataPtr[0] * 32;
int16_t sprite_y = y + dataPtr[2];
@ -1111,8 +1092,7 @@ void Game::decodeCharacterFrame(const uint8_t *dataPtr, uint8_t *dstPtr) {
}
void Game::drawCharacter(const uint8_t *dataPtr, int16_t pos_x, int16_t pos_y, uint8_t a, uint8_t b, uint8_t flags) {
debug(DBG_GAME, "Game::drawCharacter(0x%X, %d, %d, 0x%X, 0x%X, 0x%X)", dataPtr, pos_x, pos_y, a, b, flags);
debug(DBG_GAME, "Game::drawCharacter(%p, %d, %d, 0x%X, 0x%X, 0x%X)", dataPtr, pos_x, pos_y, a, b, flags);
bool var16 = false; // sprite_mirror_y
if (b & 0x40) {
b &= 0xBF;
@ -1197,7 +1177,7 @@ void Game::drawCharacter(const uint8_t *dataPtr, int16_t pos_x, int16_t pos_y, u
uint32_t dst_offset = 256 * pos_y + pos_x;
uint8_t sprite_col_mask = ((flags & 0x60) == 0x60) ? 0x50 : 0x40;
debug(DBG_GAME, "dst_offset=0x%X src_offset=0x%X", dst_offset, src - dataPtr);
debug(DBG_GAME, "dst_offset=0x%X src_offset=%ld", dst_offset, src - dataPtr);
if (!(flags & 2)) {
if (var16) {
@ -1302,7 +1282,6 @@ void Game::loadLevelData() {
switch (_res._type) {
case kResourceTypeAmiga:
if (_res._isDemo) {
_cut._patchedOffsetsTable = Cutscene::_amigaDemoOffsetsTable;
static const char *fname1 = "demo";
static const char *fname2 = "demof";
_res.load(fname1, Resource::OT_MBK);
@ -1397,6 +1376,17 @@ void Game::loadLevelData() {
pge_loadForCurrentLevel(n);
}
if (_demoBin != -1) {
_cut._id = -1;
if (_demoInputs[_demoBin].room != 255) {
_pgeLive[0].room_location = _demoInputs[_demoBin].room;
_pgeLive[0].pos_x = _demoInputs[_demoBin].x;
_pgeLive[0].pos_y = _demoInputs[_demoBin].y;
} else {
_inp_demPos = 1;
}
}
for (uint16_t i = 0; i < _res._pgeNum; ++i) {
if (_res._pgeInit[i].skill <= _skillLevel) {
LivePGE *pge = &_pgeLive[i];
@ -1466,7 +1456,7 @@ void Game::playSound(uint8_t sfxId, uint8_t softVol) {
uint16_t Game::getRandomNumber() {
uint32_t n = _randSeed * 2;
if (_randSeed > n) {
if (((int32_t)_randSeed) >= 0) {
n ^= 0x1D872B41;
}
_randSeed = n;
@ -1614,44 +1604,17 @@ void Game::handleInventory() {
}
void Game::inp_update() {
if (_inp_replay && _inp_demo) {
uint8_t keymask = _inp_demo->readByte();
if (_inp_demo->ioErr()) {
_inp_replay = false;
} else {
_stub->_pi.dirMask = keymask & 0xF;
_stub->_pi.enter = (keymask & 0x10) != 0;
_stub->_pi.space = (keymask & 0x20) != 0;
_stub->_pi.shift = (keymask & 0x40) != 0;
_stub->_pi.quit = (keymask & 0x80) != 0;
}
}
_stub->processEvents();
if (_inp_record && _inp_demo) {
uint8_t keymask = _stub->_pi.dirMask;
if (_stub->_pi.enter) {
keymask |= 0x10;
}
if (_stub->_pi.space) {
keymask |= 0x20;
}
if (_stub->_pi.shift) {
keymask |= 0x40;
}
if (_stub->_pi.quit) {
keymask |= 0x80;
}
_inp_demo->writeByte(keymask);
if (_inp_demo->ioErr()) {
_inp_record = false;
}
if (_inp_demPos < _res._demLen) {
const int keymask = _res._dem[_inp_demPos++];
_stub->_pi.dirMask = keymask & 0xF;
_stub->_pi.enter = (keymask & 0x10) != 0;
_stub->_pi.space = (keymask & 0x20) != 0;
_stub->_pi.shift = (keymask & 0x40) != 0;
_stub->_pi.backspace = (keymask & 0x80) != 0;
}
}
void Game::makeGameDemoName(char *buf) {
sprintf(buf, "rs-level%d.demo", _currentLevel + 1);
}
void Game::makeGameStateName(uint8_t slot, char *buf) {
sprintf(buf, "rs-level%d-%02d.state", _currentLevel + 1, slot);
}
@ -1856,7 +1819,7 @@ void Game::loadState(File *f) {
}
void AnimBuffers::addState(uint8_t stateNum, int16_t x, int16_t y, const uint8_t *dataPtr, LivePGE *pge, uint8_t w, uint8_t h) {
debug(DBG_GAME, "AnimBuffers::addState() stateNum=%d x=%d y=%d dataPtr=0x%X pge=0x%X", stateNum, x, y, dataPtr, pge);
debug(DBG_GAME, "AnimBuffers::addState() stateNum=%d x=%d y=%d dataPtr=%p pge=%p", stateNum, x, y, dataPtr, pge);
assert(stateNum < 4);
AnimBufferState *state = _states[stateNum];
state->x = x;

9
game.h
View File

@ -32,6 +32,7 @@ struct Game {
CT_LEFT_ROOM = 0xC0
};
static const Demo _demoInputs[3];
static const Level _gameLevels[];
static const uint16_t _scoreTable[];
static const uint8_t _monsterListLevel1[];
@ -63,6 +64,7 @@ struct Game {
const char **_textsTable;
uint8_t _currentLevel;
uint8_t _skillLevel;
int _demoBin;
uint32_t _score;
uint8_t _currentRoom;
uint8_t _currentIcon;
@ -85,7 +87,7 @@ struct Game {
bool _endLoop;
uint32_t _frameTimestamp;
Game(SystemStub *, FileSystem *, const char *savePath, int level, ResourceType ver, Language lang);
Game(SystemStub *, FileSystem *, const char *savePath, int level, int demo, ResourceType ver, Language lang);
void run();
void displayTitleScreenAmiga();
@ -351,9 +353,7 @@ struct Game {
// input
uint8_t _inp_lastKeysHit;
uint8_t _inp_lastKeysHitLeftRight;
bool _inp_replay;
bool _inp_record;
File *_inp_demo;
int _inp_demPos;
void inp_handleSpecialKeys();
void inp_update();
@ -363,7 +363,6 @@ struct Game {
uint8_t _stateSlot;
bool _validSaveState;
void makeGameDemoName(char *buf);
void makeGameStateName(uint8_t slot, char *buf);
bool saveGameState(uint8_t slot);
bool loadGameState(uint8_t slot);

View File

@ -106,6 +106,13 @@ struct Point {
int16_t y;
};
struct Demo {
const char *name;
int level;
int room;
int x, y;
};
struct Level {
const char *name;
const char *name2;

View File

@ -134,6 +134,7 @@ int main(int argc, char *argv[]) {
int scaler = DEFAULT_SCALER;
bool fullscreen = false;
int forcedLanguage = -1;
int demoNum = -1;
if (argc == 2) {
// data path as the only command line argument
struct stat st;
@ -149,6 +150,7 @@ int main(int argc, char *argv[]) {
{ "fullscreen", no_argument, 0, 4 },
{ "scaler", required_argument, 0, 5 },
{ "language", required_argument, 0, 6 },
{ "playdemo", required_argument, 0, 7 },
{ 0, 0, 0, 0 }
};
int index;
@ -195,6 +197,9 @@ int main(int argc, char *argv[]) {
}
}
break;
case 7:
demoNum = atoi(optarg);
break;
default:
printf(USAGE, argv[0]);
return 0;
@ -210,7 +215,7 @@ int main(int argc, char *argv[]) {
}
const Language language = (forcedLanguage == -1) ? detectLanguage(&fs) : (Language)forcedLanguage;
SystemStub *stub = SystemStub_SDL_create();
Game *g = new Game(stub, &fs, savePath, levelNum, (ResourceType)version, language);
Game *g = new Game(stub, &fs, savePath, levelNum, demoNum, (ResourceType)version, language);
stub->init(g_caption, Video::GAMESCREEN_W, Video::GAMESCREEN_H, scaler, fullscreen);
g->run();
delete g;

View File

@ -113,7 +113,7 @@ void Game::pge_loadForCurrentLevel(uint16_t idx) {
}
void Game::pge_process(LivePGE *pge) {
debug(DBG_PGE, "Game::pge_process() pge_num=%d", pge - &_pgeLive[0]);
debug(DBG_PGE, "Game::pge_process() pge_num=%ld", pge - &_pgeLive[0]);
_pge_playAnimSound = true;
_pge_currentPiegeFacingDir = (pge->flags & 1) != 0;
_pge_currentPiegeRoom = pge->room_location;
@ -226,7 +226,7 @@ void Game::pge_playAnimSound(LivePGE *pge, uint16_t arg2) {
}
void Game::pge_setupAnim(LivePGE *pge) {
debug(DBG_PGE, "Game::pge_setupAnim() pgeNum=%d", pge - &_pgeLive[0]);
debug(DBG_PGE, "Game::pge_setupAnim() pgeNum=%ld", pge - &_pgeLive[0]);
const uint8_t *anim_data = _res.getAniData(pge->obj_type);
if (_res._readUint16(anim_data) < pge->anim_seq) {
pge->anim_seq = 0;
@ -254,7 +254,7 @@ void Game::pge_setupAnim(LivePGE *pge) {
}
int Game::pge_execute(LivePGE *live_pge, InitPGE *init_pge, const Object *obj) {
debug(DBG_PGE, "Game::pge_execute() pge_num=%d op1=0x%X op2=0x%X op3=0x%X", live_pge - &_pgeLive[0], obj->opcode1, obj->opcode2, obj->opcode3);
debug(DBG_PGE, "Game::pge_execute() pge_num=%ld op1=0x%X op2=0x%X op3=0x%X", live_pge - &_pgeLive[0], obj->opcode1, obj->opcode2, obj->opcode3);
pge_OpcodeProc op;
ObjectOpcodeArgs args;
if (obj->opcode1) {
@ -378,7 +378,7 @@ void Game::pge_setupDefaultAnim(LivePGE *pge) {
pge->flags |= 8;
}
pge->anim_number = _res._readUint16(anim_frame) & 0x7FFF;
debug(DBG_PGE, "Game::pge_setupDefaultAnim() pgeNum=%d pge->flags=0x%X pge->anim_number=0x%X pge->anim_seq=0x%X", pge - &_pgeLive[0], pge->flags, pge->anim_number, pge->anim_seq);
debug(DBG_PGE, "Game::pge_setupDefaultAnim() pgeNum=%ld pge->flags=0x%X pge->anim_number=0x%X pge->anim_seq=0x%X", pge - &_pgeLive[0], pge->flags, pge->anim_number, pge->anim_seq);
}
}
@ -464,7 +464,7 @@ void Game::pge_setupOtherPieges(LivePGE *pge, InitPGE *init_pge) {
}
void Game::pge_addToCurrentRoomList(LivePGE *pge, uint8_t room) {
debug(DBG_PGE, "Game::pge_addToCurrentRoomList() pgeNum=%d room=%d", pge - &_pgeLive[0], room);
debug(DBG_PGE, "Game::pge_addToCurrentRoomList() pgeNum=%ld room=%d", pge - &_pgeLive[0], room);
if (room != pge->room_location) {
LivePGE *cur_pge = _pge_liveTable1[room];
LivePGE *prev_pge = 0;

View File

@ -84,6 +84,19 @@ void Resource::clearLevelRes() {
free_OBJ();
}
void Resource::load_DEM(const char *filename) {
free(_dem); _dem = 0;
_demLen = 0;
File f;
if (f.open(filename, "rb", _fs)) {
_demLen = f.size();
_dem = (uint8_t *)malloc(_demLen);
if (_dem) {
f.read(_dem, _demLen);
}
}
}
void Resource::load_FIB(const char *fileName) {
debug(DBG_RES, "Resource::load_FIB('%s')", fileName);
static const uint8_t fibonacciTable[] = {

View File

@ -148,6 +148,8 @@ struct Resource {
uint8_t *_bankDataTail;
BankSlot _bankBuffers[NUM_BANK_BUFFERS];
int _bankBuffersCount;
uint8_t *_dem;
int _demLen;
Resource(FileSystem *fs, ResourceType type, Language lang);
~Resource();
@ -159,6 +161,7 @@ struct Resource {
bool isAmiga() const { return _type == kResourceTypeAmiga; }
void clearLevelRes();
void load_DEM(const char *filename);
void load_FIB(const char *fileName);
void load_SPL_demo();
void load_MAP_menu(const char *fileName, uint8_t *dstPtr);

View File

@ -64,7 +64,8 @@ const char *Cutscene::_namesTable[] = {
"INTRO2",
"SERRURE",
"HOLOCUBE",
"CHUTE2"
"CHUTE2",
"LOGOSSSI",
};
const uint16_t Cutscene::_offsetsTable[] = {
@ -92,6 +93,11 @@ const uint8_t Cutscene::_amigaDemoOffsetsTable[] = {
255
};
const uint8_t Cutscene::_ssiOffsetsTable[] = {
64, 34, 0, /* LOGOSSSI */
255
};
const uint16_t Cutscene::_cosTable[] = {
0x0100, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FE, 0x00FE,
0x00FD, 0x00FC, 0x00FC, 0x00FB, 0x00FA, 0x00F9, 0x00F8, 0x00F7,
@ -830,6 +836,12 @@ const Cutscene::Text Cutscene::_frTextsTable[] = {
{ -1, 0 }
};
const Demo Game::_demoInputs[] = {
{ "demo1.bin", 0, 0x33, 0x60, 0x46 },
{ "demo51.bin", 5, 0x00, 0x60, 0xD6 },
{ "demo3.bin" , 2, 0xFF, 0x00, 0x00 }
};
const Level Game::_gameLevels[] = {
{ "level1", "level1", "level1", 0x00, 1, 3 },
{ "level2", "level2", "level2", 0x2F, 1, 4 },

View File

@ -35,9 +35,6 @@ struct PlayerInput {
bool load;
int stateSlot;
bool inpRecord;
bool inpReplay;
bool mirrorMode;
uint8_t dbgMask;

View File

@ -10,6 +10,8 @@
#include "util.h"
static const int kAudioHz = 22050;
static const int kJoystickIndex = 0;
static const int kJoystickCommitValue = 3200;
struct SystemStub_SDL : SystemStub {
@ -17,6 +19,7 @@ struct SystemStub_SDL : SystemStub {
SDL_Window *_window;
SDL_Renderer *_renderer;
SDL_Texture *_texture;
SDL_GameController *_controller;
#else
SDL_Surface *_surface;
#endif
@ -83,15 +86,34 @@ void SystemStub_SDL::init(const char *title, int w, int h, int scaler, bool full
memset(_pal, 0, sizeof(_pal));
_screenW = _screenH = 0;
setScreenSize(w, h);
_joystick = NULL;
_joystick = 0;
#if SDL_VERSION_ATLEAST(2, 0, 0)
_controller = 0;
if (SDL_NumJoysticks() > 0) {
_joystick = SDL_JoystickOpen(0);
SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt");
if (SDL_IsGameController(kJoystickIndex)) {
_controller = SDL_GameControllerOpen(kJoystickIndex);
}
if (!_controller) {
_joystick = SDL_JoystickOpen(kJoystickIndex);
}
}
#else
if (SDL_NumJoysticks() > 0) {
_joystick = SDL_JoystickOpen(kJoystickIndex);
}
#endif
_screenshot = 1;
}
void SystemStub_SDL::destroy() {
cleanupGraphics();
#if SDL_VERSION_ATLEAST(2, 0, 0)
if (_controller) {
SDL_GameControllerClose(_controller);
_controller = 0;
}
#endif
if (_joystick) {
SDL_JoystickClose(_joystick);
_joystick = 0;
@ -141,7 +163,7 @@ void SystemStub_SDL::setOverscanColor(int i) {
}
void SystemStub_SDL::copyRect(int x, int y, int w, int h, const uint8_t *buf, int pitch) {
if (_numBlitRects >= ARRAYSIZE(_blitRects)) {
if (_numBlitRects >= (int)ARRAYSIZE(_blitRects)) {
warning("SystemStub_SDL::copyRect() Too many blit rects, you may experience graphical glitches");
} else {
// extend the dirty region by 1 pixel for scalers accessing 'outer' pixels
@ -201,13 +223,16 @@ void SystemStub_SDL::copyRect(int x, int y, int w, int h, const uint8_t *buf, in
}
void SystemStub_SDL::fadeScreen() {
const int fadeScreenBufferSize = _screenH * _screenW * sizeof(uint16_t);
const int bufferSize = _screenH * _screenW * sizeof(uint16_t);
if (!_fadeScreenBuffer) {
_fadeScreenBuffer = (uint16_t *)malloc(fadeScreenBufferSize);
assert(_fadeScreenBuffer);
_fadeScreenBuffer = (uint16_t *)malloc(bufferSize);
if (!_fadeScreenBuffer) {
warning("SystemStub_SDL::fadeScreen() Unable to allocate buffer size %d", bufferSize);
return;
}
}
_fadeOnUpdateScreen = true;
memcpy(_fadeScreenBuffer, _screenBuffer + _screenW + 1, fadeScreenBufferSize);
memcpy(_fadeScreenBuffer, _screenBuffer + _screenW + 1, bufferSize);
}
static uint16_t blendPixel16(uint16_t colorSrc, uint16_t colorDst, uint32_t mask, int step) {
@ -219,9 +244,23 @@ static uint16_t blendPixel16(uint16_t colorSrc, uint16_t colorDst, uint32_t mask
void SystemStub_SDL::updateScreen(int shakeOffset) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
// _fadeOnUpdateScreen
SDL_UpdateTexture(_texture, 0, _screenBuffer + _screenW + 1, _screenW * sizeof(uint16_t));
SDL_RenderClear(_renderer);
if (_fadeOnUpdateScreen) {
SDL_SetRenderDrawBlendMode(_renderer, SDL_BLENDMODE_BLEND);
SDL_Rect r;
r.x = r.y = 0;
SDL_GetRendererOutputSize(_renderer, &r.w, &r.h);
for (int i = 1; i <= 16; ++i) {
SDL_SetRenderDrawColor(_renderer, 0, 0, 0, 256 - i * 16);
SDL_RenderCopy(_renderer, _texture, 0, 0);
SDL_RenderFillRect(_renderer, &r);
SDL_RenderPresent(_renderer);
SDL_Delay(30);
}
_fadeOnUpdateScreen = false;
return;
}
if (shakeOffset != 0) {
SDL_Rect r;
r.x = 0;
@ -375,41 +414,111 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
}
break;
case SDL_JOYBUTTONDOWN:
if (_joystick) {
switch (ev.jbutton.button) {
case 0:
_pi.space = true;
break;
case 1:
_pi.shift = true;
break;
case 2:
_pi.enter = true;
break;
case 3:
_pi.backspace = true;
break;
}
}
break;
case SDL_JOYBUTTONUP:
if (_joystick) {
const bool pressed = (ev.jbutton.state == SDL_PRESSED);
switch (ev.jbutton.button) {
case 0:
_pi.space = false;
_pi.space = pressed;
break;
case 1:
_pi.shift = false;
_pi.shift = pressed;
break;
case 2:
_pi.enter = false;
_pi.enter = pressed;
break;
case 3:
_pi.backspace = false;
_pi.backspace = pressed;
break;
}
}
break;
#if SDL_VERSION_ATLEAST(2, 0, 0)
case SDL_CONTROLLERAXISMOTION:
if (_controller) {
switch (ev.caxis.axis) {
case SDL_CONTROLLER_AXIS_LEFTX:
case SDL_CONTROLLER_AXIS_RIGHTX:
if (ev.caxis.value < -kJoystickCommitValue) {
_pi.dirMask |= PlayerInput::DIR_LEFT;
} else {
_pi.dirMask &= ~PlayerInput::DIR_LEFT;
}
if (ev.caxis.value > kJoystickCommitValue) {
_pi.dirMask |= PlayerInput::DIR_RIGHT;
} else {
_pi.dirMask &= ~PlayerInput::DIR_RIGHT;
}
break;
case SDL_CONTROLLER_AXIS_LEFTY:
case SDL_CONTROLLER_AXIS_RIGHTY:
if (ev.caxis.value < -kJoystickCommitValue) {
_pi.dirMask |= PlayerInput::DIR_UP;
} else {
_pi.dirMask &= ~PlayerInput::DIR_UP;
}
if (ev.caxis.value > kJoystickCommitValue) {
_pi.dirMask |= PlayerInput::DIR_DOWN;
} else {
_pi.dirMask &= ~PlayerInput::DIR_DOWN;
}
break;
}
}
break;
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
if (_controller) {
const bool pressed = (ev.cbutton.state == SDL_PRESSED);
switch (ev.cbutton.button) {
case SDL_CONTROLLER_BUTTON_A:
_pi.enter = pressed;
break;
case SDL_CONTROLLER_BUTTON_B:
_pi.space = pressed;
break;
case SDL_CONTROLLER_BUTTON_X:
_pi.shift = pressed;
break;
case SDL_CONTROLLER_BUTTON_Y:
_pi.backspace = pressed;
break;
case SDL_CONTROLLER_BUTTON_BACK:
case SDL_CONTROLLER_BUTTON_START:
_pi.escape = pressed;
break;
case SDL_CONTROLLER_BUTTON_DPAD_UP:
if (pressed) {
_pi.dirMask |= PlayerInput::DIR_UP;
} else {
_pi.dirMask &= ~PlayerInput::DIR_UP;
}
break;
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
if (pressed) {
_pi.dirMask |= PlayerInput::DIR_DOWN;
} else {
_pi.dirMask &= ~PlayerInput::DIR_DOWN;
}
break;
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
if (pressed) {
_pi.dirMask |= PlayerInput::DIR_LEFT;
} else {
_pi.dirMask &= ~PlayerInput::DIR_LEFT;
}
break;
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
if (pressed) {
_pi.dirMask |= PlayerInput::DIR_RIGHT;
} else {
_pi.dirMask &= ~PlayerInput::DIR_RIGHT;
}
break;
}
}
break;
#endif
case SDL_KEYUP:
switch (ev.key.keysym.sym) {
case SDLK_LEFT:
@ -484,10 +593,6 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
_pi.stateSlot = 1;
} else if (ev.key.keysym.sym == SDLK_KP_MINUS || ev.key.keysym.sym == SDLK_PAGEDOWN) {
_pi.stateSlot = -1;
} else if (ev.key.keysym.sym == SDLK_r) {
_pi.inpRecord = true;
} else if (ev.key.keysym.sym == SDLK_p) {
_pi.inpReplay = true;
}
}
_pi.lastChar = ev.key.keysym.sym;

6
util.h
View File

@ -27,8 +27,8 @@ enum {
extern uint16_t g_debugMask;
extern void debug(uint16_t cm, const char *msg, ...);
extern void error(const char *msg, ...);
extern void warning(const char *msg, ...);
extern void debug(uint16_t cm, const char *msg, ...); // __attribute__((__format__(__printf__, 2, 3)))
extern void error(const char *msg, ...); // __attribute__((__format__(__printf__, 1, 2)))
extern void warning(const char *msg, ...); // __attribute__((__format__(__printf__, 1, 2)))
#endif // UTIL_H__