Import 0.4.6
This commit is contained in:
parent
86baaa3a9a
commit
2dc61ca627
10
CHANGES.txt
10
CHANGES.txt
|
@ -1,3 +1,7 @@
|
|||
* release 0.4.6
|
||||
- added rewind to automatic saves
|
||||
- fixed passwords and protection codes input
|
||||
|
||||
* release 0.4.5
|
||||
- added low-pass filtering for in-game music
|
||||
- added support for 3DO background music (tunes/*.Cpc)
|
||||
|
@ -72,7 +76,7 @@
|
|||
|
||||
* release 0.2.2
|
||||
- added support for level background music
|
||||
- added italian texts
|
||||
- added Italian texts
|
||||
- fixed PC-CD SEQ cutscenes numbering
|
||||
- fixed several issues with Amiga data files
|
||||
|
||||
|
@ -111,7 +115,7 @@
|
|||
- added input keys recording
|
||||
- reduced memory usage
|
||||
|
||||
* release 0.2.0 (2005/04/02)
|
||||
* release 0.1.4 (2005/04/02)
|
||||
- added screen shaking (level 2)
|
||||
- added support for Amiga music (experimental)
|
||||
- fixed screen refresh after teleportation
|
||||
|
@ -127,7 +131,7 @@
|
|||
- added sound effects playback
|
||||
- added support for polygonal cutscenes
|
||||
- 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)
|
||||
- added missing opcodes, game should now be completable
|
||||
|
|
8
Makefile
8
Makefile
|
@ -2,24 +2,22 @@
|
|||
SDL_CFLAGS := `sdl2-config --cflags`
|
||||
SDL_LIBS := `sdl2-config --libs`
|
||||
|
||||
DL_LIBS := -ldl
|
||||
MODPLUG_LIBS := -lmodplug
|
||||
TREMOR_LIBS := -lvorbisidec -logg
|
||||
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 \
|
||||
resource_mac.cpp scaler.cpp screenshot.cpp seq_player.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)
|
||||
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)
|
||||
$(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
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
|
||||
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
|
||||
'--scaler xbrz@2' to use that algorithm with a doubled window size (512x448).
|
||||
shall be used as the name. Eg. If you have scaler_xbr.dll, you can pass
|
||||
'--scaler xbr@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
|
||||
|
@ -69,6 +69,7 @@ In-game hotkeys :
|
|||
Alt S write screenshot as .tga
|
||||
Ctrl S save game state
|
||||
Ctrl L load game state
|
||||
Ctrl R rewind game state buffer (requires --autosave)
|
||||
Ctrl + and - change game state slot
|
||||
Function Keys change game screen scaler
|
||||
|
||||
|
|
|
@ -410,8 +410,8 @@ void Cutscene::op_setPalette() {
|
|||
}
|
||||
}
|
||||
|
||||
void Cutscene::op_drawStringAtBottom() {
|
||||
debug(DBG_CUT, "Cutscene::op_drawStringAtBottom()");
|
||||
void Cutscene::op_drawCaptionText() {
|
||||
debug(DBG_CUT, "Cutscene::op_drawCaptionText()");
|
||||
uint16_t strId = fetchNextCmdWord();
|
||||
if (!_creditsSequence) {
|
||||
|
||||
|
@ -1036,7 +1036,7 @@ bool Cutscene::load(uint16_t cutName) {
|
|||
//
|
||||
uint8_t *p = _res->_cmd + 0x322;
|
||||
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[2] = 0x3a;
|
||||
p[3] = 0x00; // op_markCurPos
|
||||
|
|
|
@ -128,7 +128,7 @@ struct Cutscene {
|
|||
void op_waitForSync();
|
||||
void op_drawShape();
|
||||
void op_setPalette();
|
||||
void op_drawStringAtBottom();
|
||||
void op_drawCaptionText();
|
||||
void op_nop();
|
||||
void op_skip3();
|
||||
void op_refreshAll();
|
||||
|
|
59
dynlib.cpp
59
dynlib.cpp
|
@ -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);
|
||||
}
|
16
dynlib.h
16
dynlib.h
|
@ -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__
|
61
file.cpp
61
file.cpp
|
@ -197,6 +197,58 @@ struct AssetFile: File_impl {
|
|||
};
|
||||
#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()
|
||||
: _impl(0) {
|
||||
}
|
||||
|
@ -264,6 +316,15 @@ bool File::open(const char *filename, const char *mode, const char *directory) {
|
|||
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() {
|
||||
if (_impl) {
|
||||
_impl->close();
|
||||
|
|
1
file.h
1
file.h
|
@ -20,6 +20,7 @@ struct File {
|
|||
|
||||
bool open(const char *filename, const char *mode, FileSystem *fs);
|
||||
bool open(const char *filename, const char *mode, const char *directory);
|
||||
void openMemoryBuffer(int initialCapacity);
|
||||
void close();
|
||||
bool ioErr() const;
|
||||
uint32_t size();
|
||||
|
|
76
game.cpp
76
game.cpp
|
@ -25,6 +25,8 @@ Game::Game(SystemStub *stub, FileSystem *fs, const char *savePath, int level, Re
|
|||
_demoBin = -1;
|
||||
_widescreenMode = widescreenMode;
|
||||
_autoSave = autoSave;
|
||||
_rewindPtr = -1;
|
||||
_rewindLen = 0;
|
||||
}
|
||||
|
||||
void Game::run() {
|
||||
|
@ -159,6 +161,7 @@ void Game::run() {
|
|||
_vid._unkPalSlot1 = 0;
|
||||
_vid._unkPalSlot2 = 0;
|
||||
_score = 0;
|
||||
clearStateRewind();
|
||||
loadLevelData();
|
||||
resetGameState();
|
||||
_endLoop = false;
|
||||
|
@ -195,7 +198,7 @@ void Game::displayTitleScreenAmiga() {
|
|||
if (!buf) {
|
||||
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,
|
||||
0x751, 0x455, 0x665, 0x268, 0x961, 0x478, 0x677, 0x786,
|
||||
0x17B, 0x788, 0xB84, 0xC92, 0x49C, 0xF00, 0x9A8, 0x9AA,
|
||||
|
@ -384,11 +387,12 @@ void Game::mainLoop() {
|
|||
playCutscene(0x41);
|
||||
_endLoop = true;
|
||||
} else {
|
||||
if (_autoSave && loadGameState(kAutoSaveSlot)) {
|
||||
if (_autoSave && _rewindLen != 0 && loadGameState(kAutoSaveSlot)) {
|
||||
// autosave
|
||||
} else if (_validSaveState && loadGameState(kIngameSaveSlot)) {
|
||||
// ingame save
|
||||
} else {
|
||||
clearStateRewind();
|
||||
loadLevelData();
|
||||
resetGameState();
|
||||
}
|
||||
|
@ -453,9 +457,9 @@ void Game::mainLoop() {
|
|||
}
|
||||
}
|
||||
inp_handleSpecialKeys();
|
||||
if (_stub->getTimeStamp() - _saveTimestamp >= kAutoSaveIntervalMs) {
|
||||
// do not save if we just died
|
||||
if (_pgeLive[0].life > 0) {
|
||||
if (_autoSave && _stub->getTimeStamp() - _saveTimestamp >= kAutoSaveIntervalMs) {
|
||||
// do not save if we died or about to
|
||||
if (_pgeLive[0].life > 0 && _deathCutsceneCounter == 0) {
|
||||
saveGameState(kAutoSaveSlot);
|
||||
_saveTimestamp = _stub->getTimeStamp();
|
||||
}
|
||||
|
@ -594,6 +598,14 @@ void Game::inp_handleSpecialKeys() {
|
|||
}
|
||||
_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() {
|
||||
|
@ -1817,6 +1829,7 @@ uint16_t Game::getRandomNumber() {
|
|||
|
||||
void Game::changeLevel() {
|
||||
_vid.fadeOut();
|
||||
clearStateRewind();
|
||||
loadLevelData();
|
||||
loadLevelMap();
|
||||
_vid.setPalette0xF();
|
||||
|
@ -1981,6 +1994,9 @@ void Game::makeGameStateName(uint8_t slot, char *buf) {
|
|||
static const uint32_t TAG_FBSV = 0x46425356;
|
||||
|
||||
bool Game::saveGameState(uint8_t slot) {
|
||||
if (slot == kAutoSaveSlot) {
|
||||
return saveStateRewind();
|
||||
}
|
||||
bool success = false;
|
||||
char stateFile[32];
|
||||
makeGameStateName(slot, stateFile);
|
||||
|
@ -2008,6 +2024,9 @@ bool Game::saveGameState(uint8_t slot) {
|
|||
}
|
||||
|
||||
bool Game::loadGameState(uint8_t slot) {
|
||||
if (slot == kAutoSaveSlot) {
|
||||
return loadStateRewind();
|
||||
}
|
||||
bool success = false;
|
||||
char stateFile[32];
|
||||
makeGameStateName(slot, stateFile);
|
||||
|
@ -2177,6 +2196,53 @@ void Game::loadState(File *f) {
|
|||
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) {
|
||||
debug(DBG_GAME, "AnimBuffers::addState() stateNum=%d x=%d y=%d dataPtr=%p pge=%p", stateNum, x, y, dataPtr, pge);
|
||||
assert(stateNum < 4);
|
||||
|
|
8
game.h
8
game.h
|
@ -27,8 +27,9 @@ struct Game {
|
|||
|
||||
enum {
|
||||
kIngameSaveSlot = 0,
|
||||
kRewindSize = 120, // 10mins (~2MB)
|
||||
kAutoSaveSlot = 255,
|
||||
kAutoSaveIntervalMs = 120 * 1000
|
||||
kAutoSaveIntervalMs = 5 * 1000
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -68,6 +69,8 @@ struct Game {
|
|||
SystemStub *_stub;
|
||||
FileSystem *_fs;
|
||||
const char *_savePath;
|
||||
File _rewindBuffer[kRewindSize];
|
||||
int _rewindPtr, _rewindLen;
|
||||
|
||||
const uint8_t *_stringsTable;
|
||||
const char **_textsTable;
|
||||
|
@ -384,6 +387,9 @@ struct Game {
|
|||
bool loadGameState(uint8_t slot);
|
||||
void saveState(File *f);
|
||||
void loadState(File *f);
|
||||
void clearStateRewind();
|
||||
bool saveStateRewind();
|
||||
bool loadStateRewind();
|
||||
};
|
||||
|
||||
#endif // GAME_H__
|
||||
|
|
41
main.cpp
41
main.cpp
|
@ -156,50 +156,13 @@ static void initOptions() {
|
|||
}
|
||||
|
||||
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, '@');
|
||||
if (sep) {
|
||||
*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);
|
||||
}
|
||||
strncpy(scalerParameters->name, name, sizeof(scalerParameters->name) - 1);
|
||||
scalerParameters->name[sizeof(scalerParameters->name) - 1] = 0;
|
||||
}
|
||||
|
||||
static WidescreenMode parseWidescreen(const char *mode) {
|
||||
|
|
3
menu.cpp
3
menu.cpp
|
@ -212,9 +212,6 @@ bool Menu::handlePasswordScreen() {
|
|||
if (c != 0) {
|
||||
_stub->_pi.lastChar = 0;
|
||||
if (len < 6) {
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
c &= ~0x20;
|
||||
}
|
||||
if ((c >= 'A' && c <= 'Z') || (c == 0x20)) {
|
||||
password[len] = c;
|
||||
++len;
|
||||
|
|
|
@ -9,13 +9,11 @@
|
|||
#include "systemstub.h"
|
||||
|
||||
static uint8_t reverseBits(uint8_t ch) {
|
||||
uint8_t r = 0;
|
||||
for (int b = 0; b < 8; ++b) {
|
||||
if (ch & (1 << b)) {
|
||||
r |= (1 << (7 - b));
|
||||
}
|
||||
}
|
||||
return r;
|
||||
static const uint8_t lut[] = {
|
||||
0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
|
||||
0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF
|
||||
};
|
||||
return (lut[ch & 15] << 4) | lut[ch >> 4];
|
||||
}
|
||||
|
||||
static uint8_t decryptChar(uint8_t ch) {
|
||||
|
@ -114,9 +112,6 @@ bool Game::handleProtectionScreenShape() {
|
|||
if (c != 0) {
|
||||
_stub->_pi.lastChar = 0;
|
||||
if (len < kCodeLen) {
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
c &= ~0x20;
|
||||
}
|
||||
if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) {
|
||||
codeText[len] = c;
|
||||
++len;
|
||||
|
@ -201,7 +196,7 @@ bool Game::handleProtectionScreenWords() {
|
|||
const uint8_t code = getRandomNumber() % kWordsCount;
|
||||
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);
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "PAGE %d", protectionData[0]);
|
||||
|
@ -229,9 +224,6 @@ bool Game::handleProtectionScreenWords() {
|
|||
if (c != 0) {
|
||||
_stub->_pi.lastChar = 0;
|
||||
if (len < kCodeLen) {
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
c &= ~0x20;
|
||||
}
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
codeText[len] = c;
|
||||
++len;
|
||||
|
|
|
@ -15,6 +15,10 @@ ResourceAba::~ResourceAba() {
|
|||
free(_entries);
|
||||
}
|
||||
|
||||
static int compareAbaEntry(const void *a, const void *b) {
|
||||
return strcasecmp(((ResourceAbaEntry *)a)->name, ((ResourceAbaEntry *)b)->name);
|
||||
}
|
||||
|
||||
void ResourceAba::readEntries() {
|
||||
if (_f.open(FILENAME, "rb", _fs)) {
|
||||
_entriesCount = _f.readUint16BE();
|
||||
|
@ -39,16 +43,14 @@ void ResourceAba::readEntries() {
|
|||
}
|
||||
nextOffset = _entries[i].offset + _entries[i].compressedSize;
|
||||
}
|
||||
qsort(_entries, _entriesCount, sizeof(ResourceAbaEntry), compareAbaEntry);
|
||||
}
|
||||
}
|
||||
|
||||
const ResourceAbaEntry *ResourceAba::findEntry(const char *name) const {
|
||||
for (int i = 0; i < _entriesCount; ++i) {
|
||||
if (strcasecmp(_entries[i].name, name) == 0) {
|
||||
return &_entries[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
ResourceAbaEntry tmp;
|
||||
strcpy(tmp.name, name);
|
||||
return (const ResourceAbaEntry *)bsearch(&tmp, _entries, _entriesCount, sizeof(ResourceAbaEntry), compareAbaEntry);
|
||||
}
|
||||
|
||||
uint8_t *ResourceAba::loadEntry(const char *name, uint32_t *size) {
|
||||
|
|
15
scaler.cpp
15
scaler.cpp
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
|
||||
#include "scaler.h"
|
||||
#include "dynlib.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) {
|
||||
|
@ -282,17 +281,3 @@ const Scaler _internalScaler = {
|
|||
2, 4,
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ void SeqDemuxer::close() {
|
|||
for (int i = 0; i < kBuffersCount; ++i) {
|
||||
free(_buffers[i].data);
|
||||
}
|
||||
memset(_buffers, 0, sizeof(_buffers));
|
||||
}
|
||||
|
||||
bool SeqDemuxer::readHeader() {
|
||||
|
|
|
@ -17,7 +17,7 @@ const Cutscene::OpcodeStub Cutscene::_opcodeTable[] = {
|
|||
/* 0x04 */
|
||||
&Cutscene::op_setPalette,
|
||||
&Cutscene::op_markCurPos,
|
||||
&Cutscene::op_drawStringAtBottom,
|
||||
&Cutscene::op_drawCaptionText,
|
||||
&Cutscene::op_nop,
|
||||
/* 0x08 */
|
||||
&Cutscene::op_skip3,
|
||||
|
|
|
@ -35,6 +35,7 @@ struct PlayerInput {
|
|||
bool save;
|
||||
bool load;
|
||||
int stateSlot;
|
||||
bool rewind;
|
||||
|
||||
uint8_t dbgMask;
|
||||
bool quit;
|
||||
|
@ -42,7 +43,7 @@ struct PlayerInput {
|
|||
|
||||
struct ScalerParameters {
|
||||
ScalerType type;
|
||||
const Scaler *scaler;
|
||||
char name[32];
|
||||
int factor;
|
||||
|
||||
static ScalerParameters defaults();
|
||||
|
@ -55,7 +56,7 @@ struct 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 bool hasWidescreen() const = 0;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
/*
|
||||
* REminiscence - Flashback interpreter
|
||||
* 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 params;
|
||||
params.type = kScalerTypeInternal;
|
||||
params.scaler = &_internalScaler;
|
||||
params.name[0] = 0;
|
||||
params.factor = _internalScaler.factorMin + (_internalScaler.factorMax - _internalScaler.factorMin) / 2;
|
||||
return params;
|
||||
}
|
||||
|
@ -47,15 +46,16 @@ struct SystemStub_SDL : SystemStub {
|
|||
void *_audioCbData;
|
||||
int _screenshot;
|
||||
ScalerType _scalerType;
|
||||
const Scaler *_scaler;
|
||||
int _scaleFactor;
|
||||
const Scaler *_scaler;
|
||||
void *_scalerSo;
|
||||
int _widescreenMode;
|
||||
SDL_Texture *_widescreenTexture;
|
||||
int _wideMargin;
|
||||
bool _enableWidescreen;
|
||||
|
||||
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 bool hasWidescreen() const;
|
||||
virtual void setScreenSize(int w, int h);
|
||||
|
@ -88,7 +88,8 @@ struct SystemStub_SDL : SystemStub {
|
|||
void prepareGraphics();
|
||||
void cleanupGraphics();
|
||||
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);
|
||||
};
|
||||
|
||||
|
@ -96,7 +97,7 @@ SystemStub *SystemStub_SDL_create() {
|
|||
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_ShowCursor(SDL_DISABLE);
|
||||
_caption = title;
|
||||
|
@ -108,9 +109,13 @@ void SystemStub_SDL::init(const char *title, int w, int h, bool fullscreen, int
|
|||
_screenBuffer = 0;
|
||||
_fadeOnUpdateScreen = false;
|
||||
_fullscreen = fullscreen;
|
||||
_scalerType = scalerParameters->type;
|
||||
_scaler = scalerParameters->scaler;
|
||||
_scaleFactor = _scaler ? CLIP(scalerParameters->factor, _scaler->factorMin, _scaler->factorMax) : 1;
|
||||
_scalerType = kScalerTypeInternal;
|
||||
_scaleFactor = 1;
|
||||
_scaler = 0;
|
||||
_scalerSo = 0;
|
||||
if (scalerParameters->name[0]) {
|
||||
setScaler(scalerParameters);
|
||||
}
|
||||
memset(_rgbPalette, 0, sizeof(_rgbPalette));
|
||||
memset(_darkPalette, 0, sizeof(_darkPalette));
|
||||
_screenW = _screenH = 0;
|
||||
|
@ -143,6 +148,10 @@ void SystemStub_SDL::destroy() {
|
|||
SDL_FreeFormat(_fmt);
|
||||
_fmt = 0;
|
||||
}
|
||||
if (_scalerSo) {
|
||||
SDL_UnloadObject(_scalerSo);
|
||||
_scalerSo = 0;
|
||||
}
|
||||
if (_controller) {
|
||||
SDL_GameControllerClose(_controller);
|
||||
_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 const uint8_t blurMat[3 * 3] = {
|
||||
2, 4, 2,
|
||||
4, 8, 4,
|
||||
2, 4, 2
|
||||
};
|
||||
static const int blurMatSigma = 32 * 2;
|
||||
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) {
|
||||
|
||||
const uint32_t redBlueMask = fmt->Rmask | fmt->Bmask;
|
||||
const uint32_t greenMask = fmt->Gmask;
|
||||
const int count = 2 * radius + 1;
|
||||
|
||||
uint32_t redBlueBlurSum = 0;
|
||||
uint32_t greenBlurSum = 0;
|
||||
for (int y = 0; y < h; ++y) {
|
||||
|
||||
for (int v = 0; v < 3; ++v) {
|
||||
const int ym = CLIP(y + v - 1, 0, h - 1);
|
||||
for (int u = 0; u < 3; ++u) {
|
||||
const int xm = CLIP(x + u - 1, 0, w - 1);
|
||||
const uint32_t color = pal[src[ym * pitch + xm]];
|
||||
const int mul = blurMat[v * 3 + u];
|
||||
redBlueBlurSum += (color & redBlueMask) * mul;
|
||||
greenBlurSum += (color & greenMask) * mul;
|
||||
uint32_t r = 0;
|
||||
uint32_t g = 0;
|
||||
uint32_t b = 0;
|
||||
|
||||
uint32_t color;
|
||||
|
||||
for (int x = -radius; x <= radius; ++x) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
return ((redBlueBlurSum / blurMatSigma) & redBlueMask) | ((greenBlurSum / blurMatSigma) & greenMask);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void SystemStub_SDL::copyWidescreenBlur(int w, int h, const uint8_t *buf) {
|
||||
assert(w == _screenW && h == _screenH);
|
||||
void *dst = 0;
|
||||
void *ptr = 0;
|
||||
int pitch = 0;
|
||||
if (SDL_LockTexture(_widescreenTexture, 0, &dst, &pitch) == 0) {
|
||||
if (SDL_LockTexture(_widescreenTexture, 0, &ptr, &pitch) == 0) {
|
||||
assert((pitch & 3) == 0);
|
||||
uint32_t *p = (uint32_t *)dst;
|
||||
for (int y = 0; y < h; ++y) {
|
||||
for (int x = 0; x < w; ++x) {
|
||||
p[x] = blurPixel(x, y, buf, _rgbPalette, w, w, h, _fmt);
|
||||
|
||||
uint32_t *src = (uint32_t *)malloc(w * h * sizeof(uint32_t));
|
||||
uint32_t *tmp = (uint32_t *)malloc(w * h * sizeof(uint32_t));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
switch (ev.type) {
|
||||
case SDL_QUIT:
|
||||
|
@ -681,6 +768,9 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
|
|||
case SDLK_l:
|
||||
_pi.load = true;
|
||||
break;
|
||||
case SDLK_r:
|
||||
_pi.rewind = true;
|
||||
break;
|
||||
case SDLK_KP_PLUS:
|
||||
case SDLK_PAGEUP:
|
||||
_pi.stateSlot = 1;
|
||||
|
@ -692,7 +782,7 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
_pi.lastChar = ev.key.keysym.sym;
|
||||
setAsciiChar(_pi, &ev.key.keysym);
|
||||
switch (ev.key.keysym.sym) {
|
||||
case SDLK_LEFT:
|
||||
_pi.dirMask &= ~PlayerInput::DIR_LEFT;
|
||||
|
@ -917,39 +1007,97 @@ void SystemStub_SDL::changeGraphics(bool fullscreen, int scaleFactor) {
|
|||
prepareGraphics();
|
||||
}
|
||||
|
||||
void SystemStub_SDL::changeScaler(int scaler) {
|
||||
ScalerParameters scalerParameters = ScalerParameters::defaults();
|
||||
switch (scaler) {
|
||||
void SystemStub_SDL::setScaler(const ScalerParameters *parameters) {
|
||||
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;
|
||||
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:
|
||||
scalerParameters.type = kScalerTypePoint;
|
||||
type = kScalerTypePoint;
|
||||
break;
|
||||
case 1:
|
||||
scalerParameters.type = kScalerTypeLinear;
|
||||
type = kScalerTypeLinear;
|
||||
break;
|
||||
case 2:
|
||||
scalerParameters.type = kScalerTypeInternal;
|
||||
scalerParameters.scaler = &_internalScaler;
|
||||
type = kScalerTypeInternal;
|
||||
scaler = &_internalScaler;
|
||||
break;
|
||||
#ifdef USE_STATIC_SCALER
|
||||
case 3:
|
||||
scalerParameters.type = kScalerTypeInternal;
|
||||
scalerParameters.scaler = &scaler_nearest;
|
||||
type = kScalerTypeInternal;
|
||||
scaler = &scaler_nearest;
|
||||
break;
|
||||
case 4:
|
||||
scalerParameters.type = kScalerTypeInternal;
|
||||
scalerParameters.scaler = &scaler_tv2x;
|
||||
type = kScalerTypeInternal;
|
||||
scaler = &scaler_tv2x;
|
||||
break;
|
||||
case 5:
|
||||
scalerParameters.type = kScalerTypeInternal;
|
||||
scalerParameters.scaler = &scaler_xbr;
|
||||
type = kScalerTypeInternal;
|
||||
scaler = &scaler_xbr;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if (_scalerType != scalerParameters.type || scalerParameters.scaler != _scaler) {
|
||||
_scalerType = scalerParameters.type;
|
||||
_scaler = scalerParameters.scaler;
|
||||
if (_scalerType != type || scaler != _scaler) {
|
||||
_scalerType = type;
|
||||
_scaler = scaler;
|
||||
if (_scalerType == kScalerTypeInternal || _scalerType == kScalerTypeExternal) {
|
||||
_scaleFactor = CLIP(_scaleFactor, _scaler->factorMin, _scaler->factorMax);
|
||||
} else {
|
||||
|
|
64
unpack.cpp
64
unpack.cpp
|
@ -16,52 +16,48 @@ struct UnpackCtx {
|
|||
};
|
||||
|
||||
static bool nextBit(UnpackCtx *uc) {
|
||||
bool carry = (uc->bits & 1) != 0;
|
||||
bool bit = (uc->bits & 1) != 0;
|
||||
uc->bits >>= 1;
|
||||
if (uc->bits == 0) { // getnextlwd
|
||||
uc->bits = READ_BE_UINT32(uc->src); uc->src -= 4;
|
||||
uc->crc ^= uc->bits;
|
||||
carry = (uc->bits & 1) != 0;
|
||||
uc->bits = (1 << 31) | (uc->bits >> 1);
|
||||
const uint32_t bits = READ_BE_UINT32(uc->src); uc->src -= 4;
|
||||
uc->crc ^= bits;
|
||||
bit = (bits & 1) != 0;
|
||||
uc->bits = (1 << 31) | (bits >> 1);
|
||||
}
|
||||
return carry;
|
||||
return bit;
|
||||
}
|
||||
|
||||
static int getBits(UnpackCtx *uc, int count) { // rdd1bits
|
||||
int bits = 0;
|
||||
template<int count>
|
||||
static uint32_t getBits(UnpackCtx *uc) { // rdd1bits
|
||||
uint32_t bits = 0;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
bits <<= 1;
|
||||
if (nextBit(uc)) {
|
||||
bits |= 1;
|
||||
}
|
||||
bits |= (nextBit(uc) ? 1 : 0) << (count - 1 - i);
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
static void copyLiteral(UnpackCtx *uc, int bitsCount, int len) { // getd3chr
|
||||
int count = getBits(uc, bitsCount) + len + 1;
|
||||
uc->size -= count;
|
||||
static void copyLiteral(UnpackCtx *uc, int len) { // getd3chr
|
||||
uc->size -= len;
|
||||
if (uc->size < 0) {
|
||||
count += uc->size;
|
||||
len += uc->size;
|
||||
uc->size = 0;
|
||||
}
|
||||
for (int i = 0; i < count; ++i) {
|
||||
*(uc->dst - i) = (uint8_t)getBits(uc, 8);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
*(uc->dst - i) = (uint8_t)getBits<8>(uc);
|
||||
}
|
||||
uc->dst -= count;
|
||||
uc->dst -= len;
|
||||
}
|
||||
|
||||
static void copyReference(UnpackCtx *uc, int bitsCount, int count) { // copyd3bytes
|
||||
uc->size -= count;
|
||||
static void copyReference(UnpackCtx *uc, int len, int offset) { // copyd3bytes
|
||||
uc->size -= len;
|
||||
if (uc->size < 0) {
|
||||
count += uc->size;
|
||||
len += uc->size;
|
||||
uc->size = 0;
|
||||
}
|
||||
const int offset = getBits(uc, bitsCount);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
for (int i = 0; i < len; ++i) {
|
||||
*(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) {
|
||||
|
@ -79,24 +75,26 @@ bool bytekiller_unpack(uint8_t *dst, int dstSize, const uint8_t *src, int srcSiz
|
|||
do {
|
||||
if (!nextBit(&uc)) {
|
||||
if (!nextBit(&uc)) {
|
||||
copyLiteral(&uc, 3, 0);
|
||||
copyLiteral(&uc, getBits<3>(&uc) + 1);
|
||||
} else {
|
||||
copyReference(&uc, 8, 2);
|
||||
copyReference(&uc, 2, getBits<8>(&uc));
|
||||
}
|
||||
} else {
|
||||
const int code = getBits(&uc, 2);
|
||||
const int code = getBits<2>(&uc);
|
||||
switch (code) {
|
||||
case 3:
|
||||
copyLiteral(&uc, 8, 8);
|
||||
copyLiteral(&uc, getBits<8>(&uc) + 9);
|
||||
break;
|
||||
case 2:
|
||||
copyReference(&uc, 12, getBits(&uc, 8) + 1);
|
||||
case 2: {
|
||||
const int len = getBits<8>(&uc) + 1;
|
||||
copyReference(&uc, len, getBits<12>(&uc));
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
copyReference(&uc, 10, 4);
|
||||
copyReference(&uc, 4, getBits<10>(&uc));
|
||||
break;
|
||||
case 0:
|
||||
copyReference(&uc, 9, 3);
|
||||
copyReference(&uc, 3, getBits<9>(&uc));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue