Import 0.4.3

This commit is contained in:
Gregory Montoir 2018-03-29 00:00:00 +08:00
parent a4c4ed8fef
commit 514785d0a1
21 changed files with 390 additions and 123 deletions

View File

@ -7,15 +7,17 @@ MODPLUG_LIBS := -lmodplug
TREMOR_LIBS := -lvorbisidec -logg TREMOR_LIBS := -lvorbisidec -logg
ZLIB_LIBS := -lz ZLIB_LIBS := -lz
CXXFLAGS += -O2 -Wall -MMD $(SDL_CFLAGS) -DUSE_MODPLUG -DUSE_TREMOR -DUSE_ZLIB CXXFLAGS += -O2 -Wall -MMD $(SDL_CFLAGS) -DUSE_MODPLUG -DUSE_STATIC_SCALER -DUSE_TREMOR -DUSE_ZLIB
SRCS = collision.cpp cutscene.cpp decode_mac.cpp dynlib.cpp file.cpp fs.cpp game.cpp graphics.cpp main.cpp \ SRCS = collision.cpp cutscene.cpp decode_mac.cpp dynlib.cpp file.cpp fs.cpp game.cpp graphics.cpp main.cpp \
menu.cpp mixer.cpp mod_player.cpp ogg_player.cpp piege.cpp resource.cpp resource_aba.cpp \ menu.cpp mixer.cpp mod_player.cpp ogg_player.cpp piege.cpp resource.cpp resource_aba.cpp \
resource_mac.cpp scaler.cpp screenshot.cpp seq_player.cpp \ resource_mac.cpp scaler.cpp screenshot.cpp seq_player.cpp \
sfx_player.cpp staticres.cpp systemstub_sdl.cpp unpack.cpp util.cpp video.cpp sfx_player.cpp staticres.cpp systemstub_sdl.cpp unpack.cpp util.cpp video.cpp
OBJS = $(SRCS:.cpp=.o) SCALERS := scalers/scaler_nearest.cpp scalers/scaler_tv2x.cpp scalers/scaler_xbrz.cpp scalers/xbrz/xbrz.cpp
DEPS = $(SRCS:.cpp=.d)
OBJS = $(SRCS:.cpp=.o) $(SCALERS:.cpp=.o)
DEPS = $(SRCS:.cpp=.d) $(SCALERS:.cpp=.d)
LIBS = $(SDL_LIBS) $(DL_LIBS) $(MODPLUG_LIBS) $(TREMOR_LIBS) $(ZLIB_LIBS) LIBS = $(SDL_LIBS) $(DL_LIBS) $(MODPLUG_LIBS) $(TREMOR_LIBS) $(ZLIB_LIBS)

View File

@ -1,6 +1,6 @@
REminiscence README REminiscence README
Release version: 0.4.2 Release version: 0.4.3
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -43,7 +43,7 @@ These paths can be changed using command line switches :
--savepath=PATH Path to save files (default '.') --savepath=PATH Path to save files (default '.')
--levelnum=NUM Level to start from (default '0') --levelnum=NUM Level to start from (default '0')
--fullscreen Fullscreen display --fullscreen Fullscreen display
--widescreen 16:9 display --widescreen=MODE 16:9 display
--scaler=NAME@X Graphics scaler (default 'scale@3') --scaler=NAME@X Graphics scaler (default 'scale@3')
--language=LANG Language (fr,en,de,sp,it,jp) --language=LANG Language (fr,en,de,sp,it,jp)
@ -52,6 +52,10 @@ addition to a scaling factor. External scalers are also supported, the suffix
shall be used as the name. Eg. If you have scaler_xbrz.dll, you can pass shall be used as the name. Eg. If you have scaler_xbrz.dll, you can pass
'--scaler xbrz@2' to use that algorithm with a doubled window size (512x448). '--scaler xbrz@2' to use that algorithm with a doubled window size (512x448).
The widescreen option accepts two modes :
'adjacent' : left and right rooms bitmaps will be drawn (default)
'mirror' : the current room bitmap will be drawn mirrored
In-game hotkeys : In-game hotkeys :
Arrow Keys move Conrad Arrow Keys move Conrad
@ -60,11 +64,12 @@ In-game hotkeys :
Escape display the options Escape display the options
Backspace display the inventory Backspace display the inventory
Alt Enter toggle windowed/fullscreen mode Alt Enter toggle windowed/fullscreen mode
Alt + and - change video scaler Alt + and - increase or decrease game screen scaler factor
Alt S write screenshot as .tga Alt S write screenshot as .tga
Ctrl S save game state Ctrl S save game state
Ctrl L load game state Ctrl L load game state
Ctrl + and - change game state slot Ctrl + and - change game state slot
Function Keys change game screen scaler
Debug hotkeys : Debug hotkeys :

View File

@ -938,7 +938,12 @@ void Cutscene::op_handleKeys() {
_cmdPtr = getCommandData(); _cmdPtr = getCommandData();
n = READ_BE_UINT16(_cmdPtr + n * 2 + 2); n = READ_BE_UINT16(_cmdPtr + n * 2 + 2);
} }
_cmdPtr = _cmdPtrBak = getCommandData() + n + _startOffset; if (_res->isMac()) {
_cmdPtr = getCommandData();
_baseOffset = READ_BE_UINT16(_cmdPtr + 2 + n * 2);
n = 0;
}
_cmdPtr = _cmdPtrBak = getCommandData() + n + _baseOffset;
} }
uint8_t Cutscene::fetchNextCmdByte() { uint8_t Cutscene::fetchNextCmdByte() {
@ -951,7 +956,7 @@ uint16_t Cutscene::fetchNextCmdWord() {
return i; return i;
} }
void Cutscene::mainLoop(uint16_t offset) { void Cutscene::mainLoop(uint16_t num) {
_frameDelay = 5; _frameDelay = 5;
_tstamp = _stub->getTimeStamp(); _tstamp = _stub->getTimeStamp();
@ -963,14 +968,20 @@ void Cutscene::mainLoop(uint16_t offset) {
_newPal = false; _newPal = false;
_hasAlphaColor = false; _hasAlphaColor = false;
const uint8_t *p = getCommandData(); const uint8_t *p = getCommandData();
if (offset != 0) { int offset = 0;
offset = READ_BE_UINT16(p + (offset + 1) * 2); if (_res->isMac()) {
// const int count = READ_BE_UINT16(p);
_baseOffset = READ_BE_UINT16(p + 2 + num * 2);
} else {
if (num != 0) {
offset = READ_BE_UINT16(p + 2 + num * 2);
}
_baseOffset = (READ_BE_UINT16(p) + 1) * 2;
} }
_startOffset = (READ_BE_UINT16(p) + 1) * 2;
_varKey = 0; _varKey = 0;
_cmdPtr = _cmdPtrBak = p + _startOffset + offset; _cmdPtr = _cmdPtrBak = p + _baseOffset + offset;
_polPtr = getPolygonData(); _polPtr = getPolygonData();
debug(DBG_CUT, "_startOffset = %d offset = %d", _startOffset, offset); debug(DBG_CUT, "_baseOffset = %d offset = %d", _baseOffset, offset);
while (!_stub->_pi.quit && !_interrupted && !_stop) { while (!_stub->_pi.quit && !_interrupted && !_stop) {
uint8_t op = fetchNextCmdByte(); uint8_t op = fetchNextCmdByte();

View File

@ -71,7 +71,7 @@ struct Cutscene {
uint8_t _frameDelay; uint8_t _frameDelay;
bool _newPal; bool _newPal;
uint8_t _palBuf[0x20 * 2]; uint8_t _palBuf[0x20 * 2];
uint16_t _startOffset; uint16_t _baseOffset;
bool _creditsSequence; bool _creditsSequence;
uint32_t _rotMat[4]; uint32_t _rotMat[4];
uint8_t _primitiveColor; uint8_t _primitiveColor;
@ -139,7 +139,7 @@ struct Cutscene {
uint8_t fetchNextCmdByte(); uint8_t fetchNextCmdByte();
uint16_t fetchNextCmdWord(); uint16_t fetchNextCmdWord();
void mainLoop(uint16_t offset); void mainLoop(uint16_t num);
bool load(uint16_t cutName); bool load(uint16_t cutName);
void unload(); void unload();
void prepare(); void prepare();

102
game.cpp
View File

@ -14,7 +14,7 @@
#include "unpack.h" #include "unpack.h"
#include "util.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, ResourceType ver, Language lang, WidescreenMode widescreenMode)
: _cut(&_res, stub, &_vid), _menu(&_res, stub, &_vid), : _cut(&_res, stub, &_vid), _menu(&_res, stub, &_vid),
_mix(fs, stub), _res(fs, ver, lang), _seq(stub, &_mix), _vid(&_res, stub), _mix(fs, stub), _res(fs, ver, lang), _seq(stub, &_mix), _vid(&_res, stub),
_stub(stub), _fs(fs), _savePath(savePath) { _stub(stub), _fs(fs), _savePath(savePath) {
@ -23,6 +23,7 @@ Game::Game(SystemStub *stub, FileSystem *fs, const char *savePath, int level, Re
_skillLevel = _menu._skill = kSkillNormal; _skillLevel = _menu._skill = kSkillNormal;
_currentLevel = _menu._level = level; _currentLevel = _menu._level = level;
_demoBin = -1; _demoBin = -1;
_widescreenMode = widescreenMode;
} }
void Game::run() { void Game::run() {
@ -63,6 +64,12 @@ void Game::run() {
_mix.init(); _mix.init();
_mix._mod._isAmiga = _res.isAmiga(); _mix._mod._isAmiga = _res.isAmiga();
if (_res.isMac()) {
displayTitleScreenMac(Menu::kMacTitleScreen_MacPlay);
if (!_stub->_pi.quit) {
displayTitleScreenMac(Menu::kMacTitleScreen_Presage);
}
}
playCutscene(0x40); playCutscene(0x40);
playCutscene(0x0D); playCutscene(0x0D);
@ -86,7 +93,7 @@ void Game::run() {
break; break;
} }
bool presentMenu = (_res._type == kResourceTypeAmiga) || (_res._type == kResourceTypeDOS && _res.fileExists("MENU1.MAP")); bool presentMenu = ((_res._type != kResourceTypeDOS) || _res.fileExists("MENU1.MAP"));
while (!_stub->_pi.quit) { while (!_stub->_pi.quit) {
if (presentMenu) { if (presentMenu) {
_mix.playMusic(1); _mix.playMusic(1);
@ -121,7 +128,7 @@ void Game::run() {
_stub->setScreenSize(Video::GAMESCREEN_W, Video::GAMESCREEN_H); _stub->setScreenSize(Video::GAMESCREEN_W, Video::GAMESCREEN_H);
break; break;
case kResourceTypeMac: case kResourceTypeMac:
// TODO: displayTitleScreenMac(Menu::kMacTitleScreen_Flashback);
break; break;
} }
if (_stub->_pi.quit) { if (_stub->_pi.quit) {
@ -172,10 +179,10 @@ void Game::run() {
void Game::displayTitleScreenAmiga() { void Game::displayTitleScreenAmiga() {
static const char *FILENAME = "present.cmp"; static const char *FILENAME = "present.cmp";
_res.load_CMP_menu(FILENAME, _res._scratchBuffer); _res.load_CMP_menu(FILENAME);
static const int kW = 320; static const int kW = 320;
static const int kH = 224; static const int kH = 224;
uint8_t *buf = (uint8_t *)calloc(kW * kH, 1); uint8_t *buf = (uint8_t *)calloc(1, kW * kH);
if (!buf) { if (!buf) {
error("Failed to allocate screen buffer w=%d h=%d", kW, kH); error("Failed to allocate screen buffer w=%d h=%d", kW, kH);
} }
@ -190,13 +197,13 @@ void Game::displayTitleScreenAmiga() {
_stub->setPaletteEntry(i, &c); _stub->setPaletteEntry(i, &c);
} }
_stub->setScreenSize(kW, kH); _stub->setScreenSize(kW, kH);
// fill with black
_stub->copyRect(0, 0, kW, kH, buf, kW); _stub->copyRect(0, 0, kW, kH, buf, kW);
_stub->updateScreen(0); _stub->updateScreen(0);
_vid.AMIGA_decodeCmp(_res._scratchBuffer + 6, buf); _vid.AMIGA_decodeCmp(_res._scratchBuffer + 6, buf);
free(buf);
int h = 0; int h = 0;
while (1) { while (1) {
if (h < kH / 2) { if (h <= kH / 2) {
const int y = kH / 2 - h; const int y = kH / 2 - h;
_stub->copyRect(0, y, kW, h * 2, buf, kW); _stub->copyRect(0, y, kW, h * 2, buf, kW);
_stub->updateScreen(0); _stub->updateScreen(0);
@ -212,6 +219,72 @@ void Game::displayTitleScreenAmiga() {
} }
_stub->sleep(30); _stub->sleep(30);
} }
free(buf);
}
void Game::displayTitleScreenMac(int num) {
const int w = 512;
int h = 384;
int clutBaseColor = 0;
switch (num) {
case Menu::kMacTitleScreen_MacPlay:
break;
case Menu::kMacTitleScreen_Presage:
clutBaseColor = 12;
break;
case Menu::kMacTitleScreen_Flashback:
case Menu::kMacTitleScreen_LeftEye:
case Menu::kMacTitleScreen_RightEye:
h = 448;
break;
case Menu::kMacTitleScreen_Controls:
break;
}
DecodeBuffer buf;
memset(&buf, 0, sizeof(buf));
buf.ptr = _vid._frontLayer;
buf.pitch = buf.w = _vid._w;
buf.h = _vid._h;
buf.x = (_vid._w - w) / 2;
buf.y = (_vid._h - h) / 2;
buf.setPixel = Video::MAC_drawBuffer;
memset(_vid._frontLayer, 0, _vid._layerSize);
_res.MAC_loadTitleImage(num, &buf);
for (int i = 0; i < 12; ++i) {
Color palette[16];
_res.MAC_copyClut16(palette, 0, clutBaseColor + i);
const int basePaletteColor = i * 16;
for (int j = 0; j < 16; ++j) {
_stub->setPaletteEntry(basePaletteColor + j, &palette[j]);
}
}
if (num == Menu::kMacTitleScreen_MacPlay) {
Color palette[16];
_res.MAC_copyClut16(palette, 0, 56);
for (int i = 12; i < 16; ++i) {
const int basePaletteColor = i * 16;
for (int j = 0; j < 16; ++j) {
_stub->setPaletteEntry(basePaletteColor + j, &palette[j]);
}
}
} else if (num == Menu::kMacTitleScreen_Presage) {
Color c;
c.r = c.g = c.b = 0;
_stub->setPaletteEntry(0, &c);
}
_stub->copyRect(0, 0, _vid._w, _vid._h, _vid._frontLayer, _vid._w);
_stub->updateScreen(0);
while (1) {
_stub->processEvents();
if (_stub->_pi.quit) {
break;
}
if (_stub->_pi.enter) {
_stub->_pi.enter = false;
break;
}
_stub->sleep(30);
}
} }
void Game::resetGameState() { void Game::resetGameState() {
@ -496,8 +569,12 @@ bool Game::handleConfigPanel() {
switch (_res._type) { switch (_res._type) {
case kResourceTypeAmiga: case kResourceTypeAmiga:
// TODO for (int i = 0; i < h; ++i) {
return true; for (int j = 0; j < w; ++j) {
_vid.fillRect(Video::CHAR_W * (x + j), Video::CHAR_H * (y + i), Video::CHAR_W, Video::CHAR_H, 0xE2);
}
}
break;
case kResourceTypeDOS: case kResourceTypeDOS:
// top-left rounded corner // top-left rounded corner
_vid.PC_drawChar(0x81, y, x, kUseDefaultFont); _vid.PC_drawChar(0x81, y, x, kUseDefaultFont);
@ -543,7 +620,7 @@ bool Game::handleConfigPanel() {
_vid.MAC_drawStringChar(_vid._frontLayer, _vid._w, Video::CHAR_W * x, Video::CHAR_H * (y + i), _res._fnt, _vid._charFrontColor, 0x86); _vid.MAC_drawStringChar(_vid._frontLayer, _vid._w, Video::CHAR_W * x, Video::CHAR_H * (y + i), _res._fnt, _vid._charFrontColor, 0x86);
_vid.MAC_drawStringChar(_vid._frontLayer, _vid._w, Video::CHAR_W * (x + w), Video::CHAR_H * (y + i), _res._fnt, _vid._charFrontColor, 0x87); _vid.MAC_drawStringChar(_vid._frontLayer, _vid._w, Video::CHAR_W * (x + w), Video::CHAR_H * (y + i), _res._fnt, _vid._charFrontColor, 0x87);
for (int j = 1; j < w; ++j) { for (int j = 1; j < w; ++j) {
_vid.MAC_fillRect(Video::CHAR_W * (x + j), Video::CHAR_H * (y + i), Video::CHAR_W, Video::CHAR_H, 0xE2); _vid.fillRect(Video::CHAR_W * (x + j), Video::CHAR_H * (y + i), Video::CHAR_W, Video::CHAR_H, 0xE2);
} }
} }
break; break;
@ -1523,7 +1600,7 @@ void Game::loadLevelMap() {
_vid.AMIGA_decodeLev(_currentLevel, _currentRoom); _vid.AMIGA_decodeLev(_currentLevel, _currentRoom);
break; break;
case kResourceTypeDOS: case kResourceTypeDOS:
if (_stub->hasWidescreen()) { // draw adjacent rooms if (_stub->hasWidescreen() && _widescreenMode == kWidescreenAdjacentRooms) {
const int leftRoom = _res._ctData[CT_LEFT_ROOM + _currentRoom]; const int leftRoom = _res._ctData[CT_LEFT_ROOM + _currentRoom];
if (leftRoom > 0 && hasLevelMap(_currentLevel, leftRoom)) { if (leftRoom > 0 && hasLevelMap(_currentLevel, leftRoom)) {
_vid.PC_decodeMap(_currentLevel, leftRoom); _vid.PC_decodeMap(_currentLevel, leftRoom);
@ -1540,6 +1617,9 @@ void Game::loadLevelMap() {
} }
} }
_vid.PC_decodeMap(_currentLevel, _currentRoom); _vid.PC_decodeMap(_currentLevel, _currentRoom);
if (_stub->hasWidescreen() && _widescreenMode == kWidescreenMirrorRoom) {
_stub->copyRectMirrorBorders(Video::GAMESCREEN_W, Video::GAMESCREEN_H, _vid._backLayer);
}
break; break;
case kResourceTypeMac: case kResourceTypeMac:
_vid.MAC_decodeMap(_currentLevel, _currentRoom); _vid.MAC_decodeMap(_currentLevel, _currentRoom);

4
game.h
View File

@ -86,11 +86,13 @@ struct Game {
bool _saveStateCompleted; bool _saveStateCompleted;
bool _endLoop; bool _endLoop;
uint32_t _frameTimestamp; uint32_t _frameTimestamp;
WidescreenMode _widescreenMode;
Game(SystemStub *, FileSystem *, const char *savePath, int level, ResourceType ver, Language lang); Game(SystemStub *, FileSystem *, const char *savePath, int level, ResourceType ver, Language lang, WidescreenMode widescreenMode);
void run(); void run();
void displayTitleScreenAmiga(); void displayTitleScreenAmiga();
void displayTitleScreenMac(int num);
void resetGameState(); void resetGameState();
void mainLoop(); void mainLoop();
void updateTiming(); void updateTiming();

View File

@ -100,6 +100,12 @@ enum Skill {
kSkillExpert, kSkillExpert,
}; };
enum WidescreenMode {
kWidescreenNone,
kWidescreenAdjacentRooms,
kWidescreenMirrorRoom,
};
struct Options { struct Options {
bool bypass_protection; bool bypass_protection;
bool enable_password_menu; bool enable_password_menu;

View File

@ -22,7 +22,7 @@ static const char *USAGE =
" --savepath=PATH Path to save files (default '.')\n" " --savepath=PATH Path to save files (default '.')\n"
" --levelnum=NUM Start to level, bypass introduction\n" " --levelnum=NUM Start to level, bypass introduction\n"
" --fullscreen Fullscreen display\n" " --fullscreen Fullscreen display\n"
" --widescreen 16:9 display\n" " --widescreen=MODE 16:9 display\n"
" --scaler=NAME@X Graphics scaler (default 'scale@3')\n" " --scaler=NAME@X Graphics scaler (default 'scale@3')\n"
" --language=LANG Language (fr,en,de,sp,it,jp)\n" " --language=LANG Language (fr,en,de,sp,it,jp)\n"
; ;
@ -74,6 +74,7 @@ static Language detectLanguage(FileSystem *fs) {
return table[i].language; return table[i].language;
} }
} }
warning("Unable to detect language, defaults to English");
return LANG_EN; return LANG_EN;
} }
@ -126,12 +127,17 @@ static void initOptions() {
} }
if (*p) { if (*p) {
const bool value = (*p == 't' || *p == 'T' || *p == '1'); const bool value = (*p == 't' || *p == 'T' || *p == '1');
bool foundOption = false;
for (int i = 0; opts[i].name; ++i) { for (int i = 0; opts[i].name; ++i) {
if (strncmp(buf, opts[i].name, strlen(opts[i].name)) == 0) { if (strncmp(buf, opts[i].name, strlen(opts[i].name)) == 0) {
*opts[i].value = value; *opts[i].value = value;
foundOption = true;
break; break;
} }
} }
if (!foundOption) {
warning("Unhandled option '%s', ignoring", buf);
}
} }
} }
} }
@ -143,10 +149,16 @@ static void parseScaler(char *name, ScalerParameters *scalerParameters) {
struct { struct {
const char *name; const char *name;
int type; int type;
const Scaler *scaler;
} scalers[] = { } scalers[] = {
{ "point", kScalerTypePoint }, { "point", kScalerTypePoint, 0 },
{ "linear", kScalerTypeLinear }, { "linear", kScalerTypeLinear, 0 },
{ "scale", kScalerTypeInternal }, { "scale", kScalerTypeInternal, &_internalScaler },
#ifdef USE_STATIC_SCALER
{ "nearest", kScalerTypeInternal, &scaler_nearest },
{ "tv2x", kScalerTypeInternal, &scaler_tv2x },
{ "xbrz", kScalerTypeInternal, &scaler_xbrz },
#endif
{ 0, -1 } { 0, -1 }
}; };
bool found = false; bool found = false;
@ -157,6 +169,7 @@ static void parseScaler(char *name, ScalerParameters *scalerParameters) {
for (int i = 0; scalers[i].name; ++i) { for (int i = 0; scalers[i].name; ++i) {
if (strcmp(scalers[i].name, name) == 0) { if (strcmp(scalers[i].name, name) == 0) {
scalerParameters->type = (ScalerType)scalers[i].type; scalerParameters->type = (ScalerType)scalers[i].type;
scalerParameters->scaler = scalers[i].scaler;
found = true; found = true;
break; break;
} }
@ -179,12 +192,30 @@ static void parseScaler(char *name, ScalerParameters *scalerParameters) {
} }
} }
static WidescreenMode parseWidescreen(const char *mode) {
static const struct {
const char *name;
WidescreenMode mode;
} modes[] = {
{ "adjacent", kWidescreenAdjacentRooms },
{ "mirror", kWidescreenMirrorRoom },
{ 0, kWidescreenNone },
};
for (int i = 0; modes[i].name; ++i) {
if (strcasecmp(modes[i].name, mode) == 0) {
return modes[i].mode;
}
}
warning("Unhandled widecreen mode '%s', defaults to adjacent rooms", mode);
return kWidescreenAdjacentRooms; // default value
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
const char *dataPath = "DATA"; const char *dataPath = "DATA";
const char *savePath = "."; const char *savePath = ".";
int levelNum = 0; int levelNum = 0;
bool fullscreen = false; bool fullscreen = false;
bool widescreen = false; WidescreenMode widescreen = kWidescreenNone;
ScalerParameters scalerParameters = ScalerParameters::defaults(); ScalerParameters scalerParameters = ScalerParameters::defaults();
int forcedLanguage = -1; int forcedLanguage = -1;
if (argc == 2) { if (argc == 2) {
@ -202,7 +233,7 @@ int main(int argc, char *argv[]) {
{ "fullscreen", no_argument, 0, 4 }, { "fullscreen", no_argument, 0, 4 },
{ "scaler", required_argument, 0, 5 }, { "scaler", required_argument, 0, 5 },
{ "language", required_argument, 0, 6 }, { "language", required_argument, 0, 6 },
{ "widescreen", no_argument, 0, 7 }, { "widescreen", required_argument, 0, 7 },
{ 0, 0, 0, 0 } { 0, 0, 0, 0 }
}; };
int index; int index;
@ -248,7 +279,7 @@ int main(int argc, char *argv[]) {
} }
break; break;
case 7: case 7:
widescreen = true; widescreen = parseWidescreen(optarg);
break; break;
default: default:
printf(USAGE, argv[0]); printf(USAGE, argv[0]);
@ -265,8 +296,8 @@ int main(int argc, char *argv[]) {
} }
const Language language = (forcedLanguage == -1) ? detectLanguage(&fs) : (Language)forcedLanguage; const Language language = (forcedLanguage == -1) ? detectLanguage(&fs) : (Language)forcedLanguage;
SystemStub *stub = SystemStub_SDL_create(); SystemStub *stub = SystemStub_SDL_create();
Game *g = new Game(stub, &fs, savePath, levelNum, (ResourceType)version, language); Game *g = new Game(stub, &fs, savePath, levelNum, (ResourceType)version, language, widescreen);
stub->init(g_caption, g->_vid._w, g->_vid._h, fullscreen, widescreen, &scalerParameters); stub->init(g_caption, g->_vid._w, g->_vid._h, fullscreen, widescreen != kWidescreenNone, &scalerParameters);
g->run(); g->run();
delete g; delete g;
stub->destroy(); stub->destroy();

View File

@ -68,6 +68,11 @@ void Menu::drawString2(const char *str, int16_t y, int16_t x) {
int h = Video::CHAR_H; int h = Video::CHAR_H;
int len = 0; int len = 0;
switch (_res->_type) { switch (_res->_type) {
case kResourceTypeAmiga:
for (; str[len]; ++len) {
_vid->AMIGA_drawStringChar(_vid->_frontLayer, _vid->_w, Video::CHAR_W * (x + len), Video::CHAR_H * y, _res->_fnt, _vid->_charFrontColor, (uint8_t)str[len]);
}
break;
case kResourceTypeDOS: case kResourceTypeDOS:
for (; str[len]; ++len) { for (; str[len]; ++len) {
_vid->PC_drawChar((uint8_t)str[len], y, x + len, true); _vid->PC_drawChar((uint8_t)str[len], y, x + len, true);
@ -77,8 +82,6 @@ void Menu::drawString2(const char *str, int16_t y, int16_t x) {
for (; str[len]; ++len) { for (; str[len]; ++len) {
_vid->MAC_drawStringChar(_vid->_frontLayer, _vid->_w, Video::CHAR_W * (x + len), Video::CHAR_H * y, _res->_fnt, _vid->_charFrontColor, (uint8_t)str[len]); _vid->MAC_drawStringChar(_vid->_frontLayer, _vid->_w, Video::CHAR_W * (x + len), Video::CHAR_H * y, _res->_fnt, _vid->_charFrontColor, (uint8_t)str[len]);
} }
w *= _vid->_layerScale;
h *= _vid->_layerScale;
break; break;
} }
_vid->markBlockAsDirty(x * w, y * h, len * w, h); _vid->markBlockAsDirty(x * w, y * h, len * w, h);

8
menu.h
View File

@ -30,6 +30,14 @@ struct Menu {
SCREEN_LEVEL, SCREEN_LEVEL,
SCREEN_INFO SCREEN_INFO
}; };
enum {
kMacTitleScreen_MacPlay = 1,
kMacTitleScreen_Presage = 2,
kMacTitleScreen_Flashback = 3,
kMacTitleScreen_LeftEye = 4,
kMacTitleScreen_RightEye = 5,
kMacTitleScreen_Controls = 6
};
enum { enum {
EVENTS_DELAY = 80 EVENTS_DELAY = 80

View File

@ -21,7 +21,7 @@ Resource::Resource(FileSystem *fs, ResourceType ver, Language lang) {
_mac = 0; _mac = 0;
_readUint16 = (_type == kResourceTypeDOS) ? READ_LE_UINT16 : READ_BE_UINT16; _readUint16 = (_type == kResourceTypeDOS) ? READ_LE_UINT16 : READ_BE_UINT16;
_readUint32 = (_type == kResourceTypeDOS) ? READ_LE_UINT32 : READ_BE_UINT32; _readUint32 = (_type == kResourceTypeDOS) ? READ_LE_UINT32 : READ_BE_UINT32;
_scratchBuffer = (uint8_t *)malloc(320 * 224 + 1024); _scratchBuffer = (uint8_t *)malloc(kScratchBufferSize);
if (!_scratchBuffer) { if (!_scratchBuffer) {
error("Unable to allocate temporary memory buffer"); error("Unable to allocate temporary memory buffer");
} }
@ -36,9 +36,9 @@ Resource::Resource(FileSystem *fs, ResourceType ver, Language lang) {
Resource::~Resource() { Resource::~Resource() {
clearLevelRes(); clearLevelRes();
MAC_unloadLevelData();
free(_fnt); free(_fnt);
free(_icn); _icn = 0; free(_icn);
_icnLen = 0;
free(_tab); free(_tab);
free(_spc); free(_spc);
free(_spr1); free(_spr1);
@ -268,7 +268,7 @@ void Resource::load_PAL_menu(const char *fileName, uint8_t *dstPtr) {
error("Cannot load '%s'", _entryName); error("Cannot load '%s'", _entryName);
} }
void Resource::load_CMP_menu(const char *fileName, uint8_t *dstPtr) { void Resource::load_CMP_menu(const char *fileName) {
File f; File f;
if (f.open(fileName, "rb", _fs)) { if (f.open(fileName, "rb", _fs)) {
const uint32_t size = f.readUint32BE(); const uint32_t size = f.readUint32BE();
@ -277,7 +277,7 @@ void Resource::load_CMP_menu(const char *fileName, uint8_t *dstPtr) {
error("Failed to allocate CMP temporary buffer"); error("Failed to allocate CMP temporary buffer");
} }
f.read(tmp, size); f.read(tmp, size);
if (!delphine_unpack(dstPtr, tmp, size)) { if (!delphine_unpack(_scratchBuffer, kScratchBufferSize, tmp, size)) {
error("Bad CRC for %s", fileName); error("Bad CRC for %s", fileName);
} }
free(tmp); free(tmp);
@ -668,7 +668,7 @@ void Resource::load(const char *objName, int objType, const char *ext) {
_pal = dat; _pal = dat;
break; break;
case OT_CT: case OT_CT:
if (!delphine_unpack((uint8_t *)_ctData, dat, size)) { if (!delphine_unpack((uint8_t *)_ctData, sizeof(_ctData), dat, size)) {
error("Bad CRC for '%s'", _entryName); error("Bad CRC for '%s'", _entryName);
} }
free(dat); free(dat);
@ -736,7 +736,7 @@ void Resource::load_CT(File *pf) {
error("Unable to allocate CT buffer"); error("Unable to allocate CT buffer");
} else { } else {
pf->read(tmp, len); pf->read(tmp, len);
if (!delphine_unpack((uint8_t *)_ctData, tmp, len)) { if (!delphine_unpack((uint8_t *)_ctData, sizeof(_ctData), tmp, len)) {
error("Bad CRC for collision data"); error("Bad CRC for collision data");
} }
free(tmp); free(tmp);
@ -936,7 +936,7 @@ void Resource::load_OBC(File *f) {
} }
f->seek(4); f->seek(4);
f->read(packedData, packedSize); f->read(packedData, packedSize);
if (!delphine_unpack(tmp, packedData, packedSize)) { if (!delphine_unpack(tmp, unpackedSize, packedData, packedSize)) {
error("Bad CRC for compressed object data"); error("Bad CRC for compressed object data");
} }
free(packedData); free(packedData);
@ -1153,7 +1153,7 @@ void Resource::load_CMP(File *pf) {
} }
if (data[0].packedSize == data[0].size) { if (data[0].packedSize == data[0].size) {
memcpy(_pol, tmp + data[0].offset, data[0].packedSize); memcpy(_pol, tmp + data[0].offset, data[0].packedSize);
} else if (!delphine_unpack(_pol, tmp + data[0].offset, data[0].packedSize)) { } else if (!delphine_unpack(_pol, data[0].size, tmp + data[0].offset, data[0].packedSize)) {
error("Bad CRC for cutscene polygon data"); error("Bad CRC for cutscene polygon data");
} }
_cmd = (uint8_t *)malloc(data[1].size); _cmd = (uint8_t *)malloc(data[1].size);
@ -1162,7 +1162,7 @@ void Resource::load_CMP(File *pf) {
} }
if (data[1].packedSize == data[1].size) { if (data[1].packedSize == data[1].size) {
memcpy(_cmd, tmp + data[1].offset, data[1].packedSize); memcpy(_cmd, tmp + data[1].offset, data[1].packedSize);
} else if (!delphine_unpack(_cmd, tmp + data[1].offset, data[1].packedSize)) { } else if (!delphine_unpack(_cmd, data[1].size, tmp + data[1].offset, data[1].packedSize)) {
error("Bad CRC for cutscene command data"); error("Bad CRC for cutscene command data");
} }
free(tmp); free(tmp);
@ -1278,7 +1278,7 @@ void Resource::load_SGD(File *f) {
if (!_sgd) { if (!_sgd) {
error("Unable to allocate SGD buffer"); error("Unable to allocate SGD buffer");
} }
if (!delphine_unpack(_sgd, tmp, len)) { if (!delphine_unpack(_sgd, size, tmp, len)) {
error("Bad CRC for SGD data"); error("Bad CRC for SGD data");
} }
free(tmp); free(tmp);
@ -1310,12 +1310,12 @@ void Resource::load_SPM(File *f) {
if (!_spr1) { if (!_spr1) {
error("Unable to allocate SPR1 buffer"); error("Unable to allocate SPR1 buffer");
} }
if (!delphine_unpack(_spr1, tmp, len)) { if (!delphine_unpack(_spr1, size, tmp, len)) {
error("Bad CRC for SPM data"); error("Bad CRC for SPM data");
} }
} else { } else {
assert(size <= sizeof(_sprm)); assert(size <= sizeof(_sprm));
if (!delphine_unpack(_sprm, tmp, len)) { if (!delphine_unpack(_sprm, sizeof(_sprm), tmp, len)) {
error("Bad CRC for SPM data"); error("Bad CRC for SPM data");
} }
} }
@ -1391,7 +1391,7 @@ uint8_t *Resource::loadBankData(uint16_t num) {
} else { } else {
assert(dataOffset > 4); assert(dataOffset > 4);
assert(size == (int)READ_BE_UINT32(data - 4)); assert(size == (int)READ_BE_UINT32(data - 4));
if (!delphine_unpack(_bankDataHead, data, 0)) { if (!delphine_unpack(_bankDataHead, _bankDataTail - _bankDataHead, data, 0)) {
error("Bad CRC for bank data %d", num); error("Bad CRC for bank data %d", num);
} }
} }

View File

@ -112,7 +112,8 @@ struct Resource {
enum { enum {
kPaulaFreq = 3546897, kPaulaFreq = 3546897,
kClutSize = 1024 kClutSize = 1024,
kScratchBufferSize = 320 * 224 + 1024
}; };
static const uint16_t _voicesOffsetsTable[]; static const uint16_t _voicesOffsetsTable[];
@ -187,6 +188,7 @@ struct Resource {
bool isDOS() const { return _type == kResourceTypeDOS; } bool isDOS() const { return _type == kResourceTypeDOS; }
bool isAmiga() const { return _type == kResourceTypeAmiga; } bool isAmiga() const { return _type == kResourceTypeAmiga; }
bool isMac() const { return _type == kResourceTypeMac; }
bool fileExists(const char *filename); bool fileExists(const char *filename);
@ -196,7 +198,7 @@ struct Resource {
void load_SPL_demo(); void load_SPL_demo();
void load_MAP_menu(const char *fileName, uint8_t *dstPtr); void load_MAP_menu(const char *fileName, uint8_t *dstPtr);
void load_PAL_menu(const char *fileName, uint8_t *dstPtr); void load_PAL_menu(const char *fileName, uint8_t *dstPtr);
void load_CMP_menu(const char *fileName, uint8_t *dstPtr); void load_CMP_menu(const char *fileName);
void load_SPR_OFF(const char *fileName, uint8_t *sprData); void load_SPR_OFF(const char *fileName, uint8_t *sprData);
void load_CINE(); void load_CINE();
void free_CINE(); void free_CINE();

View File

@ -74,7 +74,7 @@ uint8_t *ResourceAba::loadEntry(const char *name, uint32_t *size) {
free(tmp); free(tmp);
return 0; return 0;
} }
const bool ret = delphine_unpack(dst, tmp, e->compressedSize); const bool ret = delphine_unpack(dst, e->size, tmp, e->compressedSize);
if (!ret) { if (!ret) {
error("Bad CRC for '%s'", name); error("Bad CRC for '%s'", name);
} }

2
rs.cfg
View File

@ -16,7 +16,7 @@ use_tiledata=false
# display text instead of playing the polygon cutscenes # display text instead of playing the polygon cutscenes
use_text_cutscenes=false use_text_cutscenes=false
# enable playback of .SEQ cutscenes (use polygonal if false) # enable playback of .SEQ cutscenes (always use polygon cutscenes if false)
use_seq_cutscenes=true use_seq_cutscenes=true
# enable playback of 'ASC' cutscene # enable playback of 'ASC' cutscene

View File

@ -31,4 +31,10 @@ extern const Scaler _internalScaler;
const Scaler *findScaler(const char *name); const Scaler *findScaler(const char *name);
#ifdef USE_STATIC_SCALER
extern const Scaler scaler_nearest;
extern const Scaler scaler_tv2x;
extern const Scaler scaler_xbrz;
#endif
#endif // SCALER_H__ #endif // SCALER_H__

View File

@ -68,6 +68,7 @@ struct SystemStub {
virtual void copyRectRgb24(int x, int y, int w, int h, const uint8_t *rgb) = 0; virtual void copyRectRgb24(int x, int y, int w, int h, const uint8_t *rgb) = 0;
virtual void copyRectLeftBorder(int w, int h, const uint8_t *buf) = 0; virtual void copyRectLeftBorder(int w, int h, const uint8_t *buf) = 0;
virtual void copyRectRightBorder(int w, int h, const uint8_t *buf) = 0; virtual void copyRectRightBorder(int w, int h, const uint8_t *buf) = 0;
virtual void copyRectMirrorBorders(int w, int h, const uint8_t *buf) = 0;
virtual void fadeScreen() = 0; virtual void fadeScreen() = 0;
virtual void updateScreen(int shakeOffset) = 0; virtual void updateScreen(int shakeOffset) = 0;

View File

@ -66,6 +66,7 @@ struct SystemStub_SDL : SystemStub {
virtual void copyRectRgb24(int x, int y, int w, int h, const uint8_t *rgb); virtual void copyRectRgb24(int x, int y, int w, int h, const uint8_t *rgb);
virtual void copyRectLeftBorder(int w, int h, const uint8_t *buf); virtual void copyRectLeftBorder(int w, int h, const uint8_t *buf);
virtual void copyRectRightBorder(int w, int h, const uint8_t *buf); virtual void copyRectRightBorder(int w, int h, const uint8_t *buf);
virtual void copyRectMirrorBorders(int w, int h, const uint8_t *buf);
virtual void fadeScreen(); virtual void fadeScreen();
virtual void updateScreen(int shakeOffset); virtual void updateScreen(int shakeOffset);
virtual void processEvents(); virtual void processEvents();
@ -82,6 +83,7 @@ struct SystemStub_SDL : SystemStub {
void prepareGraphics(); void prepareGraphics();
void cleanupGraphics(); void cleanupGraphics();
void changeGraphics(bool fullscreen, int scaleFactor); void changeGraphics(bool fullscreen, int scaleFactor);
void changeScaler(int scaler);
void drawRect(int x, int y, int w, int h, uint8_t color); void drawRect(int x, int y, int w, int h, uint8_t color);
}; };
@ -97,13 +99,13 @@ void SystemStub_SDL::init(const char *title, int w, int h, bool fullscreen, bool
_window = 0; _window = 0;
_renderer = 0; _renderer = 0;
_texture = 0; _texture = 0;
_fmt = 0; _fmt = SDL_AllocFormat(kPixelFormat);
_screenBuffer = 0; _screenBuffer = 0;
_fadeOnUpdateScreen = false; _fadeOnUpdateScreen = false;
_fullscreen = fullscreen; _fullscreen = fullscreen;
_scalerType = scalerParameters->type; _scalerType = scalerParameters->type;
_scaler = scalerParameters->scaler; _scaler = scalerParameters->scaler;
_scaleFactor = CLIP(scalerParameters->factor, _scaler->factorMin, _scaler->factorMax); _scaleFactor = _scaler ? CLIP(scalerParameters->factor, _scaler->factorMin, _scaler->factorMax) : 1;
memset(_rgbPalette, 0, sizeof(_rgbPalette)); memset(_rgbPalette, 0, sizeof(_rgbPalette));
memset(_darkPalette, 0, sizeof(_darkPalette)); memset(_darkPalette, 0, sizeof(_darkPalette));
_screenW = _screenH = 0; _screenW = _screenH = 0;
@ -127,6 +129,14 @@ void SystemStub_SDL::init(const char *title, int w, int h, bool fullscreen, bool
void SystemStub_SDL::destroy() { void SystemStub_SDL::destroy() {
cleanupGraphics(); cleanupGraphics();
if (_screenBuffer) {
free(_screenBuffer);
_screenBuffer = 0;
}
if (_fmt) {
SDL_FreeFormat(_fmt);
_fmt = 0;
}
if (_controller) { if (_controller) {
SDL_GameControllerClose(_controller); SDL_GameControllerClose(_controller);
_controller = 0; _controller = 0;
@ -147,6 +157,10 @@ void SystemStub_SDL::setScreenSize(int w, int h) {
return; return;
} }
cleanupGraphics(); cleanupGraphics();
if (_screenBuffer) {
free(_screenBuffer);
_screenBuffer = 0;
}
const int screenBufferSize = w * h * sizeof(uint32_t); const int screenBufferSize = w * h * sizeof(uint32_t);
_screenBuffer = (uint32_t *)calloc(1, screenBufferSize); _screenBuffer = (uint32_t *)calloc(1, screenBufferSize);
if (!_screenBuffer) { if (!_screenBuffer) {
@ -232,6 +246,19 @@ void SystemStub_SDL::copyRectRgb24(int x, int y, int w, int h, const uint8_t *rg
} }
} }
static void clearTexture(SDL_Texture *texture, int h, SDL_PixelFormat *fmt) {
void *dst = 0;
int pitch = 0;
if (SDL_LockTexture(texture, 0, &dst, &pitch) == 0) {
assert((pitch & 3) == 0);
const uint32_t color = SDL_MapRGB(fmt, 0, 0, 0);
for (uint32_t i = 0; i < h * pitch / sizeof(uint32_t); ++i) {
((uint32_t *)dst)[i] = color;
}
SDL_UnlockTexture(texture);
}
}
void SystemStub_SDL::copyRectLeftBorder(int w, int h, const uint8_t *buf) { void SystemStub_SDL::copyRectLeftBorder(int w, int h, const uint8_t *buf) {
assert(w >= _wideMargin); assert(w >= _wideMargin);
uint32_t *rgb = (uint32_t *)malloc(w * h * sizeof(uint32_t)); uint32_t *rgb = (uint32_t *)malloc(w * h * sizeof(uint32_t));
@ -241,7 +268,10 @@ void SystemStub_SDL::copyRectLeftBorder(int w, int h, const uint8_t *buf) {
rgb[i] = _darkPalette[buf[i]]; rgb[i] = _darkPalette[buf[i]];
} }
} else { } else {
memset(rgb, 0, w * h * sizeof(uint32_t)); const uint32_t color = SDL_MapRGB(_fmt, 0, 0, 0);
for (int i = 0; i < w * h; ++i) {
rgb[i] = color;
}
} }
const int xOffset = w - _wideMargin; const int xOffset = w - _wideMargin;
SDL_Rect r; SDL_Rect r;
@ -263,7 +293,10 @@ void SystemStub_SDL::copyRectRightBorder(int w, int h, const uint8_t *buf) {
rgb[i] = _darkPalette[buf[i]]; rgb[i] = _darkPalette[buf[i]];
} }
} else { } else {
memset(rgb, 0, w * h * sizeof(uint32_t)); const uint32_t color = SDL_MapRGB(_fmt, 0, 0, 0);
for (int i = 0; i < w * h; ++i) {
rgb[i] = color;
}
} }
const int xOffset = 0; const int xOffset = 0;
SDL_Rect r; SDL_Rect r;
@ -276,6 +309,35 @@ void SystemStub_SDL::copyRectRightBorder(int w, int h, const uint8_t *buf) {
} }
} }
void SystemStub_SDL::copyRectMirrorBorders(int w, int h, const uint8_t *buf) {
assert(w >= _wideMargin);
uint32_t *rgb = (uint32_t *)malloc(w * h * sizeof(uint32_t));
if (rgb) {
for (int i = 0; i < w * h; ++i) {
rgb[i] = _darkPalette[buf[i]];
}
void *dst = 0;
int pitch = 0;
if (SDL_LockTexture(_wideTexture, 0, &dst, &pitch) == 0) {
assert((pitch & 3) == 0);
uint32_t *p = (uint32_t *)dst;
for (int y = 0; y < h; ++y) {
for (int x = 0; x < _wideMargin; ++x) {
// left side
const int xLeft = _wideMargin - 1 - x;
p[x] = rgb[y * w + xLeft];
// right side
const int xRight = w - 1 - x;
p[_wideMargin + _screenW + x] = rgb[y * w + xRight];
}
p += pitch / sizeof(uint32_t);
}
SDL_UnlockTexture(_wideTexture);
}
free(rgb);
}
}
void SystemStub_SDL::fadeScreen() { void SystemStub_SDL::fadeScreen() {
_fadeOnUpdateScreen = true; _fadeOnUpdateScreen = true;
} }
@ -511,11 +573,15 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
break; break;
case SDLK_KP_PLUS: case SDLK_KP_PLUS:
case SDLK_PAGEUP: case SDLK_PAGEUP:
if (_scalerType == kScalerTypeInternal || _scalerType == kScalerTypeExternal) {
changeGraphics(_fullscreen, _scaleFactor + 1); changeGraphics(_fullscreen, _scaleFactor + 1);
}
break; break;
case SDLK_KP_MINUS: case SDLK_KP_MINUS:
case SDLK_PAGEDOWN: case SDLK_PAGEDOWN:
if (_scalerType == kScalerTypeInternal || _scalerType == kScalerTypeExternal) {
changeGraphics(_fullscreen, _scaleFactor - 1); changeGraphics(_fullscreen, _scaleFactor - 1);
}
break; break;
case SDLK_s: { case SDLK_s: {
char name[32]; char name[32];
@ -585,6 +651,16 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
case SDLK_ESCAPE: case SDLK_ESCAPE:
_pi.escape = false; _pi.escape = false;
break; break;
case SDLK_F1:
case SDLK_F2:
case SDLK_F3:
case SDLK_F4:
case SDLK_F5:
case SDLK_F6:
case SDLK_F7:
case SDLK_F8:
changeScaler(ev.key.keysym.sym - SDLK_F1);
break;
default: default:
break; break;
} }
@ -717,21 +793,18 @@ void SystemStub_SDL::prepareGraphics() {
_renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED); _renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED);
SDL_RenderSetLogicalSize(_renderer, windowW, windowH); SDL_RenderSetLogicalSize(_renderer, windowW, windowH);
_texture = SDL_CreateTexture(_renderer, kPixelFormat, SDL_TEXTUREACCESS_STREAMING, _texW, _texH); _texture = SDL_CreateTexture(_renderer, kPixelFormat, SDL_TEXTUREACCESS_STREAMING, _texW, _texH);
_fmt = SDL_AllocFormat(kPixelFormat);
if (_widescreen) { if (_widescreen) {
const int w = _screenH * 16 / 9; const int w = _screenH * 16 / 9;
const int h = _screenH; const int h = _screenH;
_wideTexture = SDL_CreateTexture(_renderer, kPixelFormat, SDL_TEXTUREACCESS_STREAMING, w, h); _wideTexture = SDL_CreateTexture(_renderer, kPixelFormat, SDL_TEXTUREACCESS_STREAMING, w, h);
clearTexture(_wideTexture, _screenH, _fmt);
// left and right borders // left and right borders
_wideMargin = (w - _screenW) / 2; _wideMargin = (w - _screenW) / 2;
} }
} }
void SystemStub_SDL::cleanupGraphics() { void SystemStub_SDL::cleanupGraphics() {
if (_screenBuffer) {
free(_screenBuffer);
_screenBuffer = 0;
}
if (_texture) { if (_texture) {
SDL_DestroyTexture(_texture); SDL_DestroyTexture(_texture);
_texture = 0; _texture = 0;
@ -748,10 +821,6 @@ void SystemStub_SDL::cleanupGraphics() {
SDL_DestroyWindow(_window); SDL_DestroyWindow(_window);
_window = 0; _window = 0;
} }
if (_fmt) {
SDL_FreeFormat(_fmt);
_fmt = 0;
}
} }
void SystemStub_SDL::changeGraphics(bool fullscreen, int scaleFactor) { void SystemStub_SDL::changeGraphics(bool fullscreen, int scaleFactor) {
@ -762,29 +831,53 @@ void SystemStub_SDL::changeGraphics(bool fullscreen, int scaleFactor) {
} }
_fullscreen = fullscreen; _fullscreen = fullscreen;
_scaleFactor = factor; _scaleFactor = factor;
if (_texture) { cleanupGraphics();
SDL_DestroyTexture(_texture);
_texture = 0;
}
if (_wideTexture) {
SDL_DestroyTexture(_wideTexture);
_wideTexture = 0;
}
if (_renderer) {
SDL_DestroyRenderer(_renderer);
_renderer = 0;
}
if (_window) {
SDL_DestroyWindow(_window);
_window = 0;
}
if (_fmt) {
SDL_FreeFormat(_fmt);
_fmt = 0;
}
prepareGraphics(); prepareGraphics();
} }
void SystemStub_SDL::changeScaler(int scaler) {
ScalerParameters scalerParameters = ScalerParameters::defaults();
switch (scaler) {
case 0:
scalerParameters.type = kScalerTypePoint;
break;
case 1:
scalerParameters.type = kScalerTypeLinear;
break;
case 2:
scalerParameters.type = kScalerTypeInternal;
scalerParameters.scaler = &_internalScaler;
break;
#ifdef USE_STATIC_SCALER
case 3:
scalerParameters.type = kScalerTypeInternal;
scalerParameters.scaler = &scaler_nearest;
break;
case 4:
scalerParameters.type = kScalerTypeInternal;
scalerParameters.scaler = &scaler_tv2x;
break;
case 5:
scalerParameters.type = kScalerTypeInternal;
scalerParameters.scaler = &scaler_xbrz;
break;
#endif
default:
return;
}
if (_scalerType != scalerParameters.type || scalerParameters.scaler != _scaler) {
_scalerType = scalerParameters.type;
_scaler = scalerParameters.scaler;
const int scaleFactor = CLIP(_scaleFactor, _scaler->factorMin, _scaler->factorMax);
// only recreate the window if dimensions actually changed
if (scaleFactor != _scaleFactor) {
cleanupGraphics();
_scaleFactor = scaleFactor;
prepareGraphics();
}
}
}
void SystemStub_SDL::drawRect(int x, int y, int w, int h, uint8_t color) { void SystemStub_SDL::drawRect(int x, int y, int w, int h, uint8_t color) {
const int x1 = x; const int x1 = x;
const int y1 = y; const int y1 = y;

View File

@ -5,9 +5,10 @@
*/ */
#include "unpack.h" #include "unpack.h"
#include "util.h"
struct UnpackCtx { struct UnpackCtx {
int datasize; int size;
uint32_t crc; uint32_t crc;
uint32_t bits; uint32_t bits;
uint8_t *dst; uint8_t *dst;
@ -26,40 +27,52 @@ static bool nextBit(UnpackCtx *uc) {
return carry; return carry;
} }
static uint16_t getBits(UnpackCtx *uc, int bitsCount) { static int getBits(UnpackCtx *uc, int count) {
uint16_t c = 0; int bits = 0;
for (int i = 0; i < bitsCount; ++i) { for (int i = 0; i < count; ++i) {
c <<= 1; bits <<= 1;
if (nextBit(uc)) { if (nextBit(uc)) {
c |= 1; bits |= 1;
} }
} }
return c; return bits;
} }
static void copyLiteral(UnpackCtx *uc, int bitsCount, int len) { static void copyLiteral(UnpackCtx *uc, int bitsCount, int len) {
const int count = getBits(uc, bitsCount) + len + 1; int count = getBits(uc, bitsCount) + len + 1;
for (int i = 0; i < count; ++i) { uc->size -= count;
*uc->dst = (uint8_t)getBits(uc, 8); if (uc->size < 0) {
--uc->dst; count += uc->size;
uc->size = 0;
} }
uc->datasize -= count; for (int i = 0; i < count; ++i) {
*(uc->dst - i) = (uint8_t)getBits(uc, 8);
}
uc->dst -= count;
} }
static void copyReference(UnpackCtx *uc, int bitsCount, int count) { static void copyReference(UnpackCtx *uc, int bitsCount, int count) {
const uint16_t offset = getBits(uc, bitsCount); uc->size -= count;
for (int i = 0; i < count; ++i) { if (uc->size < 0) {
*uc->dst = *(uc->dst + offset); count += uc->size;
--uc->dst; uc->size = 0;
} }
uc->datasize -= count; const int offset = getBits(uc, bitsCount);
for (int i = 0; i < count; ++i) {
*(uc->dst - i) = *(uc->dst - i + offset);
}
uc->dst -= count;
} }
bool delphine_unpack(uint8_t *dst, const uint8_t *src, int len) { bool delphine_unpack(uint8_t *dst, int dstSize, const uint8_t *src, int srcSize) {
UnpackCtx uc; UnpackCtx uc;
uc.src = src + len - 4; uc.src = src + srcSize - 4;
uc.datasize = READ_BE_UINT32(uc.src); uc.src -= 4; uc.size = READ_BE_UINT32(uc.src); uc.src -= 4;
uc.dst = dst + uc.datasize - 1; if (uc.size > dstSize) {
warning("Unexpected unpack size %d, buffer size %d", uc.size, dstSize);
return false;
}
uc.dst = dst + uc.size - 1;
uc.crc = READ_BE_UINT32(uc.src); uc.src -= 4; uc.crc = READ_BE_UINT32(uc.src); uc.src -= 4;
uc.bits = READ_BE_UINT32(uc.src); uc.src -= 4; uc.bits = READ_BE_UINT32(uc.src); uc.src -= 4;
uc.crc ^= uc.bits; uc.crc ^= uc.bits;
@ -87,6 +100,7 @@ bool delphine_unpack(uint8_t *dst, const uint8_t *src, int len) {
break; break;
} }
} }
} while (uc.datasize > 0); } while (uc.size > 0);
assert(uc.size == 0);
return uc.crc == 0; return uc.crc == 0;
} }

View File

@ -9,6 +9,6 @@
#include "intern.h" #include "intern.h"
extern bool delphine_unpack(uint8_t *dst, const uint8_t *src, int len); extern bool delphine_unpack(uint8_t *dst, int dstSize, const uint8_t *src, int srcSize);
#endif // UNPACK_H__ #endif // UNPACK_H__

View File

@ -629,8 +629,9 @@ static void decodeLevHelper(uint8_t *dst, const uint8_t *src, int offset10, int
void Video::AMIGA_decodeLev(int level, int room) { void Video::AMIGA_decodeLev(int level, int room) {
uint8_t *tmp = _res->_scratchBuffer; uint8_t *tmp = _res->_scratchBuffer;
const int offset = READ_BE_UINT32(_res->_lev + room * 4); const int offset = READ_BE_UINT32(_res->_lev + room * 4);
if (!delphine_unpack(tmp, _res->_lev, offset)) { if (!delphine_unpack(tmp, Resource::kScratchBufferSize, _res->_lev, offset)) {
error("Bad CRC for level %d room %d", level, room); warning("Bad CRC for level %d room %d", level, room);
return;
} }
uint16_t offset10 = READ_BE_UINT16(tmp + 10); uint16_t offset10 = READ_BE_UINT16(tmp + 10);
const uint16_t offset12 = READ_BE_UINT16(tmp + 12); const uint16_t offset12 = READ_BE_UINT16(tmp + 12);
@ -900,6 +901,9 @@ void Video::PC_drawStringChar(uint8_t *dst, int pitch, int x, int y, const uint8
} }
} }
static uint8_t _MAC_fontFrontColor;
static uint8_t _MAC_fontShadowColor;
void Video::MAC_drawStringChar(uint8_t *dst, int pitch, int x, int y, const uint8_t *src, uint8_t color, uint8_t chr) { void Video::MAC_drawStringChar(uint8_t *dst, int pitch, int x, int y, const uint8_t *src, uint8_t color, uint8_t chr) {
DecodeBuffer buf; DecodeBuffer buf;
memset(&buf, 0, sizeof(buf)); memset(&buf, 0, sizeof(buf));
@ -909,8 +913,8 @@ void Video::MAC_drawStringChar(uint8_t *dst, int pitch, int x, int y, const uint
buf.x = x * _layerScale; buf.x = x * _layerScale;
buf.y = y * _layerScale; buf.y = y * _layerScale;
buf.setPixel = Video::MAC_drawBufferFont; buf.setPixel = Video::MAC_drawBufferFont;
_charFrontColor = color; _MAC_fontFrontColor = color;
buf.dataPtr = this; _MAC_fontShadowColor = _charShadowColor;
assert(chr >= 32); assert(chr >= 32);
_res->MAC_decodeImageData(_res->_fnt, chr - 32, &buf); _res->MAC_decodeImageData(_res->_fnt, chr - 32, &buf);
} }
@ -1004,21 +1008,20 @@ void Video::MAC_drawBufferFont(DecodeBuffer *buf, int src_x, int src_y, int src_
if (y >= 0 && y < buf->h) { if (y >= 0 && y < buf->h) {
const int x = buf->x + src_x; const int x = buf->x + src_x;
if (x >= 0 && x < buf->w) { if (x >= 0 && x < buf->w) {
const Video *vid = (Video *)buf->dataPtr;
const int offset = y * buf->pitch + x; const int offset = y * buf->pitch + x;
switch (color) { switch (color) {
case 0xC0: case 0xC0:
buf->ptr[offset] = vid->_charShadowColor; buf->ptr[offset] = _MAC_fontShadowColor;
break; break;
case 0xC1: case 0xC1:
buf->ptr[offset] = vid->_charFrontColor; buf->ptr[offset] = _MAC_fontFrontColor;
break; break;
} }
} }
} }
} }
void Video::MAC_fillRect(int x, int y, int w, int h, uint8_t color) { void Video::fillRect(int x, int y, int w, int h, uint8_t color) {
uint8_t *p = _frontLayer + y * _layerScale * _w + x * _layerScale; uint8_t *p = _frontLayer + y * _layerScale * _w + x * _layerScale;
for (int j = 0; j < h * _layerScale; ++j) { for (int j = 0; j < h * _layerScale; ++j) {
memset(p, color, w * _layerScale); memset(p, color, w * _layerScale);

View File

@ -90,7 +90,7 @@ struct Video {
static void MAC_drawBuffer(DecodeBuffer *buf, int src_x, int src_y, int src_w, int src_h, uint8_t color); static void MAC_drawBuffer(DecodeBuffer *buf, int src_x, int src_y, int src_w, int src_h, uint8_t color);
static void MAC_drawBufferMask(DecodeBuffer *buf, int src_x, int src_y, int src_w, int src_h, uint8_t color); static void MAC_drawBufferMask(DecodeBuffer *buf, int src_x, int src_y, int src_w, int src_h, uint8_t color);
static void MAC_drawBufferFont(DecodeBuffer *buf, int src_x, int src_y, int src_w, int src_h, uint8_t color); static void MAC_drawBufferFont(DecodeBuffer *buf, int src_x, int src_y, int src_w, int src_h, uint8_t color);
void MAC_fillRect(int x, int y, int w, int h, uint8_t color); void fillRect(int x, int y, int w, int h, uint8_t color);
void MAC_drawSprite(int x, int y, const uint8_t *data, int frame, bool xflip, bool eraseBackground); void MAC_drawSprite(int x, int y, const uint8_t *data, int frame, bool xflip, bool eraseBackground);
}; };