From 31757e48dc05de7fb55416a86ee6704aab7b25c7 Mon Sep 17 00:00:00 2001 From: Gregory Montoir Date: Sat, 4 Nov 2017 00:00:00 +0800 Subject: [PATCH] Import 0.3.4 --- Makefile | 7 +- README.txt | 6 +- dynlib.cpp | 59 ++++++ dynlib.h | 16 ++ file.cpp | 22 ++- file.h | 2 +- game.cpp | 8 +- main.cpp | 49 ++++- menu.h | 1 + rs.cfg | 2 +- scaler.cpp | 179 +++++++---------- scaler.h | 29 +-- screenshot.cpp | 70 +++++++ screenshot.h | 9 + staticres.cpp | 6 + systemstub.h | 11 +- systemstub_sdl.cpp | 466 +++++++++++++++++---------------------------- 17 files changed, 505 insertions(+), 437 deletions(-) create mode 100644 dynlib.cpp create mode 100644 dynlib.h create mode 100644 screenshot.cpp create mode 100644 screenshot.h diff --git a/Makefile b/Makefile index 93d085f..9c8c9a3 100644 --- a/Makefile +++ b/Makefile @@ -2,21 +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 -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 \ +SRCS = collision.cpp cutscene.cpp dynlib.cpp file.cpp fs.cpp game.cpp graphics.cpp main.cpp menu.cpp \ mixer.cpp mod_player.cpp ogg_player.cpp piege.cpp resource.cpp resource_aba.cpp \ - scaler.cpp seq_player.cpp \ + scaler.cpp screenshot.cpp seq_player.cpp \ sfx_player.cpp staticres.cpp systemstub_sdl.cpp unpack.cpp util.cpp video.cpp OBJS = $(SRCS:.cpp=.o) DEPS = $(SRCS:.cpp=.d) -LIBS = $(SDL_LIBS) $(MODPLUG_LIBS) $(TREMOR_LIBS) $(ZLIB_LIBS) +LIBS = $(SDL_LIBS) $(DL_LIBS) $(MODPLUG_LIBS) $(TREMOR_LIBS) $(ZLIB_LIBS) rs: $(OBJS) $(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) diff --git a/README.txt b/README.txt index ee28cdd..73f418a 100644 --- a/README.txt +++ b/README.txt @@ -1,6 +1,6 @@ REminiscence README -Release version: 0.3.3 +Release version: 0.3.4 ------------------------------------------------------------------------------- @@ -44,7 +44,7 @@ directory. These paths can be changed using command line switches : --savepath=PATH Path to save files (default '.') --levelnum=NUM Level to start from (default '0') --fullscreen Fullscreen display - --scaler=INDEX Graphics scaler + --scaler=NAME@X Graphics scaler (default 'scale@3') --language=LANG Language (fr,en,de,sp,it) In-game hotkeys : @@ -56,7 +56,7 @@ In-game hotkeys : Backspace display the inventory Alt Enter toggle windowed/fullscreen mode Alt + and - change video scaler - Alt S write screenshot as .bmp + Alt S write screenshot as .tga Ctrl S save game state Ctrl L load game state Ctrl + and - change game state slot diff --git a/dynlib.cpp b/dynlib.cpp new file mode 100644 index 0000000..766ef98 --- /dev/null +++ b/dynlib.cpp @@ -0,0 +1,59 @@ + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#include +#endif +#include +#include +#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); +} diff --git a/dynlib.h b/dynlib.h new file mode 100644 index 0000000..6b4fe85 --- /dev/null +++ b/dynlib.h @@ -0,0 +1,16 @@ + +#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__ diff --git a/file.cpp b/file.cpp index c60bda1..26a3598 100644 --- a/file.cpp +++ b/file.cpp @@ -25,7 +25,7 @@ struct File_impl { virtual uint32_t size() = 0; virtual void seek(int32_t off) = 0; virtual uint32_t read(void *ptr, uint32_t len) = 0; - virtual uint32_t write(void *ptr, uint32_t len) = 0; + virtual uint32_t write(const void *ptr, uint32_t len) = 0; }; struct StdioFile : File_impl { @@ -67,7 +67,7 @@ struct StdioFile : File_impl { } return 0; } - uint32_t write(void *ptr, uint32_t len) { + uint32_t write(const void *ptr, uint32_t len) { if (_fp) { uint32_t r = fwrite(ptr, 1, len, _fp); if (r != len) { @@ -119,7 +119,7 @@ struct GzipFile : File_impl { } return 0; } - uint32_t write(void *ptr, uint32_t len) { + uint32_t write(const void *ptr, uint32_t len) { if (_fp) { uint32_t r = gzwrite(_fp, ptr, len); if (r != len) { @@ -136,8 +136,9 @@ struct GzipFile : File_impl { struct AssetFile: File_impl { SDL_RWops *_rw; AssetFile() : _rw(0) {} - bool open(const char *path, const char *mode) { - _ioErr = false; + bool prefixedOpen(const char *prefix, const char *name) { + char path[MAXPATHLEN]; + snprintf(path, sizeof(path), "%s%s", prefix, name); _rw = SDL_RWFromFile(path, "rb"); if (!_rw) { // try uppercase @@ -146,6 +147,9 @@ struct AssetFile: File_impl { int i = 0; for (; path[i] && i < MAXPATHLEN - 1; ++i) { fixedPath[i] = path[i]; + if (i < strlen(prefix)) { + continue; + } if (fixedPath[i] >= 'a' && fixedPath[i] <= 'z') { fixedPath[i] += 'A' - 'a'; } @@ -156,6 +160,10 @@ struct AssetFile: File_impl { } return _rw != 0; } + bool open(const char *path, const char *mode) { + _ioErr = false; + return prefixedOpen("", path) || prefixedOpen("/sdcard/flashback/", path); + } void close() { if (_rw) { SDL_RWclose(_rw); @@ -182,7 +190,7 @@ struct AssetFile: File_impl { } return 0; } - uint32_t write(void *ptr, uint32_t len) { + uint32_t write(const void *ptr, uint32_t len) { _ioErr = true; return 0; } @@ -308,7 +316,7 @@ uint32_t File::readUint32BE() { return (hi << 16) | lo; } -uint32_t File::write(void *ptr, uint32_t len) { +uint32_t File::write(const void *ptr, uint32_t len) { return _impl->write(ptr, len); } diff --git a/file.h b/file.h index 695ebb1..47d4a10 100644 --- a/file.h +++ b/file.h @@ -30,7 +30,7 @@ struct File { uint32_t readUint32LE(); uint16_t readUint16BE(); uint32_t readUint32BE(); - uint32_t write(void *ptr, uint32_t size); + uint32_t write(const void *ptr, uint32_t size); void writeByte(uint8_t b); void writeUint16BE(uint16_t n); void writeUint32BE(uint32_t n); diff --git a/game.cpp b/game.cpp index 8278a69..2044706 100644 --- a/game.cpp +++ b/game.cpp @@ -695,8 +695,12 @@ void Game::printLevelCode() { if (_printLevelCodeCounter != 0) { char buf[32]; const char *code = Menu::_passwords[_currentLevel][_skillLevel]; - if (_res.isAmiga() && _res._lang == LANG_FR) { - code = Menu::_passwordsFrAmiga[_skillLevel * 7 + _currentLevel]; + if (_res.isAmiga()) { + if (_res._lang == LANG_FR) { + code = Menu::_passwordsFrAmiga[_skillLevel * 7 + _currentLevel]; + } else { + code = Menu::_passwordsEnAmiga[_skillLevel * 7 + _currentLevel]; + } } snprintf(buf, sizeof(buf), "CODE: %s", code); _vid.drawString(buf, (_vid._w - strlen(buf) * 8) / 2, 16, 0xE7); diff --git a/main.cpp b/main.cpp index d22d563..cdc6392 100644 --- a/main.cpp +++ b/main.cpp @@ -22,7 +22,7 @@ static const char *USAGE = " --savepath=PATH Path to save files (default '.')\n" " --levelnum=NUM Start to level, bypass introduction\n" " --fullscreen Fullscreen display\n" - " --scaler=INDEX Graphics scaler\n" + " --scaler=NAME@X Graphics scaler (default 'scale@3')\n" " --language=LANG Language (fr,en,de,sp,it)\n" ; @@ -127,14 +127,50 @@ static void initOptions() { } } -static const int DEFAULT_SCALER = SCALER_SCALE_3X; +static void parseScaler(char *name, ScalerParameters *scalerParameters) { + struct { + const char *name; + int type; + } scalers[] = { + { "point", kScalerTypePoint }, + { "linear", kScalerTypeLinear }, + { "scale", kScalerTypeInternal }, + { 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; + found = true; + break; + } + } + if (!found) { + char libname[32]; + snprintf(libname, sizeof(libname), "scaler_%s", name); + const Scaler *scaler = findScaler(libname); + if (scaler) { + scalerParameters->type = kScalerTypeExternal; + scalerParameters->scaler = scaler; + } else { + warning("Scaler '%s' not found, using default", libname); + } + } + if (sep) { + scalerParameters->factor = atoi(sep + 1); + } +} int main(int argc, char *argv[]) { const char *dataPath = "DATA"; const char *savePath = "."; int levelNum = 0; - int scaler = DEFAULT_SCALER; bool fullscreen = false; + ScalerParameters scalerParameters = ScalerParameters::defaults(); int forcedLanguage = -1; int demoNum = -1; if (argc == 2) { @@ -174,10 +210,7 @@ int main(int argc, char *argv[]) { fullscreen = true; break; case 5: - scaler = atoi(optarg); - if (scaler < 0 || scaler >= NUM_SCALERS) { - scaler = DEFAULT_SCALER; - } + parseScaler(optarg, &scalerParameters); break; case 6: { static const struct { @@ -218,7 +251,7 @@ int main(int argc, char *argv[]) { const Language language = (forcedLanguage == -1) ? detectLanguage(&fs) : (Language)forcedLanguage; SystemStub *stub = SystemStub_SDL_create(); Game *g = new Game(stub, &fs, savePath, levelNum, demoNum, (ResourceType)version, language); - stub->init(g_caption, Video::GAMESCREEN_W, Video::GAMESCREEN_H, scaler, fullscreen); + stub->init(g_caption, Video::GAMESCREEN_W, Video::GAMESCREEN_H, fullscreen, &scalerParameters); g->run(); delete g; stub->destroy(); diff --git a/menu.h b/menu.h index 7b89cbe..554d65e 100644 --- a/menu.h +++ b/menu.h @@ -41,6 +41,7 @@ struct Menu { static const char *_passwords[8][3]; static const char *_passwordsFrAmiga[]; + static const char *_passwordsEnAmiga[]; Resource *_res; SystemStub *_stub; diff --git a/rs.cfg b/rs.cfg index c790ffe..54bc276 100644 --- a/rs.cfg +++ b/rs.cfg @@ -8,7 +8,7 @@ play_disabled_cutscenes=false enable_password_menu=false # fade palette to black for screen transition (use blending if false) -fade_out_palette=true +fade_out_palette=false # use .BNQ & .LEV datafiles (tile based rendering) for backgrounds (instead of .MAP) use_tiledata=false diff --git a/scaler.cpp b/scaler.cpp index 6af3bbc..b7ab11f 100644 --- a/scaler.cpp +++ b/scaler.cpp @@ -5,79 +5,19 @@ */ #include "scaler.h" +#include "dynlib.h" #include "util.h" -static void point1x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) { - dstPitch >>= 1; - while (h--) { - memcpy(dst, src, w * 2); - dst += dstPitch; - src += srcPitch; - } -} - -static void point2x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) { - dstPitch >>= 1; +static void scale2x(uint32_t *dst, int dstPitch, const uint32_t *src, int srcPitch, int w, int h) { const int dstPitch2 = dstPitch * 2; - while (h--) { - uint16_t *p = dst; - for (int i = 0; i < w; ++i, p += 2) { - const uint16_t c = *(src + i); - for (int j = 0; j < 2; ++j) { - *(p + j) = *(p + dstPitch + j) = c; - } - } - dst += dstPitch2; - src += srcPitch; - } -} - -static void point3x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) { - dstPitch >>= 1; - const int dstPitch2 = dstPitch * 2; - const int dstPitch3 = dstPitch * 3; - while (h--) { - uint16_t *p = dst; - for (int i = 0; i < w; ++i, p += 3) { - const uint16_t c = *(src + i); - for (int j = 0; j < 3; ++j) { - *(p + j) = *(p + dstPitch + j) = *(p + dstPitch2 + j) = c; - } - } - dst += dstPitch3; - src += srcPitch; - } -} - -static void point4x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) { - dstPitch >>= 1; - const int dstPitch2 = dstPitch * 2; - const int dstPitch3 = dstPitch * 3; - const int dstPitch4 = dstPitch * 4; - while (h--) { - uint16_t *p = dst; - for (int i = 0; i < w; ++i, p += 4) { - const uint16_t c = *(src + i); - for (int j = 0; j < 4; ++j) { - *(p + j) = *(p + dstPitch + j) = *(p + dstPitch2 + j) = *(p + dstPitch3 + j) = c; - } - } - dst += dstPitch4; - src += srcPitch; - } -} - -static void scale2x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) { - dstPitch >>= 1; - const int dstPitch2 = dstPitch * 2; - while (h--) { - uint16_t *p = dst; - uint16_t D = *(src - 1); - uint16_t E = *(src); - for (int i = 0; i < w; ++i, p += 2) { - uint16_t B = *(src + i - srcPitch); - uint16_t F = *(src + i + 1); - uint16_t H = *(src + i + srcPitch); + for (int y = 0; y < h; ++y) { + uint32_t *p = dst; + for (int x = 0; x < w; ++x, p += 2) { + const uint32_t E = *(src + x); + const uint32_t B = (y == 0) ? E : *(src + x - srcPitch); + const uint32_t D = (x == 0) ? E : *(src + x - 1); + const uint32_t F = (x == w - 1) ? E : *(src + x + 1); + const uint32_t H = (y == h - 1) ? E : *(src + x + srcPitch); if (B != H && D != F) { *(p) = D == B ? D : E; *(p + 1) = B == F ? F : E; @@ -89,30 +29,39 @@ static void scale2x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPit *(p + dstPitch) = E; *(p + dstPitch + 1) = E; } - D = E; - E = F; } dst += dstPitch2; src += srcPitch; } } -static void scale3x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) { - dstPitch >>= 1; +static void scale3x(uint32_t *dst, int dstPitch, const uint32_t *src, int srcPitch, int w, int h) { const int dstPitch2 = dstPitch * 2; const int dstPitch3 = dstPitch * 3; - while (h--) { - uint16_t *p = dst; - uint16_t A = *(src - srcPitch - 1); - uint16_t B = *(src - srcPitch); - uint16_t D = *(src - 1); - uint16_t E = *(src); - uint16_t G = *(src + srcPitch - 1); - uint16_t H = *(src + srcPitch); - for (int i = 0; i < w; ++i, p += 3) { - uint16_t C = *(src + i - srcPitch + 1); - uint16_t F = *(src + i + 1); - uint16_t I = *(src + i + srcPitch + 1); + for (int y = 0; y < h; ++y) { + uint32_t *p = dst; + for (int x = 0; x < w; ++x, p += 3) { + const uint32_t E = *(src + x); + const uint32_t B = (y == 0) ? E : *(src + x - srcPitch); + const uint32_t D = (x == 0) ? E : *(src + x - 1); + const uint32_t F = (x == w - 1) ? E : *(src + x + 1); + const uint32_t H = (y == h - 1) ? E : *(src + x + srcPitch); + uint32_t A, C; + if (y == 0) { + A = D; + C = F; + } else { + A = (x == 0) ? B : *(src + x - srcPitch - 1); + C = (x == w - 1) ? B : *(src + x - srcPitch + 1); + } + uint32_t G, I; + if (y == h - 1) { + G = D; + I = F; + } else { + G = (x == 0) ? H : *(src + x + srcPitch - 1); + I = (x == w - 1) ? H : *(src + x + srcPitch + 1); + } if (B != H && D != F) { *(p) = D == B ? D : E; *(p + 1) = (D == B && E != C) || (B == F && E != A) ? B : E; @@ -134,48 +83,62 @@ static void scale3x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPit *(p + dstPitch2 + 1) = E; *(p + dstPitch2 + 2) = E; } - A = B; - B = C; - D = E; - E = F; - G = H; - H = I; } dst += dstPitch3; src += srcPitch; } } -void scale4x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) { +static void scale4x(uint32_t *dst, int dstPitch, const uint32_t *src, int srcPitch, int w, int h) { static struct { - uint16_t *ptr; + uint32_t *ptr; int w, h, pitch; int size; } buf; - const int size = (w * 2 + 2) * (h * 2 + 2) * sizeof(uint16_t); + const int size = (w * 2) * (h * 2) * sizeof(uint32_t); if (buf.size < size) { free(buf.ptr); buf.size = size; buf.w = w * 2; buf.h = h * 2; - buf.pitch = buf.w + 2; - buf.ptr = (uint16_t *)malloc(buf.size); + buf.pitch = buf.w; + buf.ptr = (uint32_t *)malloc(buf.size); if (!buf.ptr) { error("Unable to allocate scale4x intermediate buffer"); } } - scale2x(buf.ptr + buf.pitch + 1, buf.pitch * sizeof(uint16_t), src, srcPitch, w, h); - scale2x(dst, dstPitch, buf.ptr + buf.pitch + 1, buf.pitch, w * 2, h * 2); + scale2x(buf.ptr, buf.pitch, src, srcPitch, w, h); + scale2x(dst, dstPitch, buf.ptr, buf.pitch, buf.w, buf.h); } -const Scaler _scalers[] = { - { "point1x", &point1x, 1 }, - { "point2x", &point2x, 2 }, - { "scale2x", &scale2x, 2 }, - { "point3x", &point3x, 3 }, - { "scale3x", &scale3x, 3 }, - { "point4x", &point4x, 4 }, - { "scale4x", &scale4x, 4 }, - { 0, 0, 0 } +static void scaleNx(int factor, uint32_t *dst, int dstPitch, const uint32_t *src, int srcPitch, int w, int h) { + switch (factor) { + case 2: + return scale2x(dst, dstPitch, src, srcPitch, w, h); + case 3: + return scale3x(dst, dstPitch, src, srcPitch, w, h); + case 4: + return scale4x(dst, dstPitch, src, srcPitch, w, h); + } +} + +const Scaler _internalScaler = { + SCALER_TAG, + "scaleNx", + 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; +} diff --git a/scaler.h b/scaler.h index 6ed973d..cf32150 100644 --- a/scaler.h +++ b/scaler.h @@ -7,27 +7,28 @@ #ifndef SCALER_H__ #define SCALER_H__ -#include "intern.h" +#include -typedef void (*ScaleProc)(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h); +typedef void (*ScaleProc32)(int factor, uint32_t *dst, int dstPitch, const uint32_t *src, int srcPitch, int w, int h); -enum { - SCALER_POINT_1X = 0, - SCALER_POINT_2X, - SCALER_SCALE_2X, - SCALER_POINT_3X, - SCALER_SCALE_3X, - SCALER_POINT_4X, - SCALER_SCALE_4X, - NUM_SCALERS +enum ScalerType { + kScalerTypePoint, + kScalerTypeLinear, + kScalerTypeInternal, + kScalerTypeExternal, }; +#define SCALER_TAG 1 + struct Scaler { + uint32_t tag; const char *name; - ScaleProc proc; - uint8_t factor; + int factorMin, factorMax; + ScaleProc32 scale; }; -extern const Scaler _scalers[]; +extern const Scaler _internalScaler; + +const Scaler *findScaler(const char *name); #endif // SCALER_H__ diff --git a/screenshot.cpp b/screenshot.cpp new file mode 100644 index 0000000..ba33f36 --- /dev/null +++ b/screenshot.cpp @@ -0,0 +1,70 @@ + +#include "screenshot.h" +#include "file.h" + +static void TO_LE16(uint8_t *dst, uint16_t value) { + for (int i = 0; i < 2; ++i) { + dst[i] = value & 255; + value >>= 8; + } +} + +#define kTgaImageTypeUncompressedTrueColor 2 +#define kTgaImageTypeRunLengthEncodedTrueColor 10 +#define kTgaDirectionTop (1 << 5) + +static const int TGA_HEADER_SIZE = 18; + +void saveTGA(const char *filename, const uint8_t *rgba, int w, int h) { + + static const uint8_t kImageType = kTgaImageTypeRunLengthEncodedTrueColor; + uint8_t buffer[TGA_HEADER_SIZE]; + buffer[0] = 0; // ID Length + buffer[1] = 0; // ColorMap Type + buffer[2] = kImageType; + TO_LE16(buffer + 3, 0); // ColorMap Start + TO_LE16(buffer + 5, 0); // ColorMap Length + buffer[7] = 0; // ColorMap Bits + TO_LE16(buffer + 8, 0); // X-origin + TO_LE16(buffer + 10, 0); // Y-origin + TO_LE16(buffer + 12, w); // Image Width + TO_LE16(buffer + 14, h); // Image Height + buffer[16] = 24; // Pixel Depth + buffer[17] = kTgaDirectionTop; // Descriptor + + File f; + if (f.open(filename, "wb", ".")) { + f.write(buffer, sizeof(buffer)); + if (kImageType == kTgaImageTypeUncompressedTrueColor) { + for (int i = 0; i < w * h; ++i) { + f.writeByte(rgba[0]); + f.writeByte(rgba[1]); + f.writeByte(rgba[2]); + rgba += 4; + } + } else { + assert(kImageType == kTgaImageTypeRunLengthEncodedTrueColor); + int prevColor = rgba[2] + (rgba[1] << 8) + (rgba[0] << 16); rgba += 4; + int count = 0; + for (int i = 1; i < w * h; ++i) { + int color = rgba[2] + (rgba[1] << 8) + (rgba[0] << 16); rgba += 4; + if (prevColor == color && count < 127) { + ++count; + continue; + } + f.writeByte(count | 0x80); + f.writeByte((prevColor >> 16) & 255); + f.writeByte((prevColor >> 8) & 255); + f.writeByte( prevColor & 255); + count = 0; + prevColor = color; + } + if (count != 0) { + f.writeByte(count | 0x80); + f.writeByte((prevColor >> 16) & 255); + f.writeByte((prevColor >> 8) & 255); + f.writeByte( prevColor & 255); + } + } + } +} diff --git a/screenshot.h b/screenshot.h new file mode 100644 index 0000000..c3257d6 --- /dev/null +++ b/screenshot.h @@ -0,0 +1,9 @@ + +#ifndef SCREENSHOT_H__ +#define SCREENSHOT_H__ + +#include + +void saveTGA(const char *filename, const uint8_t *rgb, int w, int h); + +#endif diff --git a/staticres.cpp b/staticres.cpp index 916629d..22b9743 100644 --- a/staticres.cpp +++ b/staticres.cpp @@ -2748,6 +2748,12 @@ const char *Menu::_passwordsFrAmiga[] = { "CLOP", "CARA", "CALE", "FONT", "HASH", "FIBO", "TIPS", // hard }; +const char *Menu::_passwordsEnAmiga[] = { + "WIND", "SPIN", "KAVA", "HIRO", "TEST", "GOLD", "WALL", // easy + "FIRE", "BURN", "EGGS", "GURT", "CHIP", "TREE", "BOLD", // normal + "MINE", "YOUR", "NEST", "LINE", "LISA", "MARY", "MICE", // 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 diff --git a/systemstub.h b/systemstub.h index dd2cf90..824dbfa 100644 --- a/systemstub.h +++ b/systemstub.h @@ -8,6 +8,7 @@ #define SYSTEMSTUB_H__ #include "intern.h" +#include "scaler.h" struct PlayerInput { enum { @@ -39,6 +40,14 @@ struct PlayerInput { bool quit; }; +struct ScalerParameters { + ScalerType type; + const Scaler *scaler; + int factor; + + static ScalerParameters defaults(); +}; + struct SystemStub { typedef void (*AudioCallback)(void *param, int16_t *stream, int len); @@ -46,7 +55,7 @@ struct SystemStub { virtual ~SystemStub() {} - virtual void init(const char *title, int w, int h, int scaler, bool fullscreen) = 0; + virtual void init(const char *title, int w, int h, bool fullscreen, ScalerParameters *scalerParameters) = 0; virtual void destroy() = 0; virtual void setScreenSize(int w, int h) = 0; diff --git a/systemstub_sdl.cpp b/systemstub_sdl.cpp index c8db672..6e8511e 100644 --- a/systemstub_sdl.cpp +++ b/systemstub_sdl.cpp @@ -6,32 +6,39 @@ #include #include "scaler.h" +#include "screenshot.h" #include "systemstub.h" #include "util.h" static const int kAudioHz = 22050; +static const char *kIconBmp = "icon.bmp"; + static const int kJoystickIndex = 0; static const int kJoystickCommitValue = 3200; +static const uint32_t kPixelFormat = SDL_PIXELFORMAT_RGB888; + +ScalerParameters ScalerParameters::defaults() { + ScalerParameters params; + params.type = kScalerTypeInternal; + params.scaler = &_internalScaler; + params.factor = _internalScaler.factorMin + (_internalScaler.factorMax - _internalScaler.factorMin) / 2; + return params; +} + struct SystemStub_SDL : SystemStub { -#if SDL_VERSION_ATLEAST(2, 0, 0) SDL_Window *_window; SDL_Renderer *_renderer; SDL_Texture *_texture; int _texW, _texH; SDL_GameController *_controller; -#else - SDL_Surface *_surface; -#endif SDL_PixelFormat *_fmt; const char *_caption; - uint16_t *_screenBuffer; - uint16_t *_fadeScreenBuffer; + uint32_t *_screenBuffer; bool _fullscreen; - int _scaler; uint8_t _overscanColor; - uint16_t _pal[256]; + uint32_t _rgbPalette[256]; int _screenW, _screenH; SDL_Joystick *_joystick; SDL_Rect _blitRects[200]; @@ -40,9 +47,12 @@ struct SystemStub_SDL : SystemStub { void (*_audioCbProc)(void *, int16_t *, int); void *_audioCbData; int _screenshot; + ScalerType _scalerType; + const Scaler *_scaler; + int _scaleFactor; virtual ~SystemStub_SDL() {} - virtual void init(const char *title, int w, int h, int scaler, bool fullscreen); + virtual void init(const char *title, int w, int h, bool fullscreen, ScalerParameters *scalerParameters); virtual void destroy(); virtual void setScreenSize(int w, int h); virtual void setPalette(const uint8_t *pal, int n); @@ -64,31 +74,30 @@ struct SystemStub_SDL : SystemStub { void processEvent(const SDL_Event &ev, bool &paused); void prepareGraphics(); void cleanupGraphics(); - void changeGraphics(bool fullscreen, uint8_t scaler); - void flipGraphics(); + void changeGraphics(bool fullscreen, int scaleFactor); void forceGraphicsRedraw(); - void drawRect(SDL_Rect *rect, uint8_t color, uint16_t *dst, uint16_t dstPitch); + void drawRect(SDL_Rect *rect, uint8_t color); }; SystemStub *SystemStub_SDL_create() { return new SystemStub_SDL(); } -void SystemStub_SDL::init(const char *title, int w, int h, int scaler, bool fullscreen) { +void SystemStub_SDL::init(const char *title, int w, int h, bool fullscreen, ScalerParameters *scalerParameters) { SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK); SDL_ShowCursor(SDL_DISABLE); _caption = title; memset(&_pi, 0, sizeof(_pi)); _screenBuffer = 0; - _fadeScreenBuffer = 0; _fadeOnUpdateScreen = false; _fullscreen = fullscreen; - _scaler = scaler; - memset(_pal, 0, sizeof(_pal)); + _scalerType = scalerParameters->type; + _scaler = scalerParameters->scaler; + _scaleFactor = scalerParameters->factor; + memset(_rgbPalette, 0, sizeof(_rgbPalette)); _screenW = _screenH = 0; setScreenSize(w, h); _joystick = 0; -#if SDL_VERSION_ATLEAST(2, 0, 0) _controller = 0; if (SDL_NumJoysticks() > 0) { SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt"); @@ -99,22 +108,15 @@ void SystemStub_SDL::init(const char *title, int w, int h, int scaler, bool full _joystick = SDL_JoystickOpen(kJoystickIndex); } } -#else - if (SDL_NumJoysticks() > 0) { - _joystick = SDL_JoystickOpen(kJoystickIndex); - } -#endif _screenshot = 1; } void SystemStub_SDL::destroy() { cleanupGraphics(); -#if SDL_VERSION_ATLEAST(2, 0, 0) if (_controller) { SDL_GameControllerClose(_controller); _controller = 0; } -#endif if (_joystick) { SDL_JoystickClose(_joystick); _joystick = 0; @@ -127,9 +129,8 @@ void SystemStub_SDL::setScreenSize(int w, int h) { return; } 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); + const int screenBufferSize = w * h * sizeof(uint32_t); + _screenBuffer = (uint32_t *)calloc(1, screenBufferSize); if (!_screenBuffer) { error("SystemStub_SDL::setScreenSize() Unable to allocate offscreen buffer, w=%d, h=%d", w, h); } @@ -144,16 +145,16 @@ void SystemStub_SDL::setPalette(const uint8_t *pal, int n) { uint8_t r = pal[i * 3 + 0]; uint8_t g = pal[i * 3 + 1]; uint8_t b = pal[i * 3 + 2]; - _pal[i] = SDL_MapRGB(_fmt, r, g, b); + _rgbPalette[i] = SDL_MapRGB(_fmt, r, g, b); } } void SystemStub_SDL::setPaletteEntry(int i, const Color *c) { - _pal[i] = SDL_MapRGB(_fmt, c->r, c->g, c->b); + _rgbPalette[i] = SDL_MapRGB(_fmt, c->r, c->g, c->b); } void SystemStub_SDL::getPaletteEntry(int i, Color *c) { - SDL_GetRGB(_pal[i], _fmt, &c->r, &c->g, &c->b); + SDL_GetRGB(_rgbPalette[i], _fmt, &c->r, &c->g, &c->b); } void SystemStub_SDL::setOverscanColor(int i) { @@ -194,53 +195,37 @@ void SystemStub_SDL::copyRect(int x, int y, int w, int h, const uint8_t *buf, in br->h = h; ++_numBlitRects; - uint16_t *p = _screenBuffer + (br->y + 1) * _screenW + (br->x + 1); + uint32_t *p = _screenBuffer + br->y * _screenW + br->x; buf += y * pitch + x; while (h--) { for (int i = 0; i < w; ++i) { - p[i] = _pal[buf[i]]; + p[i] = _rgbPalette[buf[i]]; } p += _screenW; buf += pitch; } if (_pi.dbgMask & PlayerInput::DF_DBLOCKS) { - drawRect(br, 0xE7, _screenBuffer + _screenW + 1, _screenW * 2); + drawRect(br, 0xE7); } } } void SystemStub_SDL::fadeScreen() { - const int bufferSize = _screenH * _screenW * sizeof(uint16_t); - if (!_fadeScreenBuffer) { - _fadeScreenBuffer = (uint16_t *)malloc(bufferSize); - if (!_fadeScreenBuffer) { - warning("SystemStub_SDL::fadeScreen() Unable to allocate buffer size %d", bufferSize); - return; - } - } _fadeOnUpdateScreen = true; - memcpy(_fadeScreenBuffer, _screenBuffer + _screenW + 1, bufferSize); -} - -static uint16_t blendPixel16(uint16_t colorSrc, uint16_t colorDst, uint32_t mask, int step) { - const uint32_t pSrc = (colorSrc | (colorSrc << 16)) & mask; - const uint32_t pDst = (colorDst | (colorDst << 16)) & mask; - const uint32_t pRes = ((pDst - pSrc) * step / 16 + pSrc) & mask; - return pRes | (pRes >> 16); } void SystemStub_SDL::updateScreen(int shakeOffset) { -#if SDL_VERSION_ATLEAST(2, 0, 0) 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); + assert((pitch & 3) == 0); + _scaler->scale(_scaleFactor, (uint32_t *)dst, pitch / sizeof(uint32_t), _screenBuffer, _screenW, _screenW, _screenH); SDL_UnlockTexture(_texture); } } else { - SDL_UpdateTexture(_texture, 0, _screenBuffer + _screenW + 1, _screenW * sizeof(uint16_t)); + SDL_UpdateTexture(_texture, 0, _screenBuffer, _screenW * sizeof(uint32_t)); } SDL_RenderClear(_renderer); if (_fadeOnUpdateScreen) { @@ -256,12 +241,13 @@ void SystemStub_SDL::updateScreen(int shakeOffset) { SDL_Delay(30); } _fadeOnUpdateScreen = false; + SDL_SetRenderDrawBlendMode(_renderer, SDL_BLENDMODE_NONE); return; } if (shakeOffset != 0) { SDL_Rect r; r.x = 0; - r.y = shakeOffset * _scalers[_scaler].factor; + r.y = shakeOffset * _scaleFactor; SDL_GetRendererOutputSize(_renderer, &r.w, &r.h); r.h -= r.y; SDL_RenderCopy(_renderer, _texture, 0, &r); @@ -269,65 +255,6 @@ void SystemStub_SDL::updateScreen(int shakeOffset) { SDL_RenderCopy(_renderer, _texture, 0, 0); } SDL_RenderPresent(_renderer); -#else - const int mul = _scalers[_scaler].factor; - if (_fadeOnUpdateScreen) { - const int tempScreenBufferSize = (_screenH + 2) * (_screenW + 2) * sizeof(uint16_t); - uint16_t *tempScreenBuffer = (uint16_t *)calloc(tempScreenBufferSize, 1); - assert(tempScreenBuffer); - const uint32_t colorMask = (_fmt->Gmask << 16) | (_fmt->Rmask | _fmt->Bmask); - const uint16_t *screenBuffer = _screenBuffer + _screenW + 1; - for (int i = 1; i <= 16; ++i) { - for (int x = 0; x < _screenH * _screenW; ++x) { - tempScreenBuffer[_screenW + 1 + x] = blendPixel16(_fadeScreenBuffer[x], screenBuffer[x], colorMask, i); - } - SDL_LockSurface(_surface); - uint16_t *dst = (uint16_t *)_surface->pixels; - const uint16_t *src = tempScreenBuffer + _screenW + 1; - (*_scalers[_scaler].proc)(dst, _surface->pitch, src, _screenW, _screenW, _screenH); - SDL_UnlockSurface(_surface); - SDL_UpdateRect(_surface, 0, 0, _screenW * mul, _screenH * mul); - SDL_Delay(30); - } - free(tempScreenBuffer); - _fadeOnUpdateScreen = false; - return; - } - if (shakeOffset == 0) { - for (int i = 0; i < _numBlitRects; ++i) { - SDL_Rect *br = &_blitRects[i]; - int dx = br->x * mul; - int dy = br->y * mul; - SDL_LockSurface(_surface); - uint16_t *dst = (uint16_t *)_surface->pixels + dy * _surface->pitch / 2 + dx; - const uint16_t *src = _screenBuffer + (br->y + 1) * _screenW + (br->x + 1); - (*_scalers[_scaler].proc)(dst, _surface->pitch, src, _screenW, br->w, br->h); - SDL_UnlockSurface(_surface); - br->x *= mul; - br->y *= mul; - br->w *= mul; - br->h *= mul; - } - SDL_UpdateRects(_surface, _numBlitRects, _blitRects); - } else { - SDL_LockSurface(_surface); - int w = _screenW; - int h = _screenH - shakeOffset; - uint16_t *dst = (uint16_t *)_surface->pixels + shakeOffset * mul * _surface->pitch / 2; - const uint16_t *src = _screenBuffer + _screenW + 1; - (*_scalers[_scaler].proc)(dst, _surface->pitch, src, _screenW, w, h); - SDL_UnlockSurface(_surface); - - SDL_Rect r; - r.x = 0; - r.y = 0; - r.w = _screenW * mul; - r.h = shakeOffset * mul; - SDL_FillRect(_surface, &r, _pal[_overscanColor]); - - SDL_UpdateRect(_surface, 0, 0, _screenW * mul, _screenH * mul); - } -#endif _numBlitRects = 0; } @@ -349,11 +276,10 @@ void SystemStub_SDL::processEvents() { } void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) { - switch (ev.type) { - case SDL_QUIT: - _pi.quit = true; - break; -#if SDL_VERSION_ATLEAST(2, 0, 0) + switch (ev.type) { + case SDL_QUIT: + _pi.quit = true; + break; case SDL_WINDOWEVENT: switch (ev.window.event) { case SDL_WINDOWEVENT_FOCUS_GAINED: @@ -363,14 +289,6 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) { break; } break; -#else - case SDL_ACTIVEEVENT: - if (ev.active.state & SDL_APPINPUTFOCUS) { - paused = ev.active.gain == 0; - SDL_PauseAudio(paused ? 1 : 0); - } - break; -#endif case SDL_JOYHATMOTION: if (_joystick) { _pi.dirMask = 0; @@ -430,7 +348,6 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) { } } break; -#if SDL_VERSION_ATLEAST(2, 0, 0) case SDL_CONTROLLERAXISMOTION: if (_controller) { switch (ev.caxis.axis) { @@ -515,118 +432,133 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) { } } break; -#endif - case SDL_KEYUP: + case SDL_KEYUP: + if (ev.key.keysym.mod & KMOD_ALT) { switch (ev.key.keysym.sym) { - case SDLK_LEFT: - _pi.dirMask &= ~PlayerInput::DIR_LEFT; - break; - case SDLK_RIGHT: - _pi.dirMask &= ~PlayerInput::DIR_RIGHT; - break; - case SDLK_UP: - _pi.dirMask &= ~PlayerInput::DIR_UP; - break; - case SDLK_DOWN: - _pi.dirMask &= ~PlayerInput::DIR_DOWN; - break; - case SDLK_SPACE: - _pi.space = false; - break; - case SDLK_RSHIFT: - case SDLK_LSHIFT: - _pi.shift = false; - break; case SDLK_RETURN: - _pi.enter = false; + changeGraphics(!_fullscreen, _scaleFactor); break; - case SDLK_ESCAPE: - _pi.escape = false; + case SDLK_KP_PLUS: + case SDLK_PAGEUP: + changeGraphics(_fullscreen, _scaleFactor + 1); break; - default: + case SDLK_KP_MINUS: + case SDLK_PAGEDOWN: + changeGraphics(_fullscreen, _scaleFactor - 1); + break; + case SDLK_s: { + char name[32]; + snprintf(name, sizeof(name), "screenshot-%03d.tga", _screenshot); + saveTGA(name, (const uint8_t *)_screenBuffer, _screenW, _screenH); + ++_screenshot; + debug(DBG_INFO, "Written '%s'", name); + } + break; + case SDLK_x: + _pi.quit = true; break; } break; - case SDL_KEYDOWN: - if (ev.key.keysym.mod & KMOD_ALT) { - if (ev.key.keysym.sym == SDLK_RETURN) { - changeGraphics(!_fullscreen, _scaler); - } else if (ev.key.keysym.sym == SDLK_KP_PLUS || ev.key.keysym.sym == SDLK_PAGEUP) { - uint8_t s = _scaler + 1; - if (s < NUM_SCALERS) { - changeGraphics(_fullscreen, s); - } - } else if (ev.key.keysym.sym == SDLK_KP_MINUS || ev.key.keysym.sym == SDLK_PAGEDOWN) { - int8_t s = _scaler - 1; - if (_scaler > 0) { - changeGraphics(_fullscreen, s); - } - } else if (ev.key.keysym.sym == SDLK_s) { -#if SDL_VERSION_ATLEAST(2, 0, 0) -#else - char name[32]; - snprintf(name, sizeof(name), "screenshot-%03d.bmp", _screenshot); - SDL_SaveBMP(_surface, name); - ++_screenshot; - debug(DBG_INFO, "Written '%s'", name); -#endif - } - break; - } else if (ev.key.keysym.mod & KMOD_CTRL) { - if (ev.key.keysym.sym == SDLK_f) { - _pi.dbgMask ^= PlayerInput::DF_FASTMODE; - } else if (ev.key.keysym.sym == SDLK_b) { - _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_s) { - _pi.save = true; - } else if (ev.key.keysym.sym == SDLK_l) { - _pi.load = true; - } else if (ev.key.keysym.sym == SDLK_KP_PLUS || ev.key.keysym.sym == SDLK_PAGEUP) { - _pi.stateSlot = 1; - } else if (ev.key.keysym.sym == SDLK_KP_MINUS || ev.key.keysym.sym == SDLK_PAGEDOWN) { - _pi.stateSlot = -1; - } - } - _pi.lastChar = ev.key.keysym.sym; + } else if (ev.key.keysym.mod & KMOD_CTRL) { switch (ev.key.keysym.sym) { - case SDLK_LEFT: - _pi.dirMask |= PlayerInput::DIR_LEFT; + case SDLK_f: + _pi.dbgMask ^= PlayerInput::DF_FASTMODE; break; - case SDLK_RIGHT: - _pi.dirMask |= PlayerInput::DIR_RIGHT; + case SDLK_b: + _pi.dbgMask ^= PlayerInput::DF_DBLOCKS; break; - case SDLK_UP: - _pi.dirMask |= PlayerInput::DIR_UP; + case SDLK_i: + _pi.dbgMask ^= PlayerInput::DF_SETLIFE; break; - case SDLK_DOWN: - _pi.dirMask |= PlayerInput::DIR_DOWN; + case SDLK_s: + _pi.save = true; break; - case SDLK_BACKSPACE: - case SDLK_TAB: - _pi.backspace = true; + case SDLK_l: + _pi.load = true; break; - case SDLK_SPACE: - _pi.space = true; + case SDLK_KP_PLUS: + case SDLK_PAGEUP: + _pi.stateSlot = 1; break; - case SDLK_RSHIFT: - case SDLK_LSHIFT: - _pi.shift = true; - break; - case SDLK_RETURN: - _pi.enter = true; - break; - case SDLK_ESCAPE: - _pi.escape = true; - break; - default: + case SDLK_KP_MINUS: + case SDLK_PAGEDOWN: + _pi.stateSlot = -1; break; } break; + } + _pi.lastChar = ev.key.keysym.sym; + switch (ev.key.keysym.sym) { + case SDLK_LEFT: + _pi.dirMask &= ~PlayerInput::DIR_LEFT; + break; + case SDLK_RIGHT: + _pi.dirMask &= ~PlayerInput::DIR_RIGHT; + break; + case SDLK_UP: + _pi.dirMask &= ~PlayerInput::DIR_UP; + break; + case SDLK_DOWN: + _pi.dirMask &= ~PlayerInput::DIR_DOWN; + break; + case SDLK_SPACE: + _pi.space = false; + break; + case SDLK_RSHIFT: + case SDLK_LSHIFT: + _pi.shift = false; + break; + case SDLK_RETURN: + _pi.enter = false; + break; + case SDLK_ESCAPE: + _pi.escape = false; + break; default: break; } + break; + case SDL_KEYDOWN: + if (ev.key.keysym.mod & (KMOD_ALT | KMOD_CTRL)) { + break; + } + switch (ev.key.keysym.sym) { + case SDLK_LEFT: + _pi.dirMask |= PlayerInput::DIR_LEFT; + break; + case SDLK_RIGHT: + _pi.dirMask |= PlayerInput::DIR_RIGHT; + break; + case SDLK_UP: + _pi.dirMask |= PlayerInput::DIR_UP; + break; + case SDLK_DOWN: + _pi.dirMask |= PlayerInput::DIR_DOWN; + break; + case SDLK_BACKSPACE: + case SDLK_TAB: + _pi.backspace = true; + break; + case SDLK_SPACE: + _pi.space = true; + break; + case SDLK_RSHIFT: + case SDLK_LSHIFT: + _pi.shift = true; + break; + case SDLK_RETURN: + _pi.enter = true; + break; + case SDLK_ESCAPE: + _pi.escape = true; + break; + default: + break; + } + break; + default: + break; + } } void SystemStub_SDL::sleep(int duration) { @@ -678,48 +610,38 @@ void SystemStub_SDL::unlockAudio() { } void SystemStub_SDL::prepareGraphics() { -#if SDL_VERSION_ATLEAST(2, 0, 0) - switch (_scaler) { - case SCALER_SCALE_2X: - 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: + _texW = _screenW; + _texH = _screenH; + switch (_scalerType) { + case kScalerTypePoint: SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); // nearest pixel sampling - _texW = _screenW; - _texH = _screenH; + break; + case kScalerTypeLinear: + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); + break; + case kScalerTypeInternal: + case kScalerTypeExternal: + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); + _texW *= _scaleFactor; + _texH *= _scaleFactor; break; } - const int windowW = _screenW * _scalers[_scaler].factor; - const int windowH = _screenH * _scalers[_scaler].factor; + const int windowW = _screenW * _scaleFactor; + const int windowH = _screenH * _scaleFactor; int flags = 0; if (_fullscreen) { flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; } _window = SDL_CreateWindow(_caption, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowW, windowH, flags); + SDL_Surface *icon = SDL_LoadBMP(kIconBmp); + if (icon) { + SDL_SetWindowIcon(_window, icon); + SDL_FreeSurface(icon); + } _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, _texW, _texH); _fmt = SDL_AllocFormat(kPixelFormat); -#else - SDL_WM_SetCaption(_caption, NULL); - const int w = _screenW * _scalers[_scaler].factor; - const int h = _screenH * _scalers[_scaler].factor; - int flags = SDL_HWSURFACE; - if (_fullscreen) { - flags |= SDL_FULLSCREEN; - } - static const int kBitDepth = 16; - _surface = SDL_SetVideoMode(w, h, kBitDepth, flags); - if (!_surface) { - error("SystemStub_SDL::prepareGraphics() Unable to allocate _screen buffer"); - } - _fmt = _surface->format; -#endif forceGraphicsRedraw(); } @@ -728,11 +650,6 @@ void SystemStub_SDL::cleanupGraphics() { free(_screenBuffer); _screenBuffer = 0; } - if (_fadeScreenBuffer) { - free(_fadeScreenBuffer); - _fadeScreenBuffer = 0; - } -#if SDL_VERSION_ATLEAST(2, 0, 0) if (_window) { SDL_DestroyWindow(_window); _window = 0; @@ -745,20 +662,9 @@ void SystemStub_SDL::cleanupGraphics() { SDL_FreeFormat(_fmt); _fmt = 0; } -#else - if (_surface) { - // freed by SDL_Quit() - _surface = 0; - } -#endif } -void SystemStub_SDL::changeGraphics(bool fullscreen, uint8_t scaler) { - if (_fadeScreenBuffer) { - free(_fadeScreenBuffer); - _fadeScreenBuffer = 0; - } -#if SDL_VERSION_ATLEAST(2, 0, 0) +void SystemStub_SDL::changeGraphics(bool fullscreen, int scaleFactor) { if (_window) { SDL_DestroyWindow(_window); _window = 0; @@ -771,28 +677,11 @@ void SystemStub_SDL::changeGraphics(bool fullscreen, uint8_t scaler) { SDL_FreeFormat(_fmt); _fmt = 0; } -#else - SDL_FreeSurface(_surface); - _surface = 0; -#endif _fullscreen = fullscreen; - _scaler = scaler; - prepareGraphics(); - forceGraphicsRedraw(); -} - -void SystemStub_SDL::flipGraphics() { - uint16_t scanline[256]; - assert(_screenW <= 256); - uint16_t *p = _screenBuffer + _screenW + 1; - for (int y = 0; y < _screenH; ++y) { - p += _screenW; - for (int x = 0; x < _screenW; ++x) { - scanline[x] = *--p; - } - memcpy(p, scanline, _screenW * sizeof(uint16_t)); - p += _screenW; + if (scaleFactor >= _scaler->factorMin && scaleFactor <= _scaler->factorMax) { + _scaleFactor = scaleFactor; } + prepareGraphics(); forceGraphicsRedraw(); } @@ -804,17 +693,16 @@ void SystemStub_SDL::forceGraphicsRedraw() { _blitRects[0].h = _screenH; } -void SystemStub_SDL::drawRect(SDL_Rect *rect, uint8_t color, uint16_t *dst, uint16_t dstPitch) { - dstPitch >>= 1; +void SystemStub_SDL::drawRect(SDL_Rect *rect, uint8_t color) { int x1 = rect->x; int y1 = rect->y; int x2 = rect->x + rect->w - 1; int y2 = rect->y + rect->h - 1; assert(x1 >= 0 && x2 < _screenW && y1 >= 0 && y2 < _screenH); for (int i = x1; i <= x2; ++i) { - *(dst + y1 * dstPitch + i) = *(dst + y2 * dstPitch + i) = _pal[color]; + *(_screenBuffer + y1 * _screenW + i) = *(_screenBuffer + y2 * _screenW + i) = _rgbPalette[color]; } for (int j = y1; j <= y2; ++j) { - *(dst + j * dstPitch + x1) = *(dst + j * dstPitch + x2) = _pal[color]; + *(_screenBuffer + j * _screenW + x1) = *(_screenBuffer + j * _screenW + x2) = _rgbPalette[color]; } }