Import 0.3.3

This commit is contained in:
Gregory Montoir 2017-06-08 00:00:00 +08:00
parent 5addfc699a
commit 1cd2866af7
19 changed files with 274 additions and 125 deletions

View File

@ -1,12 +1,12 @@
SDL_CFLAGS = `sdl-config --cflags`
SDL_LIBS = `sdl-config --libs`
MODPLUG_LIBS = -lmodplug
# TREMOR_LIBS = -lvorbisidec -logg
ZLIB_LIBS = -lz
SDL_CFLAGS := `sdl2-config --cflags`
SDL_LIBS := `sdl2-config --libs`
CXX := clang++
CXXFLAGS := -Wall -MMD $(SDL_CFLAGS) -DUSE_MODPLUG -DUSE_ZLIB # -DUSE_TREMOR
MODPLUG_LIBS := -lmodplug
TREMOR_LIBS := -lvorbisidec -logg
ZLIB_LIBS := -lz
CXXFLAGS += -Wall -MMD $(SDL_CFLAGS) -DUSE_MODPLUG -DUSE_TREMOR -DUSE_ZLIB
SRCS = collision.cpp cutscene.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 \

View File

@ -1,6 +1,6 @@
REminiscence README
Release version: 0.3.2
Release version: 0.3.3
-------------------------------------------------------------------------------
@ -24,30 +24,9 @@ Data Files:
You will need the original files of the PC (DOS or CD) or Amiga release.
To hear background music during polygonal cutscenes with the PC version,
you'll need to copy the .mod files of the Amiga version :
mod.flashback-ascenseur
mod.flashback-ceinturea
mod.flashback-chute
mod.flashback-desintegr
mod.flashback-donneobjt
mod.flashback-fin
mod.flashback-fin2
mod.flashback-game_over
mod.flashback-holocube
mod.flashback-introb
mod.flashback-jungle
mod.flashback-logo
mod.flashback-memoire
mod.flashback-missionca
mod.flashback-options1
mod.flashback-options2
mod.flashback-reunion
mod.flashback-taxi
mod.flashback-teleport2
mod.flashback-teleporta
mod.flashback-voyage
To have background music during polygonal cutscenes with the PC version,
you need to copy the music/ directory of the Amiga version or use the .mod
fileset from unexotica.
To hear voice during in-game dialogues, you'll need to copy the 'VOICE.VCE'
file from the SegaCD version to the DATA directory.
@ -87,7 +66,6 @@ Debug hotkeys :
Ctrl F toggle fast mode
Ctrl I Conrad 'infinite' life
Ctrl B toggle display of updated dirty blocks
Ctrl M mirror mode (right - left swapped)
Credits:

View File

@ -33,7 +33,7 @@ void Cutscene::sync() {
}
void Cutscene::copyPalette(const uint8_t *pal, uint16_t num) {
uint8_t *dst = (uint8_t *)_palBuf;
uint8_t *dst = _palBuf;
if (num != 0) {
dst += 0x20;
}
@ -1091,10 +1091,11 @@ void Cutscene::play() {
}
}
}
if (g_options.use_text_cutscenes && _res->_lang == LANG_FR) {
for (int i = 0; _frTextsTable[i].str; ++i) {
if (_id == _frTextsTable[i].num) {
playText(_frTextsTable[i].str);
if (g_options.use_text_cutscenes) {
const Text *textsTable = (_res->_lang == LANG_FR) ? _frTextsTable : _enTextsTable;
for (int i = 0; textsTable[i].str; ++i) {
if (_id == textsTable[i].num) {
playText(textsTable[i].str);
break;
}
}

View File

@ -40,6 +40,7 @@ struct Cutscene {
static const uint8_t _musicTable[];
static const uint8_t _protectionShapeData[];
static const Text _frTextsTable[];
static const Text _enTextsTable[];
Graphics _gfx;
Resource *_res;

View File

@ -11,6 +11,10 @@
#ifdef USE_ZLIB
#include "zlib.h"
#endif
#ifdef USE_RWOPS
#include <SDL_filesystem.h>
#include <SDL_rwops.h>
#endif
struct File_impl {
bool _ioErr;
@ -128,6 +132,62 @@ struct GzipFile : File_impl {
};
#endif
#ifdef USE_RWOPS
struct AssetFile: File_impl {
SDL_RWops *_rw;
AssetFile() : _rw(0) {}
bool open(const char *path, const char *mode) {
_ioErr = false;
_rw = SDL_RWFromFile(path, "rb");
if (!_rw) {
// try uppercase
char fixedPath[MAXPATHLEN];
{
int i = 0;
for (; path[i] && i < MAXPATHLEN - 1; ++i) {
fixedPath[i] = path[i];
if (fixedPath[i] >= 'a' && fixedPath[i] <= 'z') {
fixedPath[i] += 'A' - 'a';
}
}
fixedPath[i] = 0;
}
_rw = SDL_RWFromFile(fixedPath, "rb");
}
return _rw != 0;
}
void close() {
if (_rw) {
SDL_RWclose(_rw);
_rw = 0;
}
}
uint32_t size() {
if (_rw) {
return SDL_RWsize(_rw);
}
return 0;
}
void seek(int32_t off) {
if (_rw) {
SDL_RWseek(_rw, off, RW_SEEK_SET);
}
}
uint32_t read(void *ptr, uint32_t len) {
if (_rw) {
const int count = SDL_RWread(_rw, ptr, 1, len);
if (count != len) {
_ioErr = true;
}
}
return 0;
}
uint32_t write(void *ptr, uint32_t len) {
_ioErr = true;
return 0;
}
};
#endif
File::File()
: _impl(0) {
@ -155,6 +215,23 @@ bool File::open(const char *filename, const char *mode, FileSystem *fs) {
free(path);
return ret;
}
#ifdef USE_RWOPS
if (mode[0] == 'r') {
_impl = new AssetFile;
return _impl->open(filename, mode);
} else if (mode[0] == 'w') {
bool ret = false;
char *prefPath = SDL_GetPrefPath("org.cyxdown", "fb");
if (prefPath) {
char path[MAXPATHLEN];
snprintf(path, sizeof(path), "%s/%s", prefPath, filename);
_impl = new StdioFile;
ret = _impl->open(path, mode);
SDL_free(prefPath);
}
return ret;
}
#endif
return false;
}

43
fs.cpp
View File

@ -12,6 +12,9 @@
#include <sys/stat.h>
#include <sys/param.h>
#endif
#ifdef USE_RWOPS
#include <SDL_rwops.h>
#endif
#include "fs.h"
#include "util.h"
@ -47,18 +50,26 @@ struct FileSystem_impl {
debug(DBG_FILE, "Found %d files and %d directories", _filesCount, _dirsCount);
}
char *findPath(const char *name) const {
int findPathIndex(const char *name) const {
for (int i = 0; i < _filesCount; ++i) {
if (strcasecmp(_filesList[i].name, name) == 0) {
const char *dir = _dirsList[_filesList[i].dir];
const int len = strlen(dir) + 1 + strlen(_filesList[i].name) + 1;
char *p = (char *)malloc(len);
if (p) {
snprintf(p, len, "%s/%s", dir, _filesList[i].name);
}
return p;
return i;
}
}
return -1;
}
char *getPath(const char *name) const {
const int i = findPathIndex(name);
if (i >= 0) {
const char *dir = _dirsList[_filesList[i].dir];
const int len = strlen(dir) + 1 + strlen(_filesList[i].name) + 1;
char *p = (char *)malloc(len);
if (p) {
snprintf(p, len, "%s/%s", dir, _filesList[i].name);
}
return p;
}
return 0;
}
@ -146,13 +157,19 @@ FileSystem::~FileSystem() {
}
char *FileSystem::findPath(const char *filename) const {
return _impl->findPath(filename);
return _impl->getPath(filename);
}
bool FileSystem::exists(const char *filename) const {
char *path = findPath(filename);
if (path) {
free(path);
if (_impl->findPathIndex(filename) >= 0) {
return true;
}
return path != 0;
#ifdef USE_RWOPS
SDL_RWops *rw = SDL_RWFromFile(filename, "rb");
if (rw) {
SDL_RWclose(rw);
return true;
}
#endif
return false;
}

View File

@ -28,7 +28,7 @@ void Game::run() {
_randSeed = time(0);
if (_demoBin != -1) {
if (_demoBin < (int)ARRAYSIZE(_demoInputs)) {
if (_demoBin < ARRAYSIZE(_demoInputs)) {
const char *fn = _demoInputs[_demoBin].name;
debug(DBG_INFO, "Loading inputs from '%s'", fn);
_res.load_DEM(fn);
@ -50,7 +50,9 @@ void Game::run() {
break;
case kResourceTypeDOS:
_res.load("FB_TXT", Resource::OT_FNT);
_res._hasSeqData = _fs->exists("INTRO.SEQ");
if (g_options.use_seq_cutscenes) {
_res._hasSeqData = _fs->exists("INTRO.SEQ");
}
if (_fs->exists("logosssi.cmd")) {
_cut._patchedOffsetsTable = Cutscene::_ssiOffsetsTable;
}
@ -91,10 +93,12 @@ void Game::run() {
if (_demoBin != -1) {
_currentLevel = _demoInputs[_demoBin].level;
_randSeed = 0;
} else if (_res._isDemo) {
// do not present title screen and menus
} else {
_mix.playMusic(1);
switch (_res._type) {
case kResourceTypeDOS:
_mix.playMusic(1);
_menu.handleTitleScreen();
if (_menu._selectedOption == Menu::MENU_OPTION_ITEM_QUIT || _stub->_pi.quit) {
_stub->_pi.quit = true;
@ -148,11 +152,10 @@ void Game::displayTitleScreenAmiga() {
_res.load_CMP_menu(FILENAME, _res._memBuf);
static const int kW = 320;
static const int kH = 224;
uint8_t *buf = (uint8_t *)malloc(kW * kH);
uint8_t *buf = (uint8_t *)calloc(kW * kH, 1);
if (!buf) {
error("Failed to allocate screen buffer w=%d h=%d", kW, kH);
}
_vid.AMIGA_decodeCmp(_res._memBuf + 6, buf);
static const int kAmigaColors[] = {
0x000, 0x123, 0x012, 0x134, 0x433, 0x453, 0x046, 0x245,
0x751, 0x455, 0x665, 0x268, 0x961, 0x478, 0x677, 0x786,
@ -166,7 +169,14 @@ void Game::displayTitleScreenAmiga() {
_stub->setScreenSize(kW, kH);
_stub->copyRect(0, 0, kW, kH, buf, kW);
_stub->updateScreen(0);
_vid.AMIGA_decodeCmp(_res._memBuf + 6, buf);
free(buf);
for (int h = 0; h < kH / 2; h += 2) {
const int y = kH / 2 - h;
_stub->copyRect(0, y, kW, h * 2, buf, kW);
_stub->updateScreen(0);
_stub->sleep(30);
}
while (1) {
_stub->processEvents();
if (_stub->_pi.quit) {
@ -243,6 +253,9 @@ void Game::mainLoop() {
}
}
if (oldLevel != _currentLevel) {
if (_res._isDemo) {
_currentLevel = oldLevel;
}
changeLevel();
_pge_opTempVar1 = 0;
return;
@ -598,7 +611,9 @@ bool Game::handleContinueAbort() {
bool Game::handleProtectionScreen() {
bool valid = true;
_cut.prepare();
_cut.copyPalette(_protectionPal, 0);
const int palOffset = _res.isAmiga() ? 32 : 0;
_cut.copyPalette(_protectionPal + palOffset, 0);
_cut.updatePalette();
_cut._gfx.setClippingRect(64, 48, 128, 128);
@ -622,10 +637,10 @@ bool Game::handleProtectionScreen() {
do {
codeText[len] = '\0';
memcpy(_vid._frontLayer, _vid._tempLayer, _vid._layerSize);
_menu.drawString("PROTECTION", 2, 11, 5);
_vid.drawString("PROTECTION", 11 * 8, 2 * 8, _menu._charVar2);
char buf[20];
snprintf(buf, sizeof(buf), "CODE %d : %s", codeNum + 1, codeText);
_menu.drawString(buf, 23, 8, 5);
_vid.drawString(buf, 8 * 8, 23 * 8, _menu._charVar2);
_vid.updateScreen();
_stub->sleep(50);
_stub->processEvents();
@ -679,7 +694,11 @@ void Game::printLevelCode() {
--_printLevelCodeCounter;
if (_printLevelCodeCounter != 0) {
char buf[32];
snprintf(buf, sizeof(buf), "CODE: %s", _menu._passwords[_currentLevel][_skillLevel]);
const char *code = Menu::_passwords[_currentLevel][_skillLevel];
if (_res.isAmiga() && _res._lang == LANG_FR) {
code = Menu::_passwordsFrAmiga[_skillLevel * 7 + _currentLevel];
}
snprintf(buf, sizeof(buf), "CODE: %s", code);
_vid.drawString(buf, (_vid._w - strlen(buf) * 8) / 2, 16, 0xE7);
}
}
@ -1506,16 +1525,30 @@ void Game::handleInventory() {
int icon_h = 5;
int icon_y = 140;
int icon_num = 31;
static const int icon_spr_w = 16;
static const int icon_spr_h = 16;
do {
int icon_x = 56;
int icon_w = 9;
do {
drawIcon(icon_num, icon_x, icon_y, 0xF);
++icon_num;
icon_x += 16;
icon_x += icon_spr_w;
} while (--icon_w);
icon_y += 16;
icon_y += icon_spr_h;
} while (--icon_h);
if (_res._type == kResourceTypeAmiga) {
// draw outline rectangle
static const uint8_t outline_color = 0xE7;
uint8_t *p = _vid._frontLayer + 140 * Video::GAMESCREEN_W + 56;
memset(p + 1, outline_color, 9 * icon_spr_w - 2);
p += Video::GAMESCREEN_W;
for (int y = 1; y < 5 * icon_spr_h - 1; ++y) {
p[0] = p[9 * icon_spr_w - 1] = outline_color;
p += Video::GAMESCREEN_W;
}
memset(p + 1, outline_color, 9 * icon_spr_w - 2);
}
if (!display_score) {
int icon_x_pos = 72;

View File

@ -7,24 +7,20 @@
#ifndef INTERN_H__
#define INTERN_H__
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cassert>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <stdint.h>
#ifndef ABS
#undef ABS
#define ABS(x) ((x)<0?-(x):(x))
#endif
#ifndef MAX
#undef MAX
#define MAX(x,y) ((x)>(y)?(x):(y))
#endif
#ifndef MIN
#undef MIN
#define MIN(x,y) ((x)<(y)?(x):(y))
#endif
#ifndef ARRAYSIZE
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
#endif
#undef ARRAYSIZE
#define ARRAYSIZE(a) (int)(sizeof(a)/sizeof(a[0]))
inline uint16_t READ_BE_UINT16(const void *ptr) {
const uint8_t *b = (const uint8_t *)ptr;
@ -93,6 +89,7 @@ struct Options {
bool fade_out_palette;
bool use_tiledata;
bool use_text_cutscenes;
bool use_seq_cutscenes;
};
struct Color {

View File

@ -4,6 +4,7 @@
* Copyright (C) 2005-2015 Gregory Montoir (cyx@users.sourceforge.net)
*/
#include <SDL.h>
#include <ctype.h>
#include <getopt.h>
#include <sys/stat.h>
@ -19,7 +20,7 @@ static const char *USAGE =
"Usage: %s [OPTIONS]...\n"
" --datapath=PATH Path to data files (default 'DATA')\n"
" --savepath=PATH Path to save files (default '.')\n"
" --levelnum=NUM Level to start from (default '0')\n"
" --levelnum=NUM Start to level, bypass introduction\n"
" --fullscreen Fullscreen display\n"
" --scaler=INDEX Graphics scaler\n"
" --language=LANG Language (fr,en,de,sp,it)\n"
@ -36,7 +37,7 @@ static int detectVersion(FileSystem *fs) {
{ "LEVEL1.MAP", kResourceTypeDOS, "DOS" },
{ "LEVEL1.LEV", kResourceTypeAmiga, "Amiga" },
{ "DEMO.LEV", kResourceTypeAmiga, "Amiga (Demo)" },
{ 0, -1 }
{ 0, -1, 0 }
};
for (int i = 0; table[i].filename; ++i) {
File f;
@ -82,6 +83,7 @@ static void initOptions() {
g_options.enable_password_menu = false;
g_options.fade_out_palette = true;
g_options.use_text_cutscenes = false;
g_options.use_seq_cutscenes = true;
// read configuration file
struct {
const char *name;
@ -93,6 +95,7 @@ static void initOptions() {
{ "fade_out_palette", &g_options.fade_out_palette },
{ "use_tiledata", &g_options.use_tiledata },
{ "use_text_cutscenes", &g_options.use_text_cutscenes },
{ "use_seq_cutscenes", &g_options.use_seq_cutscenes },
{ 0, 0 }
};
static const char *filename = "rs.cfg";
@ -126,7 +129,6 @@ static void initOptions() {
static const int DEFAULT_SCALER = SCALER_SCALE_3X;
#undef main
int main(int argc, char *argv[]) {
const char *dataPath = "DATA";
const char *savePath = ".";

1
menu.h
View File

@ -40,6 +40,7 @@ struct Menu {
};
static const char *_passwords[8][3];
static const char *_passwordsFrAmiga[];
Resource *_res;
SystemStub *_stub;

View File

@ -488,9 +488,6 @@ void Game::pge_addToCurrentRoomList(LivePGE *pge, uint8_t room) {
void Game::pge_getInput() {
inp_update();
_inp_lastKeysHit = _stub->_pi.dirMask;
if (_stub->_pi.mirrorMode && (_inp_lastKeysHit & 0xC)) {
_inp_lastKeysHit ^= 0xC; // invert left/right
}
if ((_inp_lastKeysHit & 0xC) && (_inp_lastKeysHit & 0x3)) {
const uint8_t mask = (_inp_lastKeysHit & 0xF0) | (_inp_lastKeysHitLeftRight & 0xF);
_pge_inpKeysMask = mask;

View File

@ -949,6 +949,7 @@ void Resource::load_PGE(File *f) {
_pgeNum = f->readUint16LE();
memset(_pgeInit, 0, sizeof(_pgeInit));
debug(DBG_RES, "_pgeNum=%d", _pgeNum);
assert(_pgeNum <= ARRAYSIZE(_pgeInit));
for (uint16_t i = 0; i < _pgeNum; ++i) {
InitPGE *pge = &_pgeInit[i];
pge->type = f->readUint16LE();
@ -979,6 +980,7 @@ void Resource::decodePGE(const uint8_t *p, int size) {
_pgeNum = _readUint16(p); p += 2;
memset(_pgeInit, 0, sizeof(_pgeInit));
debug(DBG_RES, "len=%d _pgeNum=%d", size, _pgeNum);
assert(_pgeNum <= ARRAYSIZE(_pgeInit));
for (uint16_t i = 0; i < _pgeNum; ++i) {
InitPGE *pge = &_pgeInit[i];
pge->type = _readUint16(p); p += 2;

5
rs.cfg
View File

@ -13,5 +13,8 @@ fade_out_palette=true
# use .BNQ & .LEV datafiles (tile based rendering) for backgrounds (instead of .MAP)
use_tiledata=false
# display text instead of playing the polygon cutscenes (french only)
# display text instead of playing the polygon cutscenes
use_text_cutscenes=false
# enable playback of .SEQ cutscenes (use polygonal if false)
use_seq_cutscenes=true

View File

@ -19,7 +19,7 @@ enum {
SCALER_SCALE_3X,
SCALER_POINT_4X,
SCALER_SCALE_4X,
NUM_SCALERS = 7
NUM_SCALERS
};
struct Scaler {

View File

@ -836,6 +836,29 @@ const Cutscene::Text Cutscene::_frTextsTable[] = {
{ -1, 0 }
};
const Cutscene::Text Cutscene::_enTextsTable[] = {
{ 1, "YOU PICK UP THE HOLOCUBE" },
{ 2, "YOU PICK UP THE KEY" },
{ 3, "YOU PICK UP THE GUN" },
{ 5, "YOUR SHIELD IS RECHARGED" },
{ 10, "YOU PICK UP THE CREDIT CARD" },
{ 14, "THE CARTRIDGE IS RECHARGED" },
{ 15, "YOU PICK UP THE CARTRIDGE" },
{ 16, "YOU PICK UP THE TELEPORTER" },
{ 18, "YOU PICK UP THE I.D. CARD" },
{ 21, "YOU GIVE HIM THE TELEPORTER" },
{ 32, "THE RECEPTIONIST GIVES YOU||A PACKAGE" },
{ 33, "YOU GIVE THE PARCEL" },
{ 34, "THE GOVERNOR GIVES YOU||A WORKING PERMIT" },
{ 35, "THE FORGER GIVES YOU||A FAKE I.D. CARD" },
{ 36, "YOU PICK UP THE FUSE" },
{ 43, "YOU GIVE HIM||YOUR PAPERS" },
{ 44, "YOU GIVE HIM MONEY" },
{ 49, "HE GIVES YOU||AN ANTI-G BELT" },
{ 60, "YOU PICK UP THE TELE RECEPTER" },
{ -1, 0}
};
const Demo Game::_demoInputs[] = {
{ "demo1.bin", 0, 0x33, 0x60, 0x46 },
{ "demo51.bin", 5, 0x00, 0x60, 0xD6 },
@ -2700,8 +2723,12 @@ const uint8_t Game::_protectionCodeData[] = {
};
const uint8_t Game::_protectionPal[] = {
0x00, 0x00, 0x00, 0x42, 0x00, 0x63, 0x00, 0x00, 0x0F, 0xFF, 0x0F, 0xF0, 0x07, 0x77, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
// DOS
0x00, 0x00, 0x00, 0x42, 0x00, 0x63, 0x00, 0x00, 0x0F, 0xFF, 0x0F, 0xF0, 0x07, 0x77, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Amiga
0x00, 0x00, 0x03, 0x04, 0x06, 0x05, 0x00, 0x00, 0x04, 0x44, 0x05, 0x55, 0x06, 0x66, 0x07, 0x77,
0x08, 0x88, 0x09, 0x99, 0x0A, 0xAA, 0x0B, 0xBB, 0x0C, 0xCC, 0x0D, 0xDD, 0x0E, 0xEE, 0x0F, 0xFF
};
const char *Menu::_passwords[8][3] = {
@ -2715,6 +2742,12 @@ const char *Menu::_passwords[8][3] = {
{ "BELUGA", "BELUGA", "BELUGA" }
};
const char *Menu::_passwordsFrAmiga[] = {
"BACK", "LOUP", "CINE", "GOOD", "SPIZ", "BIOS", "HALL", // easy
"PLAY", "TOIT", "ZAPP", "LYNX", "SCSI", "GARY", "PONT", // normal
"CLOP", "CARA", "CALE", "FONT", "HASH", "FIBO", "TIPS", // hard
};
const uint8_t Video::_conradPal1[] = {
0x00, 0x00, 0xCC, 0x0C, 0x8F, 0x08, 0x7E, 0x07, 0x6C, 0x06, 0x5B, 0x05, 0x4A, 0x04, 0x63, 0x09,
0x52, 0x07, 0x41, 0x06, 0x30, 0x06, 0x76, 0x0C, 0x14, 0x09, 0x25, 0x0B, 0x88, 0x08, 0xFF, 0x0F

View File

@ -35,8 +35,6 @@ struct PlayerInput {
bool load;
int stateSlot;
bool mirrorMode;
uint8_t dbgMask;
bool quit;
};

View File

@ -19,6 +19,7 @@ struct SystemStub_SDL : SystemStub {
SDL_Window *_window;
SDL_Renderer *_renderer;
SDL_Texture *_texture;
int _texW, _texH;
SDL_GameController *_controller;
#else
SDL_Surface *_surface;
@ -125,10 +126,7 @@ void SystemStub_SDL::setScreenSize(int w, int h) {
if (_screenW == w && _screenH == h) {
return;
}
free(_screenBuffer);
_screenBuffer = 0;
free(_fadeScreenBuffer);
_fadeScreenBuffer = 0;
cleanupGraphics();
// allocate some extra bytes for the scaling routines
const int screenBufferSize = (w + 2) * (h + 2) * sizeof(uint16_t);
_screenBuffer = (uint16_t *)calloc(1, screenBufferSize);
@ -190,7 +188,7 @@ void SystemStub_SDL::copyRect(int x, int y, int w, int h, const uint8_t *buf, in
}
SDL_Rect *br = &_blitRects[_numBlitRects];
br->x = _pi.mirrorMode ? _screenW - (x + w) : x;
br->x = x;
br->y = y;
br->w = w;
br->h = h;
@ -199,22 +197,12 @@ void SystemStub_SDL::copyRect(int x, int y, int w, int h, const uint8_t *buf, in
uint16_t *p = _screenBuffer + (br->y + 1) * _screenW + (br->x + 1);
buf += y * pitch + x;
if (_pi.mirrorMode) {
while (h--) {
for (int i = 0; i < w; ++i) {
p[i] = _pal[buf[w - 1 - i]];
}
p += _screenW;
buf += pitch;
}
} else {
while (h--) {
for (int i = 0; i < w; ++i) {
p[i] = _pal[buf[i]];
}
p += _screenW;
buf += pitch;
while (h--) {
for (int i = 0; i < w; ++i) {
p[i] = _pal[buf[i]];
}
p += _screenW;
buf += pitch;
}
if (_pi.dbgMask & PlayerInput::DF_DBLOCKS) {
drawRect(br, 0xE7, _screenBuffer + _screenW + 1, _screenW * 2);
@ -244,7 +232,16 @@ static uint16_t blendPixel16(uint16_t colorSrc, uint16_t colorDst, uint32_t mask
void SystemStub_SDL::updateScreen(int shakeOffset) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_UpdateTexture(_texture, 0, _screenBuffer + _screenW + 1, _screenW * sizeof(uint16_t));
if (_texW != _screenW || _texH != _screenH) {
void *dst = 0;
int pitch = 0;
if (SDL_LockTexture(_texture, 0, &dst, &pitch) == 0) {
(*_scalers[_scaler].proc)((uint16_t *)dst, pitch, _screenBuffer + _screenW + 1, _screenW, _screenW, _screenH);
SDL_UnlockTexture(_texture);
}
} else {
SDL_UpdateTexture(_texture, 0, _screenBuffer + _screenW + 1, _screenW * sizeof(uint16_t));
}
SDL_RenderClear(_renderer);
if (_fadeOnUpdateScreen) {
SDL_SetRenderDrawBlendMode(_renderer, SDL_BLENDMODE_BLEND);
@ -582,9 +579,6 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
_pi.dbgMask ^= PlayerInput::DF_DBLOCKS;
} else if (ev.key.keysym.sym == SDLK_i) {
_pi.dbgMask ^= PlayerInput::DF_SETLIFE;
} else if (ev.key.keysym.sym == SDLK_m) {
_pi.mirrorMode = !_pi.mirrorMode;
flipGraphics();
} else if (ev.key.keysym.sym == SDLK_s) {
_pi.save = true;
} else if (ev.key.keysym.sym == SDLK_l) {
@ -690,9 +684,13 @@ void SystemStub_SDL::prepareGraphics() {
case SCALER_SCALE_3X:
case SCALER_SCALE_4X:
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
_texW = _screenW * _scalers[_scaler].factor;
_texH = _screenH * _scalers[_scaler].factor;
break;
default:
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); // nearest pixel sampling
_texW = _screenW;
_texH = _screenH;
break;
}
const int windowW = _screenW * _scalers[_scaler].factor;
@ -705,7 +703,7 @@ void SystemStub_SDL::prepareGraphics() {
_renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED);
SDL_RenderSetLogicalSize(_renderer, windowW, windowH);
static const uint32_t kPixelFormat = SDL_PIXELFORMAT_RGB565;
_texture = SDL_CreateTexture(_renderer, kPixelFormat, SDL_TEXTUREACCESS_STREAMING, _screenW, _screenH);
_texture = SDL_CreateTexture(_renderer, kPixelFormat, SDL_TEXTUREACCESS_STREAMING, _texW, _texH);
_fmt = SDL_AllocFormat(kPixelFormat);
#else
SDL_WM_SetCaption(_caption, NULL);

View File

@ -8,7 +8,11 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include <cstdarg>
#ifdef __ANDROID__
#define LOG_TAG "FbJni"
#include <android/log.h>
#endif
#include <stdarg.h>
#include "util.h"
@ -21,8 +25,11 @@ void debug(uint16_t cm, const char *msg, ...) {
va_start(va, msg);
vsprintf(buf, msg, va);
va_end(va);
printf("%s\n", buf);
fprintf(stdout, "%s\n", buf);
fflush(stdout);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "%s", buf);
#endif
}
}
@ -35,6 +42,9 @@ void error(const char *msg, ...) {
fprintf(stderr, "ERROR: %s!\n", buf);
#ifdef _WIN32
MessageBox(0, buf, g_caption, MB_ICONERROR);
#endif
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s", buf);
#endif
exit(-1);
}
@ -46,5 +56,8 @@ void warning(const char *msg, ...) {
vsnprintf(buf, sizeof(buf), msg, va);
va_end(va);
fprintf(stderr, "WARNING: %s!\n", buf);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_WARN, LOG_TAG, "%s", buf);
#endif
}

View File

@ -558,8 +558,8 @@ static void decodeLevHelper(uint8_t *dst, const uint8_t *src, int offset10, int
const bool yflip = (d3 & (1 << 12)) != 0;
const bool xflip = (d3 & (1 << 11)) != 0;
int mask = 0;
if ((d3 < (1 << 15)) == 0) {
mask = 0x80;
if ((d3 & 0x8000) != 0) {
mask = 0x80 + ((d3 >> 6) & 0x10);
}
if (isPC) {
PC_drawTile(dst + y * 256 + x, a2, mask, xflip, yflip, -1);
@ -586,8 +586,8 @@ static void decodeLevHelper(uint8_t *dst, const uint8_t *src, int offset10, int
int mask = 0;
if ((d3 & 0x6000) != 0 && sgdBuf) {
mask = 0x10;
} else if ((d3 < (1 << 15)) == 0) {
mask = 0x80;
} else if ((d3 & 0x8000) != 0) {
mask = 0x80 + ((d3 >> 6) & 0x10);
}
if (isPC) {
PC_drawTile(dst + y * 256 + x, a2, mask, xflip, yflip, 0);
@ -663,13 +663,14 @@ void Video::AMIGA_decodeLev(int level, int room) {
// background
setPaletteSlotBE(0x0, _mapPalSlot1);
// objects
setPaletteSlotBE(0x1, (level == 0 || level == 1) ? _mapPalSlot3 : _mapPalSlot2);
setPaletteSlotBE(0x1, (level == 0) ? _mapPalSlot3 : _mapPalSlot2);
setPaletteSlotBE(0x2, _mapPalSlot3);
setPaletteSlotBE(0x3, _mapPalSlot3);
// conrad
setPaletteSlotBE(0x4, _mapPalSlot3);
// foreground
setPaletteSlotBE(0x8, _mapPalSlot1);
setPaletteSlotBE(0x9, (level == 0) ? _mapPalSlot1 : _mapPalSlot3);
// inventory
setPaletteSlotBE(0xA, _mapPalSlot3);
}
@ -803,11 +804,8 @@ void Video::PC_drawChar(uint8_t c, int16_t y, int16_t x) {
const uint8_t *src = _res->_fnt + (c - 32) * 32;
uint8_t *dst = _frontLayer + x + 256 * y;
for (int h = 0; h < 8; ++h) {
for (int i = 0; i < 4; ++i) {
uint8_t c1 = (*src & 0xF0) >> 4;
uint8_t c2 = (*src & 0x0F) >> 0;
++src;
for (int i = 0; i < 4; ++i, ++src) {
const uint8_t c1 = *src >> 4;
if (c1 != 0) {
if (c1 != 2) {
*dst = _charFrontColor;
@ -818,7 +816,7 @@ void Video::PC_drawChar(uint8_t c, int16_t y, int16_t x) {
*dst = _charTransparentColor;
}
++dst;
const uint8_t c2 = *src & 15;
if (c2 != 0) {
if (c2 != 2) {
*dst = _charFrontColor;