Import 0.4.6

This commit is contained in:
Gregory Montoir 2019-12-29 00:00:00 +08:00
parent 86baaa3a9a
commit 2dc61ca627
21 changed files with 411 additions and 262 deletions

View File

@ -1,3 +1,7 @@
* release 0.4.6
- added rewind to automatic saves
- fixed passwords and protection codes input
* release 0.4.5 * release 0.4.5
- added low-pass filtering for in-game music - added low-pass filtering for in-game music
- added support for 3DO background music (tunes/*.Cpc) - added support for 3DO background music (tunes/*.Cpc)
@ -72,7 +76,7 @@
* release 0.2.2 * release 0.2.2
- added support for level background music - added support for level background music
- added italian texts - added Italian texts
- fixed PC-CD SEQ cutscenes numbering - fixed PC-CD SEQ cutscenes numbering
- fixed several issues with Amiga data files - fixed several issues with Amiga data files
@ -111,7 +115,7 @@
- added input keys recording - added input keys recording
- reduced memory usage - reduced memory usage
* release 0.2.0 (2005/04/02) * release 0.1.4 (2005/04/02)
- added screen shaking (level 2) - added screen shaking (level 2)
- added support for Amiga music (experimental) - added support for Amiga music (experimental)
- fixed screen refresh after teleportation - fixed screen refresh after teleportation
@ -127,7 +131,7 @@
- added sound effects playback - added sound effects playback
- added support for polygonal cutscenes - added support for polygonal cutscenes
- added support for final credits sequence - added support for final credits sequence
- fixed instructions screen display in english version - fixed instructions screen display in English version
* release 0.1.1 (2005/01/29) * release 0.1.1 (2005/01/29)
- added missing opcodes, game should now be completable - added missing opcodes, game should now be completable

View File

@ -2,24 +2,22 @@
SDL_CFLAGS := `sdl2-config --cflags` SDL_CFLAGS := `sdl2-config --cflags`
SDL_LIBS := `sdl2-config --libs` SDL_LIBS := `sdl2-config --libs`
DL_LIBS := -ldl
MODPLUG_LIBS := -lmodplug MODPLUG_LIBS := -lmodplug
TREMOR_LIBS := -lvorbisidec -logg TREMOR_LIBS := -lvorbisidec -logg
ZLIB_LIBS := -lz ZLIB_LIBS := -lz
CXXFLAGS += -Wall -Wpedantic -MMD $(SDL_CFLAGS) -DUSE_MODPLUG -DUSE_STATIC_SCALER -DUSE_TREMOR -DUSE_ZLIB CXXFLAGS += -Wall -Wpedantic -MMD $(SDL_CFLAGS) -DUSE_MODPLUG -DUSE_TREMOR -DUSE_ZLIB
SRCS = collision.cpp cpc_player.cpp cutscene.cpp decode_mac.cpp dynlib.cpp file.cpp fs.cpp game.cpp graphics.cpp main.cpp \ SRCS = collision.cpp cpc_player.cpp cutscene.cpp decode_mac.cpp file.cpp fs.cpp game.cpp graphics.cpp main.cpp \
menu.cpp mixer.cpp mod_player.cpp ogg_player.cpp piege.cpp protection.cpp resource.cpp resource_aba.cpp \ menu.cpp mixer.cpp mod_player.cpp ogg_player.cpp piege.cpp protection.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
SCALERS := scalers/scaler_nearest.cpp scalers/scaler_tv2x.cpp scalers/scaler_xbr.cpp
OBJS = $(SRCS:.cpp=.o) $(SCALERS:.cpp=.o) OBJS = $(SRCS:.cpp=.o) $(SCALERS:.cpp=.o)
DEPS = $(SRCS:.cpp=.d) $(SCALERS:.cpp=.d) DEPS = $(SRCS:.cpp=.d) $(SCALERS:.cpp=.d)
LIBS = $(SDL_LIBS) $(DL_LIBS) $(MODPLUG_LIBS) $(TREMOR_LIBS) $(ZLIB_LIBS) LIBS = $(SDL_LIBS) $(MODPLUG_LIBS) $(TREMOR_LIBS) $(ZLIB_LIBS)
rs: $(OBJS) rs: $(OBJS)
$(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)

View File

@ -1,6 +1,6 @@
REminiscence README REminiscence README
Release version: 0.4.5 Release version: 0.4.6
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -50,8 +50,8 @@ These paths can be changed using command line switches :
The scaler option specifies the algorithm used to smoothen the image in The scaler option specifies the algorithm used to smoothen the image in
addition to a scaling factor. External scalers are also supported, the suffix 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_xbr.dll, you can pass
'--scaler xbrz@2' to use that algorithm with a doubled window size (512x448). '--scaler xbr@2' to use that algorithm with a doubled window size (512x448).
The widescreen option accepts two modes : The widescreen option accepts two modes :
'adjacent' : left and right rooms bitmaps will be drawn 'adjacent' : left and right rooms bitmaps will be drawn
@ -69,6 +69,7 @@ In-game hotkeys :
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 R rewind game state buffer (requires --autosave)
Ctrl + and - change game state slot Ctrl + and - change game state slot
Function Keys change game screen scaler Function Keys change game screen scaler

View File

@ -410,8 +410,8 @@ void Cutscene::op_setPalette() {
} }
} }
void Cutscene::op_drawStringAtBottom() { void Cutscene::op_drawCaptionText() {
debug(DBG_CUT, "Cutscene::op_drawStringAtBottom()"); debug(DBG_CUT, "Cutscene::op_drawCaptionText()");
uint16_t strId = fetchNextCmdWord(); uint16_t strId = fetchNextCmdWord();
if (!_creditsSequence) { if (!_creditsSequence) {
@ -1036,7 +1036,7 @@ bool Cutscene::load(uint16_t cutName) {
// //
uint8_t *p = _res->_cmd + 0x322; uint8_t *p = _res->_cmd + 0x322;
if (memcmp(p, "\x00\x18\x00\x3a", 4) == 0) { if (memcmp(p, "\x00\x18\x00\x3a", 4) == 0) {
p[0] = 0x06 << 2; // op_drawStringAtBottom p[0] = 0x06 << 2; // op_drawCaptionText
p[1] = 0x00; p[1] = 0x00;
p[2] = 0x3a; p[2] = 0x3a;
p[3] = 0x00; // op_markCurPos p[3] = 0x00; // op_markCurPos

View File

@ -128,7 +128,7 @@ struct Cutscene {
void op_waitForSync(); void op_waitForSync();
void op_drawShape(); void op_drawShape();
void op_setPalette(); void op_setPalette();
void op_drawStringAtBottom(); void op_drawCaptionText();
void op_nop(); void op_nop();
void op_skip3(); void op_skip3();
void op_refreshAll(); void op_refreshAll();

View File

@ -1,59 +0,0 @@
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#include <stdio.h>
#include <sys/param.h>
#include "dynlib.h"
#ifdef WIN32
struct DynLib_impl {
HINSTANCE _dl;
DynLib_impl(const char *name) {
char dllname[MAXPATHLEN];
snprintf(dllname, sizeof(dllname), "%s.dll", name);
_dl = LoadLibrary(dllname);
}
~DynLib_impl() {
if (_dl) {
FreeLibrary(_dl);
_dl = 0;
}
}
void *getSymbol(const char *name) {
return (void *)GetProcAddress(_dl, name);
}
};
#else
struct DynLib_impl {
void *_dl;
DynLib_impl(const char *name) {
char soname[MAXPATHLEN];
snprintf(soname, sizeof(soname), "%s.so", name);
_dl = dlopen(soname, RTLD_LAZY);
}
~DynLib_impl() {
if (_dl) {
dlclose(_dl);
}
}
void *getSymbol(const char *name) {
return dlsym(_dl, name);
}
};
#endif
DynLib::DynLib(const char *name) {
_impl = new DynLib_impl(name);
}
DynLib::~DynLib() {
delete _impl;
}
void *DynLib::getSymbol(const char *name) {
return _impl->getSymbol(name);
}

View File

@ -1,16 +0,0 @@
#ifndef DYNLIB_H__
#define DYNLIB_H__
struct DynLib_impl;
struct DynLib {
DynLib_impl *_impl;
DynLib(const char *name);
~DynLib();
void *getSymbol(const char *name);
};
#endif // DYNLIB_H__

View File

@ -197,6 +197,58 @@ struct AssetFile: File_impl {
}; };
#endif #endif
struct MemoryBufferFile: File_impl {
uint8_t *_ptr;
uint32_t _capacity, _offset, _len;
MemoryBufferFile(int initialCapacity) {
_capacity = initialCapacity;
_ptr = (uint8_t *)malloc(_capacity);
_offset = _len = 0;
}
~MemoryBufferFile() {
free(_ptr);
}
bool open(const char *path, const char *mode) {
return false;
}
void close() {
}
uint32_t size() {
return _len;
}
uint32_t tell() {
return _offset;
}
void seek(int offs) {
_offset = offs;
}
uint32_t read(void *ptr, uint32_t len) {
int count = len;
if (_offset + count > _len) {
count = _len - _offset;
_ioErr = true;
}
if (count != 0) {
memcpy(ptr, _ptr + _offset, count);
_offset += count;
}
return count;
}
uint32_t write(const void *ptr, uint32_t len) {
int count = len;
while (_offset + count > _capacity) {
_capacity *= 2;
_ptr = (uint8_t *)realloc(_ptr, _capacity);
}
if (count != 0) {
memcpy(_ptr + _offset, ptr, count);
_offset += count;
}
_len = _offset;
return count;
}
};
File::File() File::File()
: _impl(0) { : _impl(0) {
} }
@ -264,6 +316,15 @@ bool File::open(const char *filename, const char *mode, const char *directory) {
return _impl->open(path, mode); return _impl->open(path, mode);
} }
void File::openMemoryBuffer(int initialCapacity) {
if (_impl) {
_impl->close();
delete _impl;
_impl = 0;
}
_impl = new MemoryBufferFile(initialCapacity);
}
void File::close() { void File::close() {
if (_impl) { if (_impl) {
_impl->close(); _impl->close();

1
file.h
View File

@ -20,6 +20,7 @@ struct File {
bool open(const char *filename, const char *mode, FileSystem *fs); bool open(const char *filename, const char *mode, FileSystem *fs);
bool open(const char *filename, const char *mode, const char *directory); bool open(const char *filename, const char *mode, const char *directory);
void openMemoryBuffer(int initialCapacity);
void close(); void close();
bool ioErr() const; bool ioErr() const;
uint32_t size(); uint32_t size();

View File

@ -25,6 +25,8 @@ Game::Game(SystemStub *stub, FileSystem *fs, const char *savePath, int level, Re
_demoBin = -1; _demoBin = -1;
_widescreenMode = widescreenMode; _widescreenMode = widescreenMode;
_autoSave = autoSave; _autoSave = autoSave;
_rewindPtr = -1;
_rewindLen = 0;
} }
void Game::run() { void Game::run() {
@ -159,6 +161,7 @@ void Game::run() {
_vid._unkPalSlot1 = 0; _vid._unkPalSlot1 = 0;
_vid._unkPalSlot2 = 0; _vid._unkPalSlot2 = 0;
_score = 0; _score = 0;
clearStateRewind();
loadLevelData(); loadLevelData();
resetGameState(); resetGameState();
_endLoop = false; _endLoop = false;
@ -195,7 +198,7 @@ void Game::displayTitleScreenAmiga() {
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);
} }
static const int kAmigaColors[] = { static const uint16_t kAmigaColors[] = {
0x000, 0x123, 0x012, 0x134, 0x433, 0x453, 0x046, 0x245, 0x000, 0x123, 0x012, 0x134, 0x433, 0x453, 0x046, 0x245,
0x751, 0x455, 0x665, 0x268, 0x961, 0x478, 0x677, 0x786, 0x751, 0x455, 0x665, 0x268, 0x961, 0x478, 0x677, 0x786,
0x17B, 0x788, 0xB84, 0xC92, 0x49C, 0xF00, 0x9A8, 0x9AA, 0x17B, 0x788, 0xB84, 0xC92, 0x49C, 0xF00, 0x9A8, 0x9AA,
@ -384,11 +387,12 @@ void Game::mainLoop() {
playCutscene(0x41); playCutscene(0x41);
_endLoop = true; _endLoop = true;
} else { } else {
if (_autoSave && loadGameState(kAutoSaveSlot)) { if (_autoSave && _rewindLen != 0 && loadGameState(kAutoSaveSlot)) {
// autosave // autosave
} else if (_validSaveState && loadGameState(kIngameSaveSlot)) { } else if (_validSaveState && loadGameState(kIngameSaveSlot)) {
// ingame save // ingame save
} else { } else {
clearStateRewind();
loadLevelData(); loadLevelData();
resetGameState(); resetGameState();
} }
@ -453,9 +457,9 @@ void Game::mainLoop() {
} }
} }
inp_handleSpecialKeys(); inp_handleSpecialKeys();
if (_stub->getTimeStamp() - _saveTimestamp >= kAutoSaveIntervalMs) { if (_autoSave && _stub->getTimeStamp() - _saveTimestamp >= kAutoSaveIntervalMs) {
// do not save if we just died // do not save if we died or about to
if (_pgeLive[0].life > 0) { if (_pgeLive[0].life > 0 && _deathCutsceneCounter == 0) {
saveGameState(kAutoSaveSlot); saveGameState(kAutoSaveSlot);
_saveTimestamp = _stub->getTimeStamp(); _saveTimestamp = _stub->getTimeStamp();
} }
@ -594,6 +598,14 @@ void Game::inp_handleSpecialKeys() {
} }
_stub->_pi.stateSlot = 0; _stub->_pi.stateSlot = 0;
} }
if (_stub->_pi.rewind) {
if (_rewindLen != 0) {
loadStateRewind();
} else {
debug(DBG_INFO, "Rewind buffer is empty");
}
_stub->_pi.rewind = false;
}
} }
void Game::drawCurrentInventoryItem() { void Game::drawCurrentInventoryItem() {
@ -1817,6 +1829,7 @@ uint16_t Game::getRandomNumber() {
void Game::changeLevel() { void Game::changeLevel() {
_vid.fadeOut(); _vid.fadeOut();
clearStateRewind();
loadLevelData(); loadLevelData();
loadLevelMap(); loadLevelMap();
_vid.setPalette0xF(); _vid.setPalette0xF();
@ -1981,6 +1994,9 @@ void Game::makeGameStateName(uint8_t slot, char *buf) {
static const uint32_t TAG_FBSV = 0x46425356; static const uint32_t TAG_FBSV = 0x46425356;
bool Game::saveGameState(uint8_t slot) { bool Game::saveGameState(uint8_t slot) {
if (slot == kAutoSaveSlot) {
return saveStateRewind();
}
bool success = false; bool success = false;
char stateFile[32]; char stateFile[32];
makeGameStateName(slot, stateFile); makeGameStateName(slot, stateFile);
@ -2008,6 +2024,9 @@ bool Game::saveGameState(uint8_t slot) {
} }
bool Game::loadGameState(uint8_t slot) { bool Game::loadGameState(uint8_t slot) {
if (slot == kAutoSaveSlot) {
return loadStateRewind();
}
bool success = false; bool success = false;
char stateFile[32]; char stateFile[32];
makeGameStateName(slot, stateFile); makeGameStateName(slot, stateFile);
@ -2177,6 +2196,53 @@ void Game::loadState(File *f) {
resetGameState(); resetGameState();
} }
void Game::clearStateRewind() {
// debug(DBG_INFO, "Clear rewind state (count %d)", _rewindLen);
for (int i = 0; i < _rewindLen; ++i) {
int ptr = _rewindPtr - i;
if (ptr < 0) {
ptr += kRewindSize;
}
_rewindBuffer[ptr].close();
}
_rewindPtr = -1;
_rewindLen = 0;
}
bool Game::saveStateRewind() {
if (_rewindPtr == kRewindSize - 1) {
_rewindPtr = 0;
} else {
++_rewindPtr;
}
static const int kGameStateSize = 16384;
File &f = _rewindBuffer[_rewindPtr];
f.openMemoryBuffer(kGameStateSize);
saveState(&f);
if (_rewindLen < kRewindSize) {
++_rewindLen;
}
// debug(DBG_INFO, "Save state for rewind (index %d, count %d, size %d)", _rewindPtr, _rewindLen, f.size());
return !f.ioErr();
}
bool Game::loadStateRewind() {
const int ptr = _rewindPtr;
if (_rewindPtr == 0) {
_rewindPtr = kRewindSize - 1;
} else {
--_rewindPtr;
}
File &f = _rewindBuffer[ptr];
f.seek(0);
loadState(&f);
if (_rewindLen > 0) {
--_rewindLen;
}
// debug(DBG_INFO, "Rewind state (index %d, count %d, size %d)", ptr, _rewindLen, f.size());
return !f.ioErr();
}
void AnimBuffers::addState(uint8_t stateNum, int16_t x, int16_t y, const uint8_t *dataPtr, LivePGE *pge, uint8_t w, uint8_t h) { 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=%p pge=%p", 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); assert(stateNum < 4);

8
game.h
View File

@ -27,8 +27,9 @@ struct Game {
enum { enum {
kIngameSaveSlot = 0, kIngameSaveSlot = 0,
kRewindSize = 120, // 10mins (~2MB)
kAutoSaveSlot = 255, kAutoSaveSlot = 255,
kAutoSaveIntervalMs = 120 * 1000 kAutoSaveIntervalMs = 5 * 1000
}; };
enum { enum {
@ -68,6 +69,8 @@ struct Game {
SystemStub *_stub; SystemStub *_stub;
FileSystem *_fs; FileSystem *_fs;
const char *_savePath; const char *_savePath;
File _rewindBuffer[kRewindSize];
int _rewindPtr, _rewindLen;
const uint8_t *_stringsTable; const uint8_t *_stringsTable;
const char **_textsTable; const char **_textsTable;
@ -384,6 +387,9 @@ struct Game {
bool loadGameState(uint8_t slot); bool loadGameState(uint8_t slot);
void saveState(File *f); void saveState(File *f);
void loadState(File *f); void loadState(File *f);
void clearStateRewind();
bool saveStateRewind();
bool loadStateRewind();
}; };
#endif // GAME_H__ #endif // GAME_H__

View File

@ -156,50 +156,13 @@ static void initOptions() {
} }
static void parseScaler(char *name, ScalerParameters *scalerParameters) { static void parseScaler(char *name, ScalerParameters *scalerParameters) {
static const struct {
const char *name;
int type;
const Scaler *scaler;
} scalers[] = {
{ "point", kScalerTypePoint, 0 },
{ "linear", kScalerTypeLinear, 0 },
{ "scale", kScalerTypeInternal, &_internalScaler },
#ifdef USE_STATIC_SCALER
{ "nearest", kScalerTypeInternal, &scaler_nearest },
{ "tv2x", kScalerTypeInternal, &scaler_tv2x },
{ "xbr", kScalerTypeInternal, &scaler_xbr },
#endif
{ 0, -1 }
};
bool found = false;
char *sep = strchr(name, '@'); char *sep = strchr(name, '@');
if (sep) { if (sep) {
*sep = 0; *sep = 0;
}
for (int i = 0; scalers[i].name; ++i) {
if (strcmp(scalers[i].name, name) == 0) {
scalerParameters->type = (ScalerType)scalers[i].type;
scalerParameters->scaler = scalers[i].scaler;
found = true;
break;
}
}
if (!found) {
char libname[32];
snprintf(libname, sizeof(libname), "scaler_%s", name);
const Scaler *scaler = findScaler(libname);
if (!scaler) {
warning("Scaler '%s' not found, using default", libname);
} else if (scaler->tag != SCALER_TAG) {
warning("Unexpected tag %d for scaler '%s'", scaler->tag, libname);
} else {
scalerParameters->type = kScalerTypeExternal;
scalerParameters->scaler = scaler;
}
}
if (sep) {
scalerParameters->factor = atoi(sep + 1); scalerParameters->factor = atoi(sep + 1);
} }
strncpy(scalerParameters->name, name, sizeof(scalerParameters->name) - 1);
scalerParameters->name[sizeof(scalerParameters->name) - 1] = 0;
} }
static WidescreenMode parseWidescreen(const char *mode) { static WidescreenMode parseWidescreen(const char *mode) {

View File

@ -212,9 +212,6 @@ bool Menu::handlePasswordScreen() {
if (c != 0) { if (c != 0) {
_stub->_pi.lastChar = 0; _stub->_pi.lastChar = 0;
if (len < 6) { if (len < 6) {
if (c >= 'a' && c <= 'z') {
c &= ~0x20;
}
if ((c >= 'A' && c <= 'Z') || (c == 0x20)) { if ((c >= 'A' && c <= 'Z') || (c == 0x20)) {
password[len] = c; password[len] = c;
++len; ++len;

View File

@ -9,13 +9,11 @@
#include "systemstub.h" #include "systemstub.h"
static uint8_t reverseBits(uint8_t ch) { static uint8_t reverseBits(uint8_t ch) {
uint8_t r = 0; static const uint8_t lut[] = {
for (int b = 0; b < 8; ++b) { 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
if (ch & (1 << b)) { 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF
r |= (1 << (7 - b)); };
} return (lut[ch & 15] << 4) | lut[ch >> 4];
}
return r;
} }
static uint8_t decryptChar(uint8_t ch) { static uint8_t decryptChar(uint8_t ch) {
@ -114,9 +112,6 @@ bool Game::handleProtectionScreenShape() {
if (c != 0) { if (c != 0) {
_stub->_pi.lastChar = 0; _stub->_pi.lastChar = 0;
if (len < kCodeLen) { if (len < kCodeLen) {
if (c >= 'a' && c <= 'z') {
c &= ~0x20;
}
if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) { if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) {
codeText[len] = c; codeText[len] = c;
++len; ++len;
@ -201,7 +196,7 @@ bool Game::handleProtectionScreenWords() {
const uint8_t code = getRandomNumber() % kWordsCount; const uint8_t code = getRandomNumber() % kWordsCount;
const uint8_t *protectionData = _protectionWordData + code * 18; const uint8_t *protectionData = _protectionWordData + code * 18;
const char *kSecurityCodeText = "SECURITY CODE"; static const char *kSecurityCodeText = "SECURITY CODE";
_vid.drawString(kSecurityCodeText, 72 + (114 - strlen(kSecurityCodeText) * 8) / 2, 158, 0xE4); _vid.drawString(kSecurityCodeText, 72 + (114 - strlen(kSecurityCodeText) * 8) / 2, 158, 0xE4);
char buf[16]; char buf[16];
snprintf(buf, sizeof(buf), "PAGE %d", protectionData[0]); snprintf(buf, sizeof(buf), "PAGE %d", protectionData[0]);
@ -229,9 +224,6 @@ bool Game::handleProtectionScreenWords() {
if (c != 0) { if (c != 0) {
_stub->_pi.lastChar = 0; _stub->_pi.lastChar = 0;
if (len < kCodeLen) { if (len < kCodeLen) {
if (c >= 'a' && c <= 'z') {
c &= ~0x20;
}
if (c >= 'A' && c <= 'Z') { if (c >= 'A' && c <= 'Z') {
codeText[len] = c; codeText[len] = c;
++len; ++len;

View File

@ -15,6 +15,10 @@ ResourceAba::~ResourceAba() {
free(_entries); free(_entries);
} }
static int compareAbaEntry(const void *a, const void *b) {
return strcasecmp(((ResourceAbaEntry *)a)->name, ((ResourceAbaEntry *)b)->name);
}
void ResourceAba::readEntries() { void ResourceAba::readEntries() {
if (_f.open(FILENAME, "rb", _fs)) { if (_f.open(FILENAME, "rb", _fs)) {
_entriesCount = _f.readUint16BE(); _entriesCount = _f.readUint16BE();
@ -39,16 +43,14 @@ void ResourceAba::readEntries() {
} }
nextOffset = _entries[i].offset + _entries[i].compressedSize; nextOffset = _entries[i].offset + _entries[i].compressedSize;
} }
qsort(_entries, _entriesCount, sizeof(ResourceAbaEntry), compareAbaEntry);
} }
} }
const ResourceAbaEntry *ResourceAba::findEntry(const char *name) const { const ResourceAbaEntry *ResourceAba::findEntry(const char *name) const {
for (int i = 0; i < _entriesCount; ++i) { ResourceAbaEntry tmp;
if (strcasecmp(_entries[i].name, name) == 0) { strcpy(tmp.name, name);
return &_entries[i]; return (const ResourceAbaEntry *)bsearch(&tmp, _entries, _entriesCount, sizeof(ResourceAbaEntry), compareAbaEntry);
}
}
return 0;
} }
uint8_t *ResourceAba::loadEntry(const char *name, uint32_t *size) { uint8_t *ResourceAba::loadEntry(const char *name, uint32_t *size) {

View File

@ -5,7 +5,6 @@
*/ */
#include "scaler.h" #include "scaler.h"
#include "dynlib.h"
#include "util.h" #include "util.h"
static void scanline2x(uint32_t *dst0, uint32_t *dst1, const uint32_t *src0, const uint32_t *src1, const uint32_t *src2, int w) { static void scanline2x(uint32_t *dst0, uint32_t *dst1, const uint32_t *src0, const uint32_t *src1, const uint32_t *src2, int w) {
@ -282,17 +281,3 @@ const Scaler _internalScaler = {
2, 4, 2, 4,
scaleNx, scaleNx,
}; };
static DynLib *dynLib;
static const char *kSoSym = "getScaler";
const Scaler *findScaler(const char *name) {
dynLib = new DynLib(name);
void *symbol = dynLib->getSymbol(kSoSym);
if (symbol) {
typedef const Scaler *(*GetScalerProc)();
return ((GetScalerProc)symbol)();
}
return 0;
}

View File

@ -24,6 +24,7 @@ void SeqDemuxer::close() {
for (int i = 0; i < kBuffersCount; ++i) { for (int i = 0; i < kBuffersCount; ++i) {
free(_buffers[i].data); free(_buffers[i].data);
} }
memset(_buffers, 0, sizeof(_buffers));
} }
bool SeqDemuxer::readHeader() { bool SeqDemuxer::readHeader() {

View File

@ -17,7 +17,7 @@ const Cutscene::OpcodeStub Cutscene::_opcodeTable[] = {
/* 0x04 */ /* 0x04 */
&Cutscene::op_setPalette, &Cutscene::op_setPalette,
&Cutscene::op_markCurPos, &Cutscene::op_markCurPos,
&Cutscene::op_drawStringAtBottom, &Cutscene::op_drawCaptionText,
&Cutscene::op_nop, &Cutscene::op_nop,
/* 0x08 */ /* 0x08 */
&Cutscene::op_skip3, &Cutscene::op_skip3,

View File

@ -35,6 +35,7 @@ struct PlayerInput {
bool save; bool save;
bool load; bool load;
int stateSlot; int stateSlot;
bool rewind;
uint8_t dbgMask; uint8_t dbgMask;
bool quit; bool quit;
@ -42,7 +43,7 @@ struct PlayerInput {
struct ScalerParameters { struct ScalerParameters {
ScalerType type; ScalerType type;
const Scaler *scaler; char name[32];
int factor; int factor;
static ScalerParameters defaults(); static ScalerParameters defaults();
@ -55,7 +56,7 @@ struct SystemStub {
virtual ~SystemStub() {} virtual ~SystemStub() {}
virtual void init(const char *title, int w, int h, bool fullscreen, int widescreenMode, ScalerParameters *scalerParameters) = 0; virtual void init(const char *title, int w, int h, bool fullscreen, int widescreenMode, const ScalerParameters *scalerParameters) = 0;
virtual void destroy() = 0; virtual void destroy() = 0;
virtual bool hasWidescreen() const = 0; virtual bool hasWidescreen() const = 0;

View File

@ -1,4 +1,3 @@
/* /*
* REminiscence - Flashback interpreter * REminiscence - Flashback interpreter
* Copyright (C) 2005-2019 Gregory Montoir (cyx@users.sourceforge.net) * Copyright (C) 2005-2019 Gregory Montoir (cyx@users.sourceforge.net)
@ -22,7 +21,7 @@ static const uint32_t kPixelFormat = SDL_PIXELFORMAT_RGB888;
ScalerParameters ScalerParameters::defaults() { ScalerParameters ScalerParameters::defaults() {
ScalerParameters params; ScalerParameters params;
params.type = kScalerTypeInternal; params.type = kScalerTypeInternal;
params.scaler = &_internalScaler; params.name[0] = 0;
params.factor = _internalScaler.factorMin + (_internalScaler.factorMax - _internalScaler.factorMin) / 2; params.factor = _internalScaler.factorMin + (_internalScaler.factorMax - _internalScaler.factorMin) / 2;
return params; return params;
} }
@ -47,15 +46,16 @@ struct SystemStub_SDL : SystemStub {
void *_audioCbData; void *_audioCbData;
int _screenshot; int _screenshot;
ScalerType _scalerType; ScalerType _scalerType;
const Scaler *_scaler;
int _scaleFactor; int _scaleFactor;
const Scaler *_scaler;
void *_scalerSo;
int _widescreenMode; int _widescreenMode;
SDL_Texture *_widescreenTexture; SDL_Texture *_widescreenTexture;
int _wideMargin; int _wideMargin;
bool _enableWidescreen; bool _enableWidescreen;
virtual ~SystemStub_SDL() {} virtual ~SystemStub_SDL() {}
virtual void init(const char *title, int w, int h, bool fullscreen, int widescreenMode, ScalerParameters *scalerParameters); virtual void init(const char *title, int w, int h, bool fullscreen, int widescreenMode, const ScalerParameters *scalerParameters);
virtual void destroy(); virtual void destroy();
virtual bool hasWidescreen() const; virtual bool hasWidescreen() const;
virtual void setScreenSize(int w, int h); virtual void setScreenSize(int w, int h);
@ -88,7 +88,8 @@ 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 setScaler(const ScalerParameters *parameters);
void changeScaler(int scalerNum);
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);
}; };
@ -96,7 +97,7 @@ SystemStub *SystemStub_SDL_create() {
return new SystemStub_SDL(); return new SystemStub_SDL();
} }
void SystemStub_SDL::init(const char *title, int w, int h, bool fullscreen, int widescreenMode, ScalerParameters *scalerParameters) { void SystemStub_SDL::init(const char *title, int w, int h, bool fullscreen, int widescreenMode, const ScalerParameters *scalerParameters) {
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK); SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK);
SDL_ShowCursor(SDL_DISABLE); SDL_ShowCursor(SDL_DISABLE);
_caption = title; _caption = title;
@ -108,9 +109,13 @@ void SystemStub_SDL::init(const char *title, int w, int h, bool fullscreen, int
_screenBuffer = 0; _screenBuffer = 0;
_fadeOnUpdateScreen = false; _fadeOnUpdateScreen = false;
_fullscreen = fullscreen; _fullscreen = fullscreen;
_scalerType = scalerParameters->type; _scalerType = kScalerTypeInternal;
_scaler = scalerParameters->scaler; _scaleFactor = 1;
_scaleFactor = _scaler ? CLIP(scalerParameters->factor, _scaler->factorMin, _scaler->factorMax) : 1; _scaler = 0;
_scalerSo = 0;
if (scalerParameters->name[0]) {
setScaler(scalerParameters);
}
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;
@ -143,6 +148,10 @@ void SystemStub_SDL::destroy() {
SDL_FreeFormat(_fmt); SDL_FreeFormat(_fmt);
_fmt = 0; _fmt = 0;
} }
if (_scalerSo) {
SDL_UnloadObject(_scalerSo);
_scalerSo = 0;
}
if (_controller) { if (_controller) {
SDL_GameControllerClose(_controller); SDL_GameControllerClose(_controller);
_controller = 0; _controller = 0;
@ -352,46 +361,107 @@ void SystemStub_SDL::copyWidescreenMirror(int w, int h, const uint8_t *buf) {
} }
} }
static uint32_t blurPixel(int x, int y, const uint8_t *src, const uint32_t *pal, int pitch, int w, int h, const SDL_PixelFormat *fmt) { static void blur_h(int radius, const uint32_t *src, int srcPitch, int w, int h, const SDL_PixelFormat *fmt, uint32_t *dst, int dstPitch) {
static const uint8_t blurMat[3 * 3] = {
2, 4, 2,
4, 8, 4,
2, 4, 2
};
static const int blurMatSigma = 32 * 2;
const uint32_t redBlueMask = fmt->Rmask | fmt->Bmask; const int count = 2 * radius + 1;
const uint32_t greenMask = fmt->Gmask;
uint32_t redBlueBlurSum = 0; for (int y = 0; y < h; ++y) {
uint32_t greenBlurSum = 0;
for (int v = 0; v < 3; ++v) { uint32_t r = 0;
const int ym = CLIP(y + v - 1, 0, h - 1); uint32_t g = 0;
for (int u = 0; u < 3; ++u) { uint32_t b = 0;
const int xm = CLIP(x + u - 1, 0, w - 1);
const uint32_t color = pal[src[ym * pitch + xm]]; uint32_t color;
const int mul = blurMat[v * 3 + u];
redBlueBlurSum += (color & redBlueMask) * mul; for (int x = -radius; x <= radius; ++x) {
greenBlurSum += (color & greenMask) * mul; color = src[MAX(x, 0)];
r += (color & fmt->Rmask) >> fmt->Rshift;
g += (color & fmt->Gmask) >> fmt->Gshift;
b += (color & fmt->Bmask) >> fmt->Bshift;
} }
dst[0] = ((r / count) << fmt->Rshift) | ((g / count) << fmt->Gshift) | ((b / count) << fmt->Bshift);
for (int x = 1; x < w; ++x) {
color = src[MIN(x + radius, w - 1)];
r += (color & fmt->Rmask) >> fmt->Rshift;
g += (color & fmt->Gmask) >> fmt->Gshift;
b += (color & fmt->Bmask) >> fmt->Bshift;
color = src[MAX(x - radius - 1, 0)];
r -= (color & fmt->Rmask) >> fmt->Rshift;
g -= (color & fmt->Gmask) >> fmt->Gshift;
b -= (color & fmt->Bmask) >> fmt->Bshift;
dst[x] = ((r / count) << fmt->Rshift) | ((g / count) << fmt->Gshift) | ((b / count) << fmt->Bshift);
}
src += srcPitch;
dst += dstPitch;
}
}
static void blur_v(int radius, const uint32_t *src, int srcPitch, int w, int h, const SDL_PixelFormat *fmt, uint32_t *dst, int dstPitch) {
const int count = 2 * radius + 1;
for (int x = 0; x < w; ++x) {
uint32_t r = 0;
uint32_t g = 0;
uint32_t b = 0;
uint32_t color;
for (int y = -radius; y <= radius; ++y) {
color = src[MAX(y, 0) * srcPitch];
r += (color & fmt->Rmask) >> fmt->Rshift;
g += (color & fmt->Gmask) >> fmt->Gshift;
b += (color & fmt->Bmask) >> fmt->Bshift;
}
dst[0] = ((r / count) << fmt->Rshift) | ((g / count) << fmt->Gshift) | ((b / count) << fmt->Bshift);
for (int y = 1; y < h; ++y) {
color = src[MIN(y + radius, h - 1) * srcPitch];
r += (color & fmt->Rmask) >> fmt->Rshift;
g += (color & fmt->Gmask) >> fmt->Gshift;
b += (color & fmt->Bmask) >> fmt->Bshift;
color = src[MAX(y - radius - 1, 0) * srcPitch];
r -= (color & fmt->Rmask) >> fmt->Rshift;
g -= (color & fmt->Gmask) >> fmt->Gshift;
b -= (color & fmt->Bmask) >> fmt->Bshift;
dst[y * dstPitch] = ((r / count) << fmt->Rshift) | ((g / count) << fmt->Gshift) | ((b / count) << fmt->Bshift);
}
++src;
++dst;
} }
return ((redBlueBlurSum / blurMatSigma) & redBlueMask) | ((greenBlurSum / blurMatSigma) & greenMask);
} }
void SystemStub_SDL::copyWidescreenBlur(int w, int h, const uint8_t *buf) { void SystemStub_SDL::copyWidescreenBlur(int w, int h, const uint8_t *buf) {
assert(w == _screenW && h == _screenH); assert(w == _screenW && h == _screenH);
void *dst = 0; void *ptr = 0;
int pitch = 0; int pitch = 0;
if (SDL_LockTexture(_widescreenTexture, 0, &dst, &pitch) == 0) { if (SDL_LockTexture(_widescreenTexture, 0, &ptr, &pitch) == 0) {
assert((pitch & 3) == 0); assert((pitch & 3) == 0);
uint32_t *p = (uint32_t *)dst;
for (int y = 0; y < h; ++y) { uint32_t *src = (uint32_t *)malloc(w * h * sizeof(uint32_t));
for (int x = 0; x < w; ++x) { uint32_t *tmp = (uint32_t *)malloc(w * h * sizeof(uint32_t));
p[x] = blurPixel(x, y, buf, _rgbPalette, w, w, h, _fmt); uint32_t *dst = (uint32_t *)ptr;
if (src && tmp) {
for (int i = 0; i < w * h; ++i) {
src[i] = _rgbPalette[buf[i]];
} }
p += pitch / sizeof(uint32_t); static const int radius = 8;
blur_h(radius, src, w, w, h, _fmt, tmp, w);
blur_v(radius, tmp, w, w, h, _fmt, dst, pitch / sizeof(uint32_t));
} }
free(src);
free(tmp);
SDL_UnlockTexture(_widescreenTexture); SDL_UnlockTexture(_widescreenTexture);
} }
} }
@ -476,6 +546,23 @@ void SystemStub_SDL::processEvents() {
} }
} }
// only used for the protection codes and level passwords
static void setAsciiChar(PlayerInput &pi, const SDL_Keysym *key) {
if (key->sym >= SDLK_0 && key->sym <= SDLK_9) {
pi.lastChar = '0' + key->sym - SDLK_0;
} else if (key->sym >= SDLK_a && key->sym <= SDLK_z) {
pi.lastChar = 'A' + key->sym - SDLK_a;
} else if (key->scancode == SDL_SCANCODE_0) {
pi.lastChar = '0';
} else if (key->scancode >= SDL_SCANCODE_1 && key->scancode <= SDL_SCANCODE_9) {
pi.lastChar = '1' + key->scancode - SDL_SCANCODE_1;
} else if (key->sym == SDLK_SPACE || key->sym == SDLK_KP_SPACE) {
pi.lastChar = ' ';
} else {
pi.lastChar = 0;
}
}
void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) { void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
switch (ev.type) { switch (ev.type) {
case SDL_QUIT: case SDL_QUIT:
@ -681,6 +768,9 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
case SDLK_l: case SDLK_l:
_pi.load = true; _pi.load = true;
break; break;
case SDLK_r:
_pi.rewind = true;
break;
case SDLK_KP_PLUS: case SDLK_KP_PLUS:
case SDLK_PAGEUP: case SDLK_PAGEUP:
_pi.stateSlot = 1; _pi.stateSlot = 1;
@ -692,7 +782,7 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
} }
break; break;
} }
_pi.lastChar = ev.key.keysym.sym; setAsciiChar(_pi, &ev.key.keysym);
switch (ev.key.keysym.sym) { switch (ev.key.keysym.sym) {
case SDLK_LEFT: case SDLK_LEFT:
_pi.dirMask &= ~PlayerInput::DIR_LEFT; _pi.dirMask &= ~PlayerInput::DIR_LEFT;
@ -917,39 +1007,97 @@ void SystemStub_SDL::changeGraphics(bool fullscreen, int scaleFactor) {
prepareGraphics(); prepareGraphics();
} }
void SystemStub_SDL::changeScaler(int scaler) { void SystemStub_SDL::setScaler(const ScalerParameters *parameters) {
ScalerParameters scalerParameters = ScalerParameters::defaults(); static const struct {
switch (scaler) { const char *name;
int type;
const Scaler *scaler;
} scalers[] = {
{ "point", kScalerTypePoint, 0 },
{ "linear", kScalerTypeLinear, 0 },
{ "scale", kScalerTypeInternal, &_internalScaler },
#ifdef USE_STATIC_SCALER
{ "nearest", kScalerTypeInternal, &scaler_nearest },
{ "tv2x", kScalerTypeInternal, &scaler_tv2x },
{ "xbr", kScalerTypeInternal, &scaler_xbr },
#endif
{ 0, -1 }
};
bool found = false;
for (int i = 0; scalers[i].name; ++i) {
if (strcmp(scalers[i].name, parameters->name) == 0) {
_scalerType = (ScalerType)scalers[i].type;
_scaler = scalers[i].scaler;
found = true;
break;
}
}
if (!found) {
#ifdef _WIN32
static const char *libSuffix = "dll";
#else
static const char *libSuffix = "so";
#endif
char libname[64];
snprintf(libname, sizeof(libname), "scaler_%s.%s", parameters->name, libSuffix);
_scalerSo = SDL_LoadObject(libname);
if (!_scalerSo) {
warning("Scaler '%s' not found, using default", libname);
} else {
static const char *kSoSym = "getScaler";
void *symbol = SDL_LoadFunction(_scalerSo, kSoSym);
if (!symbol) {
warning("Symbol '%s' not found in '%s'", kSoSym, libname);
} else {
typedef const Scaler *(*GetScalerProc)();
const Scaler *scaler = ((GetScalerProc)symbol)();
const int tag = scaler ? scaler->tag : 0;
if (tag != SCALER_TAG) {
warning("Unexpected tag %d for scaler '%s'", tag, libname);
} else {
_scalerType = kScalerTypeExternal;
_scaler = scaler;
}
}
}
}
_scaleFactor = _scaler ? CLIP(parameters->factor, _scaler->factorMin, _scaler->factorMax) : 1;
}
void SystemStub_SDL::changeScaler(int scalerNum) {
ScalerType type = kScalerTypeInternal;
const Scaler *scaler = 0;
switch (scalerNum) {
case 0: case 0:
scalerParameters.type = kScalerTypePoint; type = kScalerTypePoint;
break; break;
case 1: case 1:
scalerParameters.type = kScalerTypeLinear; type = kScalerTypeLinear;
break; break;
case 2: case 2:
scalerParameters.type = kScalerTypeInternal; type = kScalerTypeInternal;
scalerParameters.scaler = &_internalScaler; scaler = &_internalScaler;
break; break;
#ifdef USE_STATIC_SCALER #ifdef USE_STATIC_SCALER
case 3: case 3:
scalerParameters.type = kScalerTypeInternal; type = kScalerTypeInternal;
scalerParameters.scaler = &scaler_nearest; scaler = &scaler_nearest;
break; break;
case 4: case 4:
scalerParameters.type = kScalerTypeInternal; type = kScalerTypeInternal;
scalerParameters.scaler = &scaler_tv2x; scaler = &scaler_tv2x;
break; break;
case 5: case 5:
scalerParameters.type = kScalerTypeInternal; type = kScalerTypeInternal;
scalerParameters.scaler = &scaler_xbr; scaler = &scaler_xbr;
break; break;
#endif #endif
default: default:
return; return;
} }
if (_scalerType != scalerParameters.type || scalerParameters.scaler != _scaler) { if (_scalerType != type || scaler != _scaler) {
_scalerType = scalerParameters.type; _scalerType = type;
_scaler = scalerParameters.scaler; _scaler = scaler;
if (_scalerType == kScalerTypeInternal || _scalerType == kScalerTypeExternal) { if (_scalerType == kScalerTypeInternal || _scalerType == kScalerTypeExternal) {
_scaleFactor = CLIP(_scaleFactor, _scaler->factorMin, _scaler->factorMax); _scaleFactor = CLIP(_scaleFactor, _scaler->factorMin, _scaler->factorMax);
} else { } else {

View File

@ -16,52 +16,48 @@ struct UnpackCtx {
}; };
static bool nextBit(UnpackCtx *uc) { static bool nextBit(UnpackCtx *uc) {
bool carry = (uc->bits & 1) != 0; bool bit = (uc->bits & 1) != 0;
uc->bits >>= 1; uc->bits >>= 1;
if (uc->bits == 0) { // getnextlwd if (uc->bits == 0) { // getnextlwd
uc->bits = READ_BE_UINT32(uc->src); uc->src -= 4; const uint32_t bits = READ_BE_UINT32(uc->src); uc->src -= 4;
uc->crc ^= uc->bits; uc->crc ^= bits;
carry = (uc->bits & 1) != 0; bit = (bits & 1) != 0;
uc->bits = (1 << 31) | (uc->bits >> 1); uc->bits = (1 << 31) | (bits >> 1);
} }
return carry; return bit;
} }
static int getBits(UnpackCtx *uc, int count) { // rdd1bits template<int count>
int bits = 0; static uint32_t getBits(UnpackCtx *uc) { // rdd1bits
uint32_t bits = 0;
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
bits <<= 1; bits |= (nextBit(uc) ? 1 : 0) << (count - 1 - i);
if (nextBit(uc)) {
bits |= 1;
}
} }
return bits; return bits;
} }
static void copyLiteral(UnpackCtx *uc, int bitsCount, int len) { // getd3chr static void copyLiteral(UnpackCtx *uc, int len) { // getd3chr
int count = getBits(uc, bitsCount) + len + 1; uc->size -= len;
uc->size -= count;
if (uc->size < 0) { if (uc->size < 0) {
count += uc->size; len += uc->size;
uc->size = 0; uc->size = 0;
} }
for (int i = 0; i < count; ++i) { for (int i = 0; i < len; ++i) {
*(uc->dst - i) = (uint8_t)getBits(uc, 8); *(uc->dst - i) = (uint8_t)getBits<8>(uc);
} }
uc->dst -= count; uc->dst -= len;
} }
static void copyReference(UnpackCtx *uc, int bitsCount, int count) { // copyd3bytes static void copyReference(UnpackCtx *uc, int len, int offset) { // copyd3bytes
uc->size -= count; uc->size -= len;
if (uc->size < 0) { if (uc->size < 0) {
count += uc->size; len += uc->size;
uc->size = 0; uc->size = 0;
} }
const int offset = getBits(uc, bitsCount); for (int i = 0; i < len; ++i) {
for (int i = 0; i < count; ++i) {
*(uc->dst - i) = *(uc->dst - i + offset); *(uc->dst - i) = *(uc->dst - i + offset);
} }
uc->dst -= count; uc->dst -= len;
} }
bool bytekiller_unpack(uint8_t *dst, int dstSize, const uint8_t *src, int srcSize) { bool bytekiller_unpack(uint8_t *dst, int dstSize, const uint8_t *src, int srcSize) {
@ -79,24 +75,26 @@ bool bytekiller_unpack(uint8_t *dst, int dstSize, const uint8_t *src, int srcSiz
do { do {
if (!nextBit(&uc)) { if (!nextBit(&uc)) {
if (!nextBit(&uc)) { if (!nextBit(&uc)) {
copyLiteral(&uc, 3, 0); copyLiteral(&uc, getBits<3>(&uc) + 1);
} else { } else {
copyReference(&uc, 8, 2); copyReference(&uc, 2, getBits<8>(&uc));
} }
} else { } else {
const int code = getBits(&uc, 2); const int code = getBits<2>(&uc);
switch (code) { switch (code) {
case 3: case 3:
copyLiteral(&uc, 8, 8); copyLiteral(&uc, getBits<8>(&uc) + 9);
break; break;
case 2: case 2: {
copyReference(&uc, 12, getBits(&uc, 8) + 1); const int len = getBits<8>(&uc) + 1;
copyReference(&uc, len, getBits<12>(&uc));
}
break; break;
case 1: case 1:
copyReference(&uc, 10, 4); copyReference(&uc, 4, getBits<10>(&uc));
break; break;
case 0: case 0:
copyReference(&uc, 9, 3); copyReference(&uc, 3, getBits<9>(&uc));
break; break;
} }
} }