[Scummvm-git-logs] scummvm master -> 047f3fbfea170cf8b713b09fa6cd6a86b364272d
bluegr
noreply at scummvm.org
Tue Dec 24 11:15:40 UTC 2024
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
047f3fbfea SCI: cleanup and reorganize gfx drivers
Commit: 047f3fbfea170cf8b713b09fa6cd6a86b364272d
https://github.com/scummvm/scummvm/commit/047f3fbfea170cf8b713b09fa6cd6a86b364272d
Author: athrxx (athrxx at scummvm.org)
Date: 2024-12-24T13:15:37+02:00
Commit Message:
SCI: cleanup and reorganize gfx drivers
gfxdrivers.cpp has become quite large. So I've now made a
separate file for each driver. I also separated the mode
validation and driver init code from the enigine and put
it into an extra file.
Changed paths:
A engines/sci/graphics/drivers/cga.cpp
A engines/sci/graphics/drivers/cgabw.cpp
A engines/sci/graphics/drivers/common.cpp
A engines/sci/graphics/drivers/default.cpp
A engines/sci/graphics/drivers/ega.cpp
A engines/sci/graphics/drivers/gfxdriver.h
A engines/sci/graphics/drivers/gfxdriver_intern.h
A engines/sci/graphics/drivers/hercules.cpp
A engines/sci/graphics/drivers/init.cpp
A engines/sci/graphics/drivers/pc98_16col.cpp
A engines/sci/graphics/drivers/pc98_8col_sci0.cpp
A engines/sci/graphics/drivers/pc98_8col_sci1.cpp
A engines/sci/graphics/drivers/upscaled.cpp
A engines/sci/graphics/drivers/vgagrey.cpp
A engines/sci/graphics/drivers/win16col.cpp
A engines/sci/graphics/drivers/win256col.cpp
R engines/sci/graphics/gfxdrivers.cpp
R engines/sci/graphics/gfxdrivers.h
engines/sci/engine/kgraphics.cpp
engines/sci/engine/kmisc.cpp
engines/sci/engine/kvideo.cpp
engines/sci/event.cpp
engines/sci/graphics/controls16.cpp
engines/sci/graphics/cursor.cpp
engines/sci/graphics/fontsjis.cpp
engines/sci/graphics/maciconbar.cpp
engines/sci/graphics/paint16.cpp
engines/sci/graphics/palette.cpp
engines/sci/graphics/portrait.cpp
engines/sci/graphics/screen.cpp
engines/sci/graphics/transitions.cpp
engines/sci/graphics/view.cpp
engines/sci/module.mk
engines/sci/sci.cpp
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index 488317e8831..538a562f7f9 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -43,7 +43,7 @@
#include "sci/graphics/compare.h"
#include "sci/graphics/controls16.h"
#include "sci/graphics/cursor.h"
-#include "sci/graphics/gfxdrivers.h"
+#include "sci/graphics/drivers/gfxdriver.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/paint16.h"
#include "sci/graphics/picture.h"
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index 2af7dc587d1..0db69581e9e 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -35,7 +35,7 @@
#endif
#include "sci/engine/savegame.h"
#include "sci/graphics/cursor.h"
-#include "sci/graphics/gfxdrivers.h"
+#include "sci/graphics/drivers/gfxdriver.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/screen.h"
#ifdef ENABLE_SCI32
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index 8beb1e6a5ea..c427ed446d3 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -23,7 +23,7 @@
#include "sci/engine/state.h"
#include "sci/graphics/helpers.h"
#include "sci/graphics/cursor.h"
-#include "sci/graphics/gfxdrivers.h"
+#include "sci/graphics/drivers/gfxdriver.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/screen.h"
#include "sci/util.h"
diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp
index 87ba1fddfba..c32175fb8e4 100644
--- a/engines/sci/event.cpp
+++ b/engines/sci/event.cpp
@@ -28,7 +28,7 @@
#include "sci/console.h"
#include "sci/engine/state.h"
#include "sci/engine/kernel.h"
-#include "sci/graphics/gfxdrivers.h"
+#include "sci/graphics/drivers/gfxdriver.h"
#ifdef ENABLE_SCI32
#include "sci/graphics/cursor32.h"
#include "sci/graphics/frameout.h"
diff --git a/engines/sci/graphics/controls16.cpp b/engines/sci/graphics/controls16.cpp
index 53a8845b8ca..ac9c96f2771 100644
--- a/engines/sci/graphics/controls16.cpp
+++ b/engines/sci/graphics/controls16.cpp
@@ -32,7 +32,7 @@
#include "sci/engine/selector.h"
#include "sci/engine/tts.h"
#include "sci/graphics/compare.h"
-#include "sci/graphics/gfxdrivers.h"
+#include "sci/graphics/drivers/gfxdriver.h"
#include "sci/graphics/ports.h"
#include "sci/graphics/paint16.h"
#include "sci/graphics/scifont.h"
diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp
index 90fadeaf186..28a9f2e8c31 100644
--- a/engines/sci/graphics/cursor.cpp
+++ b/engines/sci/graphics/cursor.cpp
@@ -30,7 +30,7 @@
#include "sci/sci.h"
#include "sci/event.h"
#include "sci/engine/state.h"
-#include "sci/graphics/gfxdrivers.h"
+#include "sci/graphics/drivers/gfxdriver.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/coordadjuster.h"
diff --git a/engines/sci/graphics/drivers/cga.cpp b/engines/sci/graphics/drivers/cga.cpp
new file mode 100644
index 00000000000..b3de66a7b72
--- /dev/null
+++ b/engines/sci/graphics/drivers/cga.cpp
@@ -0,0 +1,224 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "common/file.h"
+#include "common/system.h"
+#include "graphics/cursorman.h"
+#include "sci/graphics/drivers/gfxdriver_intern.h"
+
+namespace Sci {
+
+class SCI0_CGADriver final : public SCI0_DOSPreVGADriver {
+public:
+ SCI0_CGADriver(bool emulateCGAModeOnEGACard, bool rgbRendering);
+ ~SCI0_CGADriver() override;
+ void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod*, const byte*) override;
+ void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
+ static bool validateMode(Common::Platform p) { return (p == Common::kPlatformDOS) && checkDriver(&_driverFile, 1); }
+private:
+ void setupRenderProc() override;
+ uint16 *_cgaPatterns;
+ byte _palette[12];
+ const bool _disableMode5;
+ typedef void (*LineProc)(byte*&, const byte*, int, int, int, const uint16*, const byte*);
+ LineProc _renderLine;
+ static const char *_driverFile;
+};
+
+SCI0_CGADriver::SCI0_CGADriver(bool emulateCGAModeOnEGACard, bool rgbRendering) : SCI0_DOSPreVGADriver(4, 320, 200, rgbRendering), _cgaPatterns(nullptr), _disableMode5(emulateCGAModeOnEGACard), _renderLine(nullptr) {
+ static const byte cgaColors[48] = {
+ /*
+ // Canonical CGA palette
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0x00, 0xAA, 0xAA,
+ 0xAA, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0xAA, 0x55, 0x00, 0xAA, 0xAA, 0xAA,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0x55, 0x55, 0xFF, 0xFF,
+ 0xFF, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0xFF, 0xFF, 0x55, 0xFF, 0xFF, 0xFF
+ */
+ // Improved palette model taken from https://int10h.org/blog/2022/06/ibm-5153-color-true-cga-palette/
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x00, 0xC4, 0x00, 0x00, 0xC4, 0xC4,
+ 0xC4, 0x00, 0x00, 0xC4, 0x00, 0xC4, 0xC4, 0x7E, 0x00, 0xC4, 0xC4, 0xC4,
+ 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0xDC, 0x4E, 0xDC, 0x4E, 0x4E, 0xF3, 0xF3,
+ 0xDC, 0x4E, 0x4E, 0xF3, 0x4E, 0xF3, 0xF3, 0xF3, 0x4E, 0xFF, 0xFF, 0xFF
+ };
+
+ static const byte modeColorMap[3][4] = {
+ { 0, 2, 4, 6 },
+ { 0, 3, 5, 7 },
+ { 0, 3, 4, 7 }
+ };
+
+ Common::File drv;
+ if (!drv.open(_driverFile))
+ GFXDRV_ERR_OPEN(_driverFile);
+
+ byte palIndex = 1;
+ byte palIntensity = 1;
+ byte mode = 4;
+
+ byte colMap[4];
+ memset(colMap, 0, sizeof(colMap));
+
+ uint16 eprcOffs = 0;
+
+ uint32 cmd = drv.readUint32LE();
+ if ((cmd & 0xFF) == 0xE9)
+ eprcOffs = ((cmd >> 8) & 0xFFFF) + 3;
+
+ if (!eprcOffs || drv.readUint32LE() != 0x87654321 || !drv.skip(1) || !drv.seek(drv.readByte(), SEEK_CUR) || !drv.seek(drv.readByte(), SEEK_CUR))
+ GFXDRV_ERR_VERSION(_driverFile);
+
+ drv.skip(drv.readByte() == 0x90 ? 2 : 1);
+
+ uint16 op1st = drv.readUint16LE();
+ int op1len = drv.readUint16LE() - op1st;
+
+ // sanity check
+ assert(op1len > 0 && op1len < 0x100);
+
+ drv.seek(op1st, SEEK_SET);
+ byte *buf = new byte[op1len]();
+ drv.read(buf, op1len);
+
+ // Try figuring out the correct settings...
+ for (int i = 0; i < op1len - 7; ++i) {
+ uint32 cfg = READ_BE_UINT32(buf + i);
+ cmd = READ_BE_UINT32(buf + 4 + i);
+ if ((cmd >> 16) == 0xCD10 && (cfg & 0xff00ff) == 0xB80000) {
+ mode = (cfg >> 8) & 0xff;
+ } else if (cmd == 0xB40BCD10) {
+ if (cfg >> 8 == 0x00B701B3) {
+ palIndex = cfg & 1;
+ palIntensity = (cfg >> 4) & 1;
+ } else if (cfg >> 8 == 0x00B700B3) {
+ colMap[0] = (cfg & 0x0f) + ((cfg & 0x10) >> 1);
+ }
+ }
+ }
+
+ delete[] buf;
+
+ assert(palIndex <= 1);
+ assert(palIntensity <= 1);
+
+ for (int i = 1; i < 4; ++i)
+ colMap[i] = modeColorMap[(!_disableMode5 && mode == 5) ? 2 : palIndex][i] + (palIntensity << 3);
+
+ memset (_palette, 0, sizeof(_palette));
+ for (int i = 0; i < 4; ++i) {
+ for (int ii = 0; ii < 3; ++ii)
+ _palette[i * 3 + ii] = cgaColors[colMap[i] * 3 + ii];
+ }
+
+ assignPalette(_palette);
+
+ _cgaPatterns = new uint16[256]();
+ // The pattern map is always located right before the driver entry point proc.
+ drv.seek(eprcOffs - 512, SEEK_SET);
+ for (int i = 0; i < 256; ++i)
+ _cgaPatterns[i] = drv.readUint16LE();
+
+ drv.close();
+}
+
+SCI0_CGADriver::~SCI0_CGADriver() {
+ delete[] _cgaPatterns;
+}
+
+void SCI0_CGADriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod*, const byte*) {
+ GFXDRV_ASSERT_READY;
+
+ byte diff = srcX & 1;
+ srcX &= ~1;
+ destX &= ~1;
+ w = (w + diff + 1) & ~1;
+
+ src += (srcY * pitch + srcX);
+
+ byte *dst = _compositeBuffer;
+ int ty = destY;
+
+ for (int i = 0; i < h; ++i) {
+ _renderLine(dst, src, w, srcX & 3, ++ty, _cgaPatterns, _internalPalette);
+ src += pitch;
+ }
+
+ g_system->copyRectToScreen(_compositeBuffer, w * _pixelSize, destX, destY, w, h);
+}
+
+void SCI0_CGADriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
+ GFXDRV_ASSERT_READY;
+ // Instead of implementing the original cursor rendering code, we rely on the 8 bit cursor
+ // that has already been generated by the engine. We simply convert the colors as needed...
+ assert(keycolor == 1);
+ const byte *s = reinterpret_cast<const byte*>(cursor);
+ byte *d = _compositeBuffer;
+ for (uint i = w * h; i; --i)
+ *d++ = *s++ & 3;
+
+ CursorMan.replaceCursor(_compositeBuffer, w, h, hotspotX, hotspotY, keycolor);
+}
+
+
+template <typename T> void cgaRenderLine(byte *&dst, const byte *src, int w, int tx, int ty, const uint16 *patterns, const byte *pal) {
+ T *d = reinterpret_cast<T*>(dst);
+ const T *p = reinterpret_cast<const T*>(pal);
+ w >>= 1;
+
+ for (int i = 0; i < w; ++i) {
+ uint16 pattern = patterns[((src[0] & 0x0f) << 4) | (src[1] & 0x0f)];
+ src += 2;
+ byte sh = (ty & 3) << 1;
+ byte lo = ((pattern & 0xff) >> sh) | ((pattern & 0xff) << (8 - sh));
+ byte hi = (pattern >> (8 + sh)) | ((pattern >> 8) << (8 - sh));
+ if (sizeof(T) == 1) {
+ *d++ = (lo >> (6 - (tx << 1))) & 3;
+ *d++ = (hi >> (4 - (tx << 1))) & 3;
+ } else {
+ *d++ = p[(lo >> (6 - (tx << 1))) & 3];
+ *d++ = p[(hi >> (4 - (tx << 1))) & 3];
+ }
+ tx ^= 2;
+ }
+
+ dst = reinterpret_cast<byte*>(d);
+}
+
+void SCI0_CGADriver::setupRenderProc() {
+ static const LineProc lineProcs[] = {
+ &cgaRenderLine<byte>,
+ &cgaRenderLine<uint16>,
+ &cgaRenderLine<uint32>
+ };
+
+ assert((_pixelSize >> 1) < ARRAYSIZE(lineProcs));
+ _renderLine = lineProcs[_pixelSize >> 1];
+}
+
+const char *SCI0_CGADriver::_driverFile = "CGA320C.DRV";
+
+SCI_GFXDRV_VALIDATE_IMPL(SCI0_CGA)
+
+GfxDriver *SCI0_CGADriver_create(int rgbRendering, ...) {
+ return new SCI0_CGADriver(false, rgbRendering != 0);
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/drivers/cgabw.cpp b/engines/sci/graphics/drivers/cgabw.cpp
new file mode 100644
index 00000000000..cab0c390eb5
--- /dev/null
+++ b/engines/sci/graphics/drivers/cgabw.cpp
@@ -0,0 +1,222 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "common/file.h"
+#include "common/system.h"
+#include "graphics/cursorman.h"
+#include "sci/graphics/drivers/gfxdriver_intern.h"
+
+namespace Sci {
+
+class SCI0_CGABWDriver final : public SCI0_DOSPreVGADriver {
+public:
+ SCI0_CGABWDriver(uint32 monochromeColor, bool rgbRendering);
+ ~SCI0_CGABWDriver() override;
+ void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod*, const byte*) override;
+ void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
+ Common::Point getMousePos() const override;
+ void setMousePos(const Common::Point &pos) const override;
+ void setShakePos(int shakeXOffset, int shakeYOffset) const override;
+ void clearRect(const Common::Rect &r) const override;
+ Common::Point getRealCoords(Common::Point &pos) const override;
+ static bool validateMode(Common::Platform p) { return (p == Common::kPlatformDOS) && checkDriver(_driverFiles, 2); }
+private:
+ void setupRenderProc() override;
+ byte _monochromePalette[6];
+ const byte *_monochromePatterns;
+ bool _earlyVersion;
+ typedef void (*LineProc)(byte*&, const byte*, int, int, int, const byte*, const byte*);
+ LineProc _renderLine;
+ static const char *_driverFiles[2];
+};
+
+SCI0_CGABWDriver::SCI0_CGABWDriver(uint32 monochromeColor, bool rgbRendering) : SCI0_DOSPreVGADriver(2, 640, 400, rgbRendering), _monochromePatterns(nullptr), _earlyVersion(false), _renderLine(nullptr) {
+ _monochromePalette[0] = _monochromePalette[1] = _monochromePalette[2] = 0;
+ _monochromePalette[3] = (monochromeColor >> 16) & 0xff;
+ _monochromePalette[4] = (monochromeColor >> 8) & 0xff;
+ _monochromePalette[5] = monochromeColor & 0xff;
+ assignPalette(_monochromePalette);
+
+ if (!(_monochromePatterns = SciGfxDrvInternal::monochrInit(_driverFiles[0], _earlyVersion)) && !(_monochromePatterns = SciGfxDrvInternal::monochrInit(_driverFiles[1], _earlyVersion)))
+ error("Failed to open '%s' or '%s'", _driverFiles[0], _driverFiles[1]);
+}
+
+SCI0_CGABWDriver::~SCI0_CGABWDriver() {
+ delete[] _monochromePatterns;
+}
+
+void SCI0_CGABWDriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod*, const byte*) {
+ GFXDRV_ASSERT_READY;
+
+ byte *dst = _compositeBuffer;
+ int ty = destY & 7;
+
+ if (_earlyVersion) {
+ ++ty;
+ byte diff = srcX & 1;
+ srcX &= ~1;
+ destX &= ~1;
+ w = (w + diff + 1) & ~1;
+ }
+
+ src += (srcY * pitch + srcX);
+
+ for (int i = 0; i < h; ++i) {
+ _renderLine(dst, src, w, srcX & 3, ty, _monochromePatterns, _internalPalette);
+ ty = (ty + 1) & 7;
+ src += pitch;
+ }
+
+ g_system->copyRectToScreen(_compositeBuffer, (w << 1) * _pixelSize, destX << 1, destY << 1, w << 1, h << 1);
+}
+
+void SCI0_CGABWDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
+ GFXDRV_ASSERT_READY;
+ // Instead of implementing the original cursor rendering code, we rely on the 8 bit cursor that
+ // has already been generated by the engine. We simply convert the colors as needed and scale the cursor...
+ assert(keycolor == 1);
+ keycolor = 0x0f;
+ w <<= 1;
+ const byte *s = reinterpret_cast<const byte*>(cursor);
+ byte *d0 = _compositeBuffer;
+ byte *d1 = _compositeBuffer + w;
+
+ for (uint i = 0; i < h; ++i) {
+ for (uint ii = 0; ii < w; ++ii) {
+ *d0++ = *d1++ = *s ? (*s ^ 0x0e) : 0;
+ if (ii & 1)
+ ++s;
+ }
+ d0 += w;
+ d1 += w;
+ }
+
+ CursorMan.replaceCursor(_compositeBuffer, w, h << 1, hotspotX << 1, hotspotY << 1, keycolor);
+}
+
+Common::Point SCI0_CGABWDriver::getMousePos() const {
+ Common::Point res = GfxDriver::getMousePos();
+ res.x >>= 1;
+ res.y >>= 1;
+ return res;
+}
+
+void SCI0_CGABWDriver::setMousePos(const Common::Point &pos) const {
+ g_system->warpMouse(pos.x << 1, pos.y << 1);
+}
+
+void SCI0_CGABWDriver::setShakePos(int shakeXOffset, int shakeYOffset) const {
+ g_system->setShakePos(shakeXOffset << 1, shakeYOffset << 1);
+}
+
+void SCI0_CGABWDriver::clearRect(const Common::Rect &r) const {
+ Common::Rect r2(r.left << 1, r.top << 1, r.right << 1, r.bottom << 1);
+ GfxDriver::clearRect(r2);
+}
+
+Common::Point SCI0_CGABWDriver::getRealCoords(Common::Point &pos) const {
+ return Common::Point(pos.x << 1, pos.y << 1);
+}
+
+template <typename T> void cgabwRenderLine_v1(byte *&dst, const byte *src, int w, int tx, int ty, const byte *patterns, const byte *pal) {
+ const T *p = reinterpret_cast<const T*>(pal);
+ const uint16 *patterns16 = reinterpret_cast<const uint16*>(patterns);
+ T *d1 = reinterpret_cast<T*>(dst);
+ T *d2 = d1 + (w << 1);
+ w >>= 1;
+
+ for (int i = 0; i < w; ++i) {
+ uint16 pt = patterns16[((src[0] & 0x0f) << 4) | (src[1] & 0x0f)];
+ src += 2;
+ byte sh = (ty & 3) << 1;
+ byte lo = ((pt & 0xff) >> sh) | ((pt & 0xff) << (8 - sh));
+ byte hi = (pt >> (8 + sh)) | ((pt >> 8) << (8 - sh));
+ if (sizeof(T) == 1) {
+ *d1++ = *d2++ = ((lo >> (6 - (tx << 1))) >> 1) & 1;
+ *d1++ = *d2++ = (lo >> (6 - (tx << 1))) & 1;
+ *d1++ = *d2++ = ((hi >> (4 - (tx << 1))) >> 1) & 1;
+ *d1++ = *d2++ = (hi >> (4 - (tx << 1))) & 1;
+ } else {
+ *d1++ = *d2++ = p[((lo >> (6 - (tx << 1))) >> 1) & 1];
+ *d1++ = *d2++ = p[(lo >> (6 - (tx << 1))) & 1];
+ *d1++ = *d2++ = p[((hi >> (4 - (tx << 1))) >> 1) & 1];
+ *d1++ = *d2++ = p[(hi >> (4 - (tx << 1))) & 1];
+ }
+ tx ^= 2;
+ }
+
+ dst = reinterpret_cast<byte*>(d2);
+}
+
+template <typename T> void cgabwRenderLine_v2(byte *&dst, const byte *src, int w, int tx, int ty, const byte *patterns, const byte *pal) {
+ const T *p = reinterpret_cast<const T*>(pal);
+ T *d1 = reinterpret_cast<T*>(dst);
+ T *d2 = d1 + (w << 1);
+
+ for (int i = 0; i < w; ++i) {
+ byte pt = patterns[((*src++ & 0x0f) << 3) + ty] >> (6 - (tx << 1));
+ if (sizeof(T) == 1) {
+ *d1++ = *d2++ = (pt >> 1) & 1;
+ *d1++ = *d2++ = pt & 1;
+ } else {
+ *d1++ = *d2++ = p[(pt >> 1) & 1];
+ *d1++ = *d2++ = p[pt & 1];
+ }
+ tx = (tx + 1) & 3;
+ }
+
+ dst = reinterpret_cast<byte*>(d2);
+}
+
+void SCI0_CGABWDriver::setupRenderProc() {
+ static const LineProc lineProcs[] = {
+ &cgabwRenderLine_v1<byte>,
+ &cgabwRenderLine_v1<uint16>,
+ &cgabwRenderLine_v1<uint32>,
+ &cgabwRenderLine_v2<byte>,
+ &cgabwRenderLine_v2<uint16>,
+ &cgabwRenderLine_v2<uint32>
+ };
+
+ int t = _pixelSize >> 1;
+ if (!_earlyVersion)
+ t += 3;
+
+ assert(t < ARRAYSIZE(lineProcs));
+ _renderLine = lineProcs[t];
+}
+
+const char *SCI0_CGABWDriver::_driverFiles[2] = { "CGA320BW.DRV", "CGA320M.DRV" };
+
+SCI_GFXDRV_VALIDATE_IMPL(SCI0_CGABW)
+
+GfxDriver *SCI0_CGABWDriver_create(int rgbRendering, ...) {
+ static const uint32 monochromeColors[] = { 0xffbf66, 0x66ff66, 0xffffff };
+ va_list args;
+ va_start(args, rgbRendering);
+ int config = CLIP<int>(va_arg(args, int), 0, ARRAYSIZE(monochromeColors));
+ va_end(args);
+
+ return new SCI0_CGABWDriver(monochromeColors[config], rgbRendering != 0);
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/drivers/common.cpp b/engines/sci/graphics/drivers/common.cpp
new file mode 100644
index 00000000000..b70f263a949
--- /dev/null
+++ b/engines/sci/graphics/drivers/common.cpp
@@ -0,0 +1,368 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "common/events.h"
+#include "common/file.h"
+#include "common/system.h"
+#include "engines/util.h"
+#include "graphics/cursorman.h"
+#include "graphics/paletteman.h"
+
+#include "sci/graphics/drivers/gfxdriver_intern.h"
+#include "sci/sci.h"
+
+namespace Sci {
+
+Common::Point GfxDriver::getMousePos() const {
+ return g_system->getEventManager()->getMousePos();
+}
+
+void GfxDriver::setMousePos(const Common::Point &pos) const {
+ g_system->warpMouse(pos.x, pos.y);
+}
+
+void GfxDriver::setShakePos(int shakeXOffset, int shakeYOffset) const {
+ g_system->setShakePos(shakeXOffset, shakeYOffset);
+}
+
+void GfxDriver::clearRect(const Common::Rect &r) const {
+ GFXDRV_ASSERT_READY;
+ g_system->fillScreen(r, 0);
+}
+
+void GfxDriver::copyCurrentPalette(byte *dest, int start, int num) const {
+ assert(dest);
+ assert(start + num <= 256);
+ g_system->getPaletteManager()->grabPalette(dest, start, num);
+}
+
+bool GfxDriver::checkDriver(const char *const *driverNames, int listSize) {
+ Common::String missing;
+ while (listSize-- && *driverNames) {
+ if (Common::File::exists(*driverNames))
+ return true;
+ if (!missing.empty())
+ missing += " or ";
+ missing += "'" + Common::String(*driverNames) + "'";
+ ++driverNames;
+ }
+ warning("Driver file %s not found. Starting game in default mode", missing.c_str());
+ return false;
+}
+
+SCI0_DOSPreVGADriver::SCI0_DOSPreVGADriver(int numColors, int screenW, int screenH, bool rgbRendering) :
+ GfxDriver(screenW, screenH, numColors), _requestRGBMode(rgbRendering), _colors(nullptr), _compositeBuffer(nullptr), _internalPalette(nullptr) {
+}
+
+SCI0_DOSPreVGADriver::~SCI0_DOSPreVGADriver() {
+ delete[] _compositeBuffer;
+ delete[] _internalPalette;
+}
+
+void SCI0_DOSPreVGADriver::assignPalette(const byte *colors) {
+ _colors = colors;
+}
+
+void SCI0_DOSPreVGADriver::initScreen(const Graphics::PixelFormat*) {
+ Graphics::PixelFormat format(Graphics::PixelFormat::createFormatCLUT8());
+ initGraphics(_screenW, _screenH, _requestRGBMode ? nullptr : &format);
+ format = g_system->getScreenFormat();
+ _pixelSize = format.bytesPerPixel;
+
+ if (_requestRGBMode && _pixelSize == 1)
+ warning("SCI0_DOSPreVGADriver::initScreen(): RGB rendering not available in this ScummVM build");
+
+ delete[] _compositeBuffer;
+ delete[] _internalPalette;
+ _internalPalette = nullptr;
+ _compositeBuffer = nullptr;
+
+ assert(_colors);
+ if (_pixelSize == 1) {
+ g_system->getPaletteManager()->setPalette(_colors, 0, _numColors);
+ } else {
+ byte *rgbpal = new byte[_numColors * _pixelSize]();
+ assert(rgbpal);
+
+ if (_pixelSize == 2)
+ SciGfxDrvInternal::updateRGBPalette<uint16>(rgbpal, _colors, 0, _numColors, format);
+ else if (_pixelSize == 4)
+ SciGfxDrvInternal::updateRGBPalette<uint32>(rgbpal, _colors, 0, _numColors, format);
+ else
+ error("SCI0_DOSPreVGADriver::initScreen(): Unsupported screen format");
+ _internalPalette = rgbpal;
+ CursorMan.replaceCursorPalette(_colors, 0, _numColors);
+ }
+
+ _compositeBuffer = new byte[_screenW * _screenH * _pixelSize]();
+ assert(_compositeBuffer);
+
+ setupRenderProc();
+
+ _ready = true;
+}
+
+void SCI0_DOSPreVGADriver::replaceMacCursor(const Graphics::Cursor*) {
+ // This is not needed for SCI0 (and not for any PC version of games at all)
+ error("SCI0_DOSPreVGADriver::replaceMacCursor(Graphics::Cursor*): Not implemented");
+}
+
+void SCI0_DOSPreVGADriver::copyCurrentBitmap(byte*, uint32) const {
+ // This is not needed for SCI0
+ error("SCI0_DOSPreVGADriver::copyCurrentBitmap(): Not implemented");
+}
+
+void SCI0_DOSPreVGADriver::copyCurrentPalette(byte *dest, int start, int num) const {
+ GFXDRV_ASSERT_READY;
+
+ if (_pixelSize == 1) {
+ GfxDriver::copyCurrentPalette(dest, start, num);
+ return;
+ }
+
+ assert(dest);
+ memcpy(dest + start * 3, _colors + start * 3, MIN<int>(num, _numColors) * 3);
+}
+
+void SCI0_DOSPreVGADriver::drawTextFontGlyph(const byte*, int, int, int, int, int, int, const PaletteMod*, const byte*) {
+ // This is only needed for scaling drivers with unscaled hires fonts.
+ error("SCI0_DOSPreVGADriver::drawTextFontGlyph(): Not implemented");
+}
+
+} // End of namespace Sci
+
+namespace SciGfxDrvInternal {
+
+void updateBitmapBuffer(byte *dst, int dstPitch, const byte *src, int srcPitch, int x, int y, int w, int h) {
+ if (!dst)
+ return;
+
+ if (w == srcPitch && w == dstPitch) {
+ memcpy(dst + y * w, src, w * h);
+ } else {
+ const byte *s = src;
+ byte *d = dst + y * dstPitch + x;
+ for (int i = 0; i < h; ++i) {
+ memcpy(d, s, w);
+ s += srcPitch;
+ d += dstPitch;
+ }
+ }
+}
+
+template <typename T> void updateRGBPalette(byte *dest, const byte *src, uint start, uint num, Graphics::PixelFormat &f) {
+ T *dst = &reinterpret_cast<T*>(dest)[start];
+ for (uint i = 0; i < num; ++i) {
+ *dst++ = f.RGBToColor(src[0], src[1], src[2]);
+ src += 3;
+ }
+}
+
+
+template void updateRGBPalette<byte>(byte *dest, const byte *src, uint start, uint num, Graphics::PixelFormat &f);
+template void updateRGBPalette<uint16>(byte *dest, const byte *src, uint start, uint num, Graphics::PixelFormat &f);
+template void updateRGBPalette<uint32>(byte *dest, const byte *src, uint start, uint num, Graphics::PixelFormat &f);
+
+template <typename T> void scale2x(byte *dst, const byte *src, int pitch, int w, int h) {
+ const T *s = reinterpret_cast<const T*>(src);
+ int dstPitch = pitch << 1;
+ T *d1 = reinterpret_cast<T*>(dst);
+ T *d2 = d1 + dstPitch;
+ pitch -= w;
+ dstPitch += (pitch << 1);
+
+ while (h--) {
+ for (int i = 0; i < w; ++i) {
+ d1[0] = d1[1] = d2[0] = d2[1] = *s++;
+ d1 += 2;
+ d2 += 2;
+ }
+ s += pitch;
+ d1 += dstPitch;
+ d2 += dstPitch;
+ }
+}
+
+template void scale2x<byte>(byte *dst, const byte *src, int pitch, int w, int h);
+template void scale2x<uint16>(byte *dst, const byte *src, int pitch, int w, int h);
+template void scale2x<uint32>(byte *dst, const byte *src, int pitch, int w, int h);
+
+byte findColorInPalette(uint32 rgbTriplet, const byte *palette, int numColors) {
+ byte color[3];
+ for (int i = 2; i >= 0; --i) {
+ color[i] = rgbTriplet & 0xFF;
+ rgbTriplet >>= 8;
+ }
+ int min = 65025;
+ byte match = 0;
+ for (int i = 0; i < numColors && min; ++i) {
+ const byte *rgb = &palette[i * 3];
+ int t = (color[0] - rgb[0]) * (color[0] - rgb[0]) + (color[1] - rgb[1]) * (color[1] - rgb[1]) + (color[2] - rgb[2]) * (color[2] - rgb[2]);
+ if (t < min) {
+ min = t;
+ match = i;
+ }
+ }
+ return match;
+}
+
+void renderWinMonochromeCursor(byte *dst, const void *src, const byte *palette, uint &w, uint &h, int &hotX, int &hotY, byte blackColor, byte whiteColor, uint32 &keycolor, bool noScale) {
+ const byte *s = reinterpret_cast<const byte*>(src);
+ uint16 min = 65025;
+ uint16 max = 0;
+
+ byte newKeyColor = 0;
+ while (newKeyColor == blackColor || newKeyColor == whiteColor)
+ ++newKeyColor;
+
+ for (uint i = 0; i < w * h; ++i) {
+ byte col = *s++;
+ if (col == keycolor)
+ continue;
+ const byte *rgb = &palette[col * 3];
+ uint16 t = rgb[0] * 28 + rgb[1] * 150 + rgb[2] * 28;
+ if (t > max)
+ max = t;
+ if (t < min)
+ min = t;
+ }
+
+#if 0
+ // The original interpreter will accidentally let the value overflow like this,
+ // making most cursors completely white. I have fixed it.
+ uint16 med = (uint16)(min + max) >> 1;
+#else
+ uint16 med = (min + max) >> 1;
+#endif
+ uint16 lim1 = max - (max - min) / 3;
+ uint16 lim2 = min + max - lim1;
+ s = reinterpret_cast<const byte*>(src);
+
+ if (w < 17 && h < 17 && !noScale) {
+ // Small cursors (like the insignia ring in KQ6) get scaled and dithered.
+ byte *dst2 = dst + (w << 1);
+ for (uint i = 0; i < h; ++i) {
+ for (uint ii = 0; ii < w; ++ii) {
+ byte col = *s++;
+ if (col == keycolor) {
+ *dst++ = *dst2++ = newKeyColor;
+ *dst++ = *dst2++ = newKeyColor;
+ continue;
+ }
+ const byte *rgb = &palette[col * 3];
+ uint16 t = rgb[0] * 28 + rgb[1] * 150 + rgb[2] * 28;
+
+ dst[0] = dst2[1] = t > lim2 ? whiteColor : blackColor;
+ dst2[0] = dst[1] = t > lim1 ? whiteColor : blackColor;
+ dst += 2;
+ dst2 += 2;
+ };
+ dst += (w << 1);
+ dst2 += (w << 1);
+ }
+ w <<= 1;
+ h <<= 1;
+ hotX <<= 1;
+ hotY <<= 1;
+ } else {
+ for (uint i = 0; i < w * h; ++i) {
+ byte col = *s++;
+ if (col == keycolor) {
+ *dst++ = newKeyColor;
+ continue;
+ }
+ const byte *rgb = &palette[col * 3];
+ uint16 t = rgb[0] * 28 + rgb[1] * 150 + rgb[2] * 28;
+ *dst++ = t > med ? whiteColor : blackColor;
+ }
+ }
+ keycolor = newKeyColor;
+}
+
+void renderPC98GlyphFat(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h, int transpCol) {
+ dstPitch -= w;
+ srcPitch -= w;
+
+ while (h--) {
+ for (int i = 0; i < w - 1; ++i) {
+ uint8 a = *src++;
+ uint8 b = *src;
+ if (a != transpCol)
+ *dst = a;
+ else if (b != transpCol)
+ *dst = b;
+ ++dst;
+ }
+ byte l = *src++;
+ if (l != transpCol)
+ *dst = l;
+ ++dst;
+ src += srcPitch;
+ dst += dstPitch;
+ }
+}
+
+const byte *monochrInit(const char *drvFile, bool &earlyVersion) {
+ Common::File drv;
+ if (!drv.open(drvFile))
+ return nullptr;
+
+ uint16 eprcOffs = 0;
+
+ uint32 cmd = drv.readUint32LE();
+ if ((cmd & 0xFF) == 0xE9)
+ eprcOffs = ((cmd >> 8) & 0xFFFF) + 3;
+
+ if (!eprcOffs || drv.readUint32LE() != 0x87654321 || !drv.skip(1) || !drv.seek(drv.readByte(), SEEK_CUR) || !drv.seek(drv.readByte(), SEEK_CUR))
+ GFXDRV_ERR_VERSION(drv.getName());
+
+ // This is a safe assumption, as the early version pattern map is 4 times the size of the later one.
+ earlyVersion = (eprcOffs > 0x500);
+ uint16 size = earlyVersion ? 512 : 128;
+
+ byte *result = new byte[size];
+ // For CGA, the pattern map is always located before the entry point dispatcher proc.
+ drv.seek(eprcOffs - size, SEEK_SET);
+ drv.read(result, size);
+
+ // For Hercules there are some extra vars in between, all with initial values
+ // of zero. The last entry of the pattern map is definitely never zero...
+ int xtraOffs = 0;
+ while (result[size - 1 - xtraOffs] == 0)
+ ++xtraOffs;
+ if (xtraOffs != 0) {
+ drv.seek(eprcOffs - size - xtraOffs, SEEK_SET);
+ drv.read(result, size);
+ }
+
+ drv.close();
+
+ if (earlyVersion) {
+ uint16 *r = reinterpret_cast<uint16*>(result);
+ for (int i = 0; i < 256; ++i)
+ r[i] = FROM_LE_16(r[i]);
+ }
+
+ return result;
+}
+
+} // End of namespace SciGfxDrvInternal
diff --git a/engines/sci/graphics/drivers/default.cpp b/engines/sci/graphics/drivers/default.cpp
new file mode 100644
index 00000000000..190aa833701
--- /dev/null
+++ b/engines/sci/graphics/drivers/default.cpp
@@ -0,0 +1,270 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "common/system.h"
+#include "engines/util.h"
+#include "graphics/cursorman.h"
+#include "graphics/paletteman.h"
+#include "sci/graphics/drivers/gfxdriver_intern.h"
+#include "sci/resource/resource.h"
+
+namespace Sci {
+
+GfxDefaultDriver::GfxDefaultDriver(uint16 screenWidth, uint16 screenHeight, bool isSCI0, bool rgbRendering) : GfxDriver(screenWidth, screenHeight, 0), _cursorUsesScreenPalette(true), _colorConv(nullptr), _colorConvMod(nullptr),
+ _srcPixelSize(1), _requestRGBMode(rgbRendering), _compositeBuffer(nullptr), _currentBitmap(nullptr), _internalPalette(nullptr), _currentPalette(nullptr), _virtualW(screenWidth), _virtualH(screenHeight), _alwaysCreateBmpBuffer(!isSCI0) {
+ switch (g_sci->getResMan()->getViewType()) {
+ case kViewEga:
+ _numColors = 16; // QFG PC-98 with 8 colors also reports 16 here
+ break;
+ case kViewAmiga:
+ _numColors = 32;
+ break;
+ case kViewAmiga64:
+ _numColors = 64;
+ break;
+ case kViewVga:
+ case kViewVga11:
+ _numColors = 256;
+ break;
+ default:
+ break;
+ }
+
+ if (_numColors == 0)
+ error("GfxDefaultDriver: Unknown view type");
+}
+
+GfxDefaultDriver::~GfxDefaultDriver() {
+ delete[] _compositeBuffer;
+ delete[] _currentBitmap;
+ delete[] _internalPalette;
+ delete[] _currentPalette;
+}
+
+template <typename T> void colorConvert(byte *dst, const byte *src, int pitch, int w, int h, const byte *pal) {
+ T *d = reinterpret_cast<T*>(dst);
+ const T *p = reinterpret_cast<const T*>(pal);
+ const byte *s = src;
+ pitch -= w;
+
+ while (h--) {
+ for (int i = 0; i < w; ++i)
+ *d++ = p[*s++];
+ s += pitch;
+ }
+}
+
+#define applyMod(a, b) MIN<uint>(a * (128 + b) / 128, 255)
+template <typename T> void colorConvertMod(byte *dst, const byte *src, int pitch, int w, int h, const byte *srcPal, const byte *internalPal, Graphics::PixelFormat &f, const PaletteMod *mods, const byte *modMapping) {
+ T *d = reinterpret_cast<T*>(dst);
+ const T *p = reinterpret_cast<const T*>(internalPal);
+ const byte *s1 = src;
+ const byte *s2 = modMapping;
+ pitch -= w;
+
+ while (h--) {
+ for (int i = 0; i < w; ++i) {
+ byte m = *s2++;
+ if (m) {
+ const byte *col = &srcPal[*s1++ * 3];
+ *d++ = f.RGBToColor(applyMod(col[0], mods[m].r), applyMod(col[1], mods[m].g), applyMod(col[2], mods[m].b));
+ } else {
+ *d++ = p[*s1++];
+ }
+ }
+ s1 += pitch;
+ s2 += pitch;
+ }
+}
+#undef applyMod
+
+void GfxDefaultDriver::initScreen(const Graphics::PixelFormat *srcRGBFormat) {
+ Graphics::PixelFormat format8bt(Graphics::PixelFormat::createFormatCLUT8());
+ initGraphics(_screenW, _screenH, srcRGBFormat ? srcRGBFormat : (_requestRGBMode ? nullptr : &format8bt));
+ _format = g_system->getScreenFormat();
+
+ int srcPixelSize = srcRGBFormat ? _format.bytesPerPixel : 1;
+ if (srcPixelSize != _srcPixelSize || _pixelSize != _format.bytesPerPixel) {
+ delete[] _compositeBuffer;
+ delete[] _currentBitmap;
+ delete[] _internalPalette;
+ delete[] _currentPalette;
+ _compositeBuffer = _currentBitmap = _internalPalette = _currentPalette = nullptr;
+ }
+
+ _pixelSize = _format.bytesPerPixel;
+ _srcPixelSize = srcPixelSize;
+
+ if (_requestRGBMode && _pixelSize == 1)
+ warning("GfxDefaultDriver::initScreen(): RGB rendering not available in this ScummVM build");
+
+ if (_pixelSize != _srcPixelSize) {
+ uint32 bufferSize = _screenW * _screenH * _pixelSize;
+ _compositeBuffer = new byte[bufferSize]();
+ assert(_compositeBuffer);
+ }
+
+ // Not needed for SCI0, except for rgb rendering. Unfortunately, SCI_VERSION_01
+ // does need it and we can't tell the version from the number of colors there.
+ // That's why we have the _alwaysCreateBmpBuffer flag...
+ if (_alwaysCreateBmpBuffer || _numColors > 16 || _pixelSize > 1) {
+ _currentBitmap = new byte[_virtualW * _virtualH * _srcPixelSize]();
+ assert(_currentBitmap);
+ }
+
+ if (_numColors > 16 || _pixelSize > 1) {
+ // Not needed for SCI0, except for rgb rendering
+ _currentPalette = new byte[256 * 3]();
+ assert(_currentPalette);
+ if (_pixelSize != _srcPixelSize) {
+ _internalPalette = new byte[256 * _pixelSize]();
+ assert(_internalPalette);
+ }
+ }
+
+ static const ColorConvProc colorConvProcs[] = {
+ &colorConvert<byte>,
+ &colorConvert<uint16>,
+ &colorConvert<uint32>
+ };
+ assert((_pixelSize >> 1) < ARRAYSIZE(colorConvProcs));
+ _colorConv = colorConvProcs[_pixelSize >> 1];
+
+ static const ColorConvModProc colorConvModProcs[] = {
+ &colorConvertMod<byte>,
+ &colorConvertMod<uint16>,
+ &colorConvertMod<uint32>
+ };
+ assert((_pixelSize >> 1) < ARRAYSIZE(colorConvModProcs));
+ _colorConvMod = colorConvModProcs[_pixelSize >> 1];
+
+ _ready = true;
+}
+
+void GfxDefaultDriver::setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod *palMods, const byte *palModMapping) {
+ GFXDRV_ASSERT_READY;
+ if (_pixelSize > 1) {
+ updatePalette(colors, start, num);
+ if (update)
+ copyRectToScreen(_currentBitmap, 0, 0, _virtualW, 0, 0, _virtualW, _virtualH, palMods, palModMapping);
+ if (_cursorUsesScreenPalette)
+ CursorMan.replaceCursorPalette(_currentPalette, 0, 256);
+ } else {
+ g_system->getPaletteManager()->setPalette(colors, start, num);
+ }
+}
+
+void GfxDefaultDriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) {
+ GFXDRV_ASSERT_READY;
+ assert (h >= 0 && w >= 0);
+
+ src += (srcY * pitch + srcX * _srcPixelSize);
+ if (src != _currentBitmap)
+ SciGfxDrvInternal::updateBitmapBuffer(_currentBitmap, _screenW * _srcPixelSize, src, pitch, destX * _srcPixelSize, destY, w * _srcPixelSize, h);
+
+ if (_pixelSize != _srcPixelSize) {
+ generateOutput(_compositeBuffer, src, pitch, w, h, palMods, palModMapping + destY * pitch + destX);
+ src = _compositeBuffer;
+ pitch = w * _pixelSize;
+ }
+
+ g_system->copyRectToScreen(src, pitch, destX, destY, w, h);
+}
+
+void GfxDefaultDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
+ GFXDRV_ASSERT_READY;
+ CursorMan.replaceCursor(cursor, w, h, hotspotX, hotspotY, keycolor);
+ if (_pixelSize > 1 && _currentPalette != nullptr)
+ CursorMan.replaceCursorPalette(_currentPalette, 0, 256);
+}
+
+void GfxDefaultDriver::replaceMacCursor(const Graphics::Cursor*) {
+ // This is not needed for any non-Mac version of games at all)
+ error("GfxDefaultDriver::replaceMacCursor(Graphics::Cursor*): Not implemented");
+}
+
+void GfxDefaultDriver::copyCurrentBitmap(byte *dest, uint32 size) const {
+ GFXDRV_ASSERT_READY;
+ assert(dest);
+ assert(size <= (uint32)(_screenW * _screenH));
+
+ // SCI 0 should not make calls to this method (except when using palette mods), but we have to know if it does...
+ if (!_currentBitmap)
+ error("GfxDefaultDriver::copyCurrentBitmap(): unexpected call");
+
+ // I have changed the implementation a bit from what the engine did before. For non-rgb rendering
+ // it would call OSystem::lockScreen() and then memcpy the data from there (which avoided the need
+ // for the extra bitmap buffer). However, OSystem::lockScreen() is meant more as an update method
+ // for the screen, the call to OSystem::unlockScreen() will turn the whole screen dirty (to be
+ // updated on the next OSysten::updateScreen() call. This is not what we need here, so I rather use
+ // the extra bitmap buffer (which is required for rgb rendering anyway).
+ memcpy(dest, _currentBitmap, size);
+}
+
+void GfxDefaultDriver::copyCurrentPalette(byte *dest, int start, int num) const {
+ GFXDRV_ASSERT_READY;
+
+ if (_pixelSize == 1) {
+ GfxDriver::copyCurrentPalette(dest, start, num);
+ return;
+ }
+
+ assert(dest);
+ assert(_currentPalette);
+ assert(start + num <= 256);
+ memcpy(dest + start * 3, _currentPalette + start * 3, num * 3);
+}
+
+void GfxDefaultDriver::drawTextFontGlyph(const byte*, int, int, int, int, int, int, const PaletteMod*, const byte*) {
+ // This is only needed for scaling drivers with unscaled hires fonts.
+ error("GfxDefaultDriver::drawTextFontGlyph(): Not implemented");
+}
+
+void GfxDefaultDriver::updatePalette(const byte *colors, uint start, uint num) {
+ memcpy(_currentPalette + start * 3, colors, num * 3);
+ if (_pixelSize == 4)
+ SciGfxDrvInternal::updateRGBPalette<uint32>(_internalPalette, colors, start, num, _format);
+ else if (_pixelSize == 2)
+ SciGfxDrvInternal::updateRGBPalette<uint16>(_internalPalette, colors, start, num, _format);
+ else
+ error("GfxDefaultDriver::updatePalette(): Unsupported pixel size %d", _pixelSize);
+}
+
+void GfxDefaultDriver::generateOutput(byte *dst, const byte *src, int pitch, int w, int h, const PaletteMod *palMods, const byte *palModMapping) {
+ if (palMods && palModMapping)
+ _colorConvMod(dst, src, pitch, w, h, _currentPalette, _internalPalette, _format, palMods, palModMapping);
+ else
+ _colorConv(dst, src, pitch, w, h, _internalPalette);
+}
+
+GfxDriver *GfxDefaultDriver_create(int rgbRendering, ...) {
+ va_list args;
+ va_start(args, rgbRendering);
+ int config = va_arg(args, int);
+ int width = va_arg(args, int);
+ int height = va_arg(args, int);
+ va_end(args);
+
+ return new GfxDefaultDriver(width, height, config == 0, rgbRendering != 0);
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/drivers/ega.cpp b/engines/sci/graphics/drivers/ega.cpp
new file mode 100644
index 00000000000..8decef6c8e7
--- /dev/null
+++ b/engines/sci/graphics/drivers/ega.cpp
@@ -0,0 +1,304 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "common/file.h"
+#include "common/system.h"
+#include "engines/util.h"
+#include "graphics/cursorman.h"
+#include "graphics/paletteman.h"
+#include "sci/graphics/drivers/gfxdriver_intern.h"
+
+namespace Sci {
+
+SCI1_EGADriver::SCI1_EGADriver(bool rgbRendering) : GfxDriver(320, 200, 256), _requestRGBMode(rgbRendering), _egaColorPatterns(nullptr), _egaMatchTable(nullptr),
+ _currentBitmap(nullptr), _compositeBuffer(nullptr), _currentPalette(nullptr), _internalPalette(nullptr), _colAdjust(0), _renderLine(nullptr), _vScaleMult(2), _vScaleDiv(1) {
+ static const byte egaColors[48] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0x00, 0xAA, 0xAA,
+ 0xAA, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0xAA, 0x55, 0x00, 0xAA, 0xAA, 0xAA,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0x55, 0x55, 0xFF, 0xFF,
+ 0xFF, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0xFF, 0xFF, 0x55, 0xFF, 0xFF, 0xFF
+ };
+ _convPalette = egaColors;
+}
+
+SCI1_EGADriver::~SCI1_EGADriver() {
+ delete[] _egaMatchTable;
+ delete[] _egaColorPatterns;
+ delete[] _compositeBuffer;
+ delete[] _currentBitmap;
+ delete[] _currentPalette;
+ delete[] _internalPalette;
+}
+
+template <typename T> void ega640RenderLine(byte *&dst, const byte *src, int w, const byte *patterns, const byte *pal, bool) {
+ const T *p = reinterpret_cast<const T*>(pal);
+ T *d1 = reinterpret_cast<T*>(dst);
+ T *d2 = d1 + (w << 1);
+
+ for (int i = 0; i < w; ++i) {
+ byte pt = patterns[*src++];
+ if (sizeof(T) == 1) {
+ *d1++ = *d2++ = pt >> 4;
+ *d1++ = *d2++ = pt & 0x0f;
+ } else {
+ *d1++ = *d2++ = p[pt >> 4];
+ *d1++ = *d2++ = p[pt & 0x0f];
+ }
+ }
+ dst = reinterpret_cast<byte*>(d2);
+}
+
+void SCI1_EGADriver::initScreen(const Graphics::PixelFormat*) {
+ if (!_ready)
+ loadData();
+
+ Graphics::PixelFormat format(Graphics::PixelFormat::createFormatCLUT8());
+ initGraphics(_screenW << 1, _screenH * _vScaleMult / _vScaleDiv, _requestRGBMode ? nullptr : &format);
+ format = g_system->getScreenFormat();
+ _pixelSize = format.bytesPerPixel;
+
+ if (_requestRGBMode && _pixelSize == 1)
+ warning("SCI1_EGADriver::initScreen(): RGB rendering not available in this ScummVM build");
+
+ delete[] _egaColorPatterns;
+ delete[] _compositeBuffer;
+ delete[] _currentBitmap;
+ delete[] _currentPalette;
+ delete[] _internalPalette;
+ _internalPalette = nullptr;
+ _egaColorPatterns = _compositeBuffer = _currentBitmap = _currentPalette = nullptr;
+
+ if (_pixelSize == 1) {
+ g_system->getPaletteManager()->setPalette(_convPalette, 0, 16);
+ } else {
+ byte *rgbpal = new byte[_numColors * _pixelSize]();
+ assert(rgbpal);
+
+ if (_pixelSize == 2)
+ SciGfxDrvInternal::updateRGBPalette<uint16>(rgbpal, _convPalette, 0, 16, format);
+ else if (_pixelSize == 4)
+ SciGfxDrvInternal::updateRGBPalette<uint32>(rgbpal, _convPalette, 0, 16, format);
+ else
+ error("SCI1_EGADriver::initScreen(): Unsupported screen format");
+ _internalPalette = rgbpal;
+ CursorMan.replaceCursorPalette(_convPalette, 0, 16);
+ }
+
+ _compositeBuffer = new byte[(_screenW << 1) * (_screenH * _vScaleMult / _vScaleDiv) * _pixelSize]();
+ assert(_compositeBuffer);
+ _currentBitmap = new byte[_screenW * _screenH]();
+ assert(_currentBitmap);
+ _currentPalette = new byte[256 * 3]();
+ assert(_currentPalette);
+ _egaColorPatterns = new byte[256]();
+ assert(_egaColorPatterns);
+
+ static const LineProc lineProcs[] = {
+ &ega640RenderLine<byte>,
+ &ega640RenderLine<uint16>,
+ &ega640RenderLine<uint32>
+ };
+
+ assert((_pixelSize >> 1) < ARRAYSIZE(lineProcs));
+ _renderLine = lineProcs[_pixelSize >> 1];
+
+ _ready = true;
+}
+
+void SCI1_EGADriver::setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod*, const byte*) {
+ GFXDRV_ASSERT_READY;
+ memcpy(_currentPalette + start * 3, colors, num * 3);
+ byte *d = &_egaColorPatterns[start];
+ for (uint i = 0; i < num; ++i) {
+ *d++ = _egaMatchTable[((MIN<byte>((colors[0] >> 2) + _colAdjust, 63) & 0x38) << 3) | (MIN<byte>((colors[1] >> 2) + _colAdjust, 63) & 0x38) | (MIN<byte>((colors[2] >> 2) + _colAdjust, 63) >> 3)];
+ colors += 3;
+ }
+ if (update)
+ copyRectToScreen(_currentBitmap, 0, 0, _screenW, 0, 0, _screenW, _screenH, nullptr, nullptr);
+}
+
+void SCI1_EGADriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod*, const byte*) {
+ GFXDRV_ASSERT_READY;
+ assert (h >= 0 && w >= 0);
+
+ src += (srcY * pitch + srcX);
+
+ if (src != _currentBitmap)
+ SciGfxDrvInternal::updateBitmapBuffer(_currentBitmap, _screenW, src, pitch, destX, destY, w, h);
+
+ uint16 realWidth, realHeight;
+ renderBitmap(_compositeBuffer, src, pitch, destY, w, h, _egaColorPatterns, _internalPalette, realWidth, realHeight);
+
+ Common::Point pos(destX, destY);
+ pos = getRealCoords(pos);
+
+ g_system->copyRectToScreen(_compositeBuffer, realWidth * _pixelSize, pos.x, pos.y, realWidth, realHeight);
+}
+
+void SCI1_EGADriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
+ GFXDRV_ASSERT_READY;
+ const byte *s = reinterpret_cast<const byte*>(cursor);
+ int dstPitch = (w << 1);
+ byte *d1 = _compositeBuffer;
+ byte *d2 = _compositeBuffer + dstPitch;
+ uint32 newKeyColor = 0xFF;
+
+ for (uint i = 0; i < h; ++i) {
+ for (uint ii = 0; ii < w; ++ii) {
+ byte col = *s++;
+ if (col == keycolor) {
+ *d1++ = *d2++ = newKeyColor;
+ *d1++ = *d2++ = newKeyColor;
+ } else {
+ byte pt = _egaColorPatterns[col];
+ *d1++ = *d2++ = pt >> 4;
+ *d1++ = *d2++ = pt & 0x0f;
+ }
+ }
+ d1 += dstPitch;
+ d2 += dstPitch;
+ }
+
+ CursorMan.replaceCursor(_compositeBuffer, w << 1, h << 1, hotspotX << 1, hotspotY << 1, newKeyColor);
+}
+
+void SCI1_EGADriver::copyCurrentBitmap(byte *dest, uint32 size) const {
+ GFXDRV_ASSERT_READY;
+ assert(dest);
+ assert(size <= (uint32)(_screenW * _screenH));
+ memcpy(dest, _currentBitmap, size);
+}
+
+void SCI1_EGADriver::copyCurrentPalette(byte *dest, int start, int num) const {
+ GFXDRV_ASSERT_READY;
+ assert(dest);
+ assert(start + num <= 256);
+ memcpy(dest + start * 3, _currentPalette + start * 3, num * 3);
+}
+
+void SCI1_EGADriver::drawTextFontGlyph(const byte*, int, int, int, int, int, int, const PaletteMod*, const byte*) {
+ // This is only needed for scaling drivers with unscaled hires fonts.
+ error("SCI1_EGADriver::drawTextFontGlyph(): Not implemented");
+}
+
+Common::Point SCI1_EGADriver::getMousePos() const {
+ Common::Point res = GfxDriver::getMousePos();
+ res.x >>= 1;
+ res.y = res.y * _vScaleDiv / _vScaleMult;
+ return res;
+}
+
+void SCI1_EGADriver::setMousePos(const Common::Point &pos) const {
+ g_system->warpMouse(pos.x << 1, pos.y * _vScaleMult / _vScaleDiv);
+}
+
+void SCI1_EGADriver::setShakePos(int shakeXOffset, int shakeYOffset) const {
+ g_system->setShakePos(shakeXOffset << 1, shakeYOffset * _vScaleMult / _vScaleDiv);
+}
+
+void SCI1_EGADriver::clearRect(const Common::Rect &r) const {
+ Common::Rect r2(r.left << 1, r.top * _vScaleMult / _vScaleDiv, r.right << 1, r.bottom * _vScaleMult / _vScaleDiv);
+ GfxDriver::clearRect(r2);
+}
+
+Common::Point SCI1_EGADriver::getRealCoords(Common::Point &pos) const {
+ return Common::Point(pos.x << 1, pos.y * _vScaleMult / _vScaleDiv);
+}
+
+void SCI1_EGADriver::loadData() {
+ Common::File drv;
+ if (!drv.open(_driverFile))
+ GFXDRV_ERR_OPEN(_driverFile);
+
+ uint16 eprcOffs = 0;
+
+ uint32 cmd = drv.readUint32LE();
+ if ((cmd & 0xFF) == 0xE9)
+ eprcOffs = ((cmd >> 8) & 0xFFFF) + 3;
+
+ if (!eprcOffs || drv.readUint32LE() != 0x87654321 || !drv.skip(1) || !drv.seek(drv.readByte(), SEEK_CUR) || !drv.seek(drv.readByte(), SEEK_CUR) || drv.readUint32LE() != 0xFEDCBA98 || !drv.skip(4))
+ GFXDRV_ERR_VERSION(_driverFile);
+
+ uint32 pos = (drv.pos() + 1) & ~1;
+
+ drv.seek(pos);
+ drv.seek(drv.readUint16LE());
+ uint32 colResponse = drv.readUint32LE();
+ _numColors = (colResponse >> 8) & 0xffff;
+ if (_numColors < 16 || _numColors > 256 || (colResponse & 0xff0000ff) != 0xC30000B8)
+ error("SCI1_EGADriver: Failed to retrieve color info from '%s'", _driverFile);
+
+ drv.seek(pos + 20);
+ drv.seek(drv.readUint16LE());
+ byte *buff = new byte[128];
+ drv.read(buff, 128);
+
+ uint16 tableOffs = 0;
+ for (int i = 0; i < 120 && !tableOffs; ++i) {
+ uint32 c = READ_BE_UINT32(buff + i);
+ if (c == 0x8BD82E8A) {
+ if (buff[i + 4] == 0x87)
+ tableOffs = READ_LE_UINT16(buff + i + 5);
+ } else if (c == 0xD0E8D0E8) {
+ for (int ii = 4; ii < 14; ++ii) {
+ if (READ_BE_UINT16(buff + i + ii) == 0x83C0) {
+ c = READ_BE_UINT32(buff + i + ii + 2);
+ if ((c & 0xFFFFFF) == 0x83F83F)
+ _colAdjust = c >> 24;
+ }
+ }
+ }
+ }
+ delete[] buff;
+
+ if (!tableOffs)
+ error("SCI1_EGADriver: Failed to load color data from '%s'", _driverFile);
+
+ drv.seek(tableOffs);
+ byte *table = new byte[512]();
+ drv.read(table, 512);
+ _egaMatchTable = table;
+
+ if (drv.readUint16LE() != 152 || drv.readUint16LE() != 160)
+ GFXDRV_ERR_VERSION(_driverFile);
+
+ drv.close();
+}
+
+void SCI1_EGADriver::renderBitmap(byte *dst, const byte *src, int pitch, int, int w, int h, const byte *patterns, const byte *palette, uint16 &realWidth, uint16 &realHeight) {
+ for (int i = 0; i < h; ++i) {
+ _renderLine(dst, src, w, patterns, palette, 0);
+ src += pitch;
+ }
+ realWidth = w << 1;
+ realHeight = h << 1;
+}
+
+const char *SCI1_EGADriver::_driverFile = "EGA640.DRV";
+
+SCI_GFXDRV_VALIDATE_IMPL(SCI1_EGA)
+
+GfxDriver *SCI1_EGADriver_create(int rgbRendering, ...) {
+ return new SCI1_EGADriver(rgbRendering != 0);
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/drivers/gfxdriver.h b/engines/sci/graphics/drivers/gfxdriver.h
new file mode 100644
index 00000000000..7328af5c37a
--- /dev/null
+++ b/engines/sci/graphics/drivers/gfxdriver.h
@@ -0,0 +1,89 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#ifndef SCI_GRAPHICS_DRIVERS_GFXDRIVER_H
+#define SCI_GRAPHICS_DRIVERS_GFXDRIVER_H
+
+#include "common/rendermode.h"
+#include "common/rect.h"
+#include "graphics/pixelformat.h"
+#include "sci/detection.h"
+
+namespace Graphics {
+ class Cursor;
+}
+
+namespace Sci {
+
+struct PaletteMod;
+
+class GfxDriver {
+public:
+ enum DrawFlags : uint32 {
+ kHiResMode = 1 << 0,
+ kMovieMode = 1 << 1
+ };
+
+ GfxDriver(uint16 screenWidth, uint16 screenHeight, int numColors) : _screenW(screenWidth), _screenH(screenHeight), _numColors(numColors), _ready(false), _pixelSize(1) {}
+ virtual ~GfxDriver() {}
+ virtual void initScreen(const Graphics::PixelFormat *srcRGBFormat = nullptr) = 0; // srcRGBFormat: expect incoming data to have the specified rgb pixel format (used for Mac hicolor videos)
+ virtual void setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod *palMods, const byte *palModMapping) = 0;
+ virtual void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) = 0;
+ virtual void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) = 0;
+ virtual void replaceMacCursor(const Graphics::Cursor *cursor) = 0;
+ virtual Common::Point getMousePos() const;
+ virtual void setMousePos(const Common::Point &pos) const;
+ virtual void setShakePos(int shakeXOffset, int shakeYOffset) const;
+ virtual void clearRect(const Common::Rect &r) const;
+ virtual void copyCurrentBitmap(byte *dest, uint32 size) const = 0;
+ virtual void copyCurrentPalette(byte *dest, int start, int num) const;
+ virtual void drawTextFontGlyph(const byte *src, int pitch, int hiresDestX, int hiresDestY, int hiresW, int hiresH, int transpColor, const PaletteMod *palMods, const byte *palModMapping) = 0;
+ virtual byte remapTextColor(byte color) const { return color; }
+ virtual void setColorMap(const byte *colorMap) {}
+ virtual Common::Point getRealCoords(Common::Point &pos) const { return pos; }
+ virtual void setFlags(uint32 flags) {}
+ virtual void clearFlags(uint32 flags) {}
+ virtual bool supportsPalIntensity() const = 0;
+ virtual bool supportsHiResGraphics() const = 0;
+ virtual bool driverBasedTextRendering() const = 0;
+ uint16 numColors() const { return _numColors; }
+ byte pixelSize() const { return _pixelSize; }
+
+protected:
+ bool _ready;
+ static bool checkDriver(const char *const *driverNames, int listSize);
+ const uint16 _screenW;
+ const uint16 _screenH;
+ uint16 _numColors;
+ byte _pixelSize;
+};
+
+} // End of namespace Sci
+
+namespace SciGfxDriver {
+
+Common::RenderMode getRenderMode();
+Sci::GfxDriver *create(Common::RenderMode renderMode, int width, int height);
+
+} // End of namespace SciGfxDriver
+
+#endif // SCI_GRAPHICS_DRIVERS_GFXDRIVER_H
diff --git a/engines/sci/graphics/drivers/gfxdriver_intern.h b/engines/sci/graphics/drivers/gfxdriver_intern.h
new file mode 100644
index 00000000000..e12fb4a7776
--- /dev/null
+++ b/engines/sci/graphics/drivers/gfxdriver_intern.h
@@ -0,0 +1,194 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#ifndef SCI_GRAPHICS_DRIVERS_GFXDRIVER_INTERN_H
+#define SCI_GRAPHICS_DRIVERS_GFXDRIVER_INTERN_H
+
+#include "common/platform.h"
+#include "sci/graphics/drivers/gfxdriver.h"
+
+namespace Sci {
+
+class GfxDefaultDriver : public GfxDriver {
+public:
+ GfxDefaultDriver(uint16 screenWidth, uint16 screenHeight, bool isSCI0, bool rgbRendering);
+ ~GfxDefaultDriver() override;
+ void initScreen(const Graphics::PixelFormat *srcRGBFormat) override; // srcRGBFormat: expect incoming data to have the specified rgb pixel format (used for Mac hicolor videos)
+ void setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod *palMods, const byte *palModMapping) override;
+ void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) override;
+ void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
+ void replaceMacCursor(const Graphics::Cursor*) override;
+ void copyCurrentBitmap(byte *dest, uint32 size) const override;
+ void copyCurrentPalette(byte *dest, int start, int num) const override;
+ void drawTextFontGlyph(const byte*, int, int, int, int, int, int, const PaletteMod*, const byte*) override; // Only for HiRes fonts. Not implemented here.
+ bool supportsPalIntensity() const override { return true; }
+ bool supportsHiResGraphics() const override { return false; }
+ bool driverBasedTextRendering() const override { return false; }
+protected:
+ void updatePalette(const byte *colors, uint start, uint num);
+ byte *_compositeBuffer;
+ byte *_currentBitmap;
+ byte *_currentPalette;
+ byte *_internalPalette;
+ uint16 _virtualW;
+ uint16 _virtualH;
+ Graphics::PixelFormat _format;
+ byte _srcPixelSize;
+ bool _cursorUsesScreenPalette;
+ const bool _alwaysCreateBmpBuffer;
+ const bool _requestRGBMode;
+ typedef void (*ColorConvProc)(byte*, const byte*, int, int, int, const byte*);
+ ColorConvProc _colorConv;
+ typedef void (*ColorConvModProc)(byte*, const byte*, int, int, int, const byte*, const byte*, Graphics::PixelFormat&, const PaletteMod*, const byte*);
+ ColorConvModProc _colorConvMod;
+private:
+ void generateOutput(byte *dst, const byte *src, int pitch, int w, int h, const PaletteMod *palMods, const byte *palModMapping);
+};
+
+class SCI0_DOSPreVGADriver : public GfxDriver {
+public:
+ SCI0_DOSPreVGADriver(int numColors, int screenW, int screenH, bool rgbRendering);
+ ~SCI0_DOSPreVGADriver() override;
+ void initScreen(const Graphics::PixelFormat*) override;
+ void setPalette(const byte*, uint, uint, bool, const PaletteMod*, const byte*) override {}
+ void replaceMacCursor(const Graphics::Cursor*) override;
+ void copyCurrentBitmap(byte*, uint32) const override;
+ void drawTextFontGlyph(const byte*, int, int, int, int, int, int, const PaletteMod*, const byte*) override; // Only for HiRes fonts. Not implemented here.
+ void copyCurrentPalette(byte *dest, int start, int num) const override;
+ bool supportsPalIntensity() const override { return false; }
+ bool supportsHiResGraphics() const override { return false; }
+ bool driverBasedTextRendering() const override { return false; }
+protected:
+ void assignPalette(const byte *colors);
+ byte *_compositeBuffer;
+ const byte *_internalPalette;
+private:
+ virtual void setupRenderProc() = 0;
+ const bool _requestRGBMode;
+ const byte *_colors;
+};
+
+class UpscaledGfxDriver : public GfxDefaultDriver {
+public:
+ UpscaledGfxDriver(int16 textAlignX, bool scaleCursor, bool rgbRendering);
+ ~UpscaledGfxDriver() override;
+ void initScreen(const Graphics::PixelFormat *format) override;
+ void setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod *palMods, const byte *palModMapping) override;
+ void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) override;
+ void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
+ Common::Point getMousePos() const override;
+ void setMousePos(const Common::Point &pos) const override;
+ void setShakePos(int shakeXOffset, int shakeYOffset) const override;
+ void clearRect(const Common::Rect &r) const override;
+ Common::Point getRealCoords(Common::Point &pos) const override;
+ void drawTextFontGlyph(const byte *src, int pitch, int hiresDestX, int hiresDestY, int hiresW, int hiresH, int transpColor, const PaletteMod *palMods, const byte *palModMapping) override; // For HiRes fonts.
+ bool driverBasedTextRendering() const override { return true; }
+protected:
+ UpscaledGfxDriver(uint16 scaledW, uint16 scaledH, int16 textAlignX, bool scaleCursor, bool rgbRendering);
+ void updateScreen(int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping);
+ void adjustCursorBuffer(uint16 newWidth, uint16 newHeight);
+ typedef void (*GlyphRenderProc)(byte*, int, const byte*, int, int, int, int);
+ GlyphRenderProc _renderGlyph;
+ typedef void (*ScaledRenderProc)(byte*, const byte*, int, int, int);
+ ScaledRenderProc _renderScaled;
+ uint16 _textAlignX;
+ uint16 _hScaleMult;
+ uint16 _vScaleMult;
+ uint16 _vScaleDiv;
+ byte *_scaledBitmap;
+private:
+ virtual void renderBitmap(const byte *src, int pitch, int dx, int dy, int w, int h, int &realWidth, int &realHeight);
+ const bool _scaleCursor;
+ uint16 _cursorWidth;
+ uint16 _cursorHeight;
+ bool _needCursorBuffer;
+};
+
+class SCI1_EGADriver : public GfxDriver {
+public:
+ SCI1_EGADriver(bool rgbRendering);
+ ~SCI1_EGADriver() override;
+ void initScreen(const Graphics::PixelFormat*) override;
+ void setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod*, const byte*) override;
+ void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod*, const byte*) override;
+ void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
+ void replaceMacCursor(const Graphics::Cursor *cursor) override {}
+ void copyCurrentBitmap(byte *dest, uint32 size) const override;
+ void copyCurrentPalette(byte *dest, int start, int num) const override;
+ void drawTextFontGlyph(const byte*, int, int, int, int, int, int, const PaletteMod*, const byte*) override; // Only for HiRes fonts. Not implemented here.
+ Common::Point getMousePos() const override;
+ void setMousePos(const Common::Point &pos) const override;
+ void setShakePos(int shakeXOffset, int shakeYOffset) const override;
+ void clearRect(const Common::Rect &r) const override;
+ Common::Point getRealCoords(Common::Point &pos) const override;
+ bool supportsPalIntensity() const override { return false; }
+ bool supportsHiResGraphics() const override { return false; }
+ bool driverBasedTextRendering() const override { return false; }
+ static bool validateMode(Common::Platform p) { return (p == Common::kPlatformDOS || p == Common::kPlatformWindows) && checkDriver(&_driverFile, 1); }
+protected:
+ typedef void (*LineProc)(byte*&, const byte*, int, const byte*, const byte*, bool);
+ LineProc _renderLine;
+ const byte *_convPalette;
+ uint16 _vScaleMult, _vScaleDiv;
+ const byte *_egaMatchTable;
+ byte *_egaColorPatterns;
+ uint8 _colAdjust;
+ byte *_compositeBuffer;
+ byte *_currentPalette;
+private:
+ virtual void loadData();
+ virtual void renderBitmap(byte *dst, const byte *src, int pitch, int y, int w, int h, const byte *patterns, const byte *palette, uint16 &realWidth, uint16 &realHeight);
+ byte *_currentBitmap;
+ const byte *_internalPalette;
+ const bool _requestRGBMode;
+ static const char *_driverFile;
+};
+
+#define GFXDRV_ASSERT_READY \
+ if (!_ready) \
+ error("%s(): initScreen() must be called before using this method", __FUNCTION__)
+
+#define GFXDRV_ERR_OPEN(x) \
+ error("%s(): Failed to open '%s'", __FUNCTION__, x)
+
+#define GFXDRV_ERR_VERSION(x) \
+ error("%s(): Driver file '%s' unknown version", __FUNCTION__, x)
+
+#define SCI_GFXDRV_VALIDATE_IMPL(name) \
+ bool name##Driver_validateMode(Common::Platform platform) { \
+ return name##Driver::validateMode(platform); \
+ }
+
+} // End of namespace Sci
+
+namespace SciGfxDrvInternal {
+ template <typename T> void updateRGBPalette(byte *dest, const byte *src, uint start, uint num, Graphics::PixelFormat &f);
+ template <typename T> void scale2x(byte *dst, const byte *src, int pitch, int w, int h);
+ void updateBitmapBuffer(byte *dst, int dstPitch, const byte *src, int srcPitch, int x, int y, int w, int h);
+ byte findColorInPalette(uint32 rgbTriplet, const byte *palette, int numColors);
+ void renderWinMonochromeCursor(byte *dst, const void *src, const byte *palette, uint &w, uint &h, int &hotX, int &hotY, byte blackColor, byte whiteColor, uint32 &keycolor, bool noScale);
+ void renderPC98GlyphFat(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h, int transpCol);
+ const byte *monochrInit(const char *drvFile, bool &earlyVersion);
+
+} // End of namespace SciGfxDrvInternal
+
+#endif // SCI_GRAPHICS_DRIVERS_GFXDRIVER_INTERN_H
diff --git a/engines/sci/graphics/drivers/hercules.cpp b/engines/sci/graphics/drivers/hercules.cpp
new file mode 100644
index 00000000000..116b5a95ee9
--- /dev/null
+++ b/engines/sci/graphics/drivers/hercules.cpp
@@ -0,0 +1,196 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "common/file.h"
+#include "common/system.h"
+#include "graphics/cursorman.h"
+#include "sci/graphics/drivers/gfxdriver_intern.h"
+
+namespace Sci {
+
+class SCI0_HerculesDriver final : public SCI0_DOSPreVGADriver {
+public:
+ SCI0_HerculesDriver(uint32 monochromeColor, bool rgbRendering, bool cropImage);
+ ~SCI0_HerculesDriver() override;
+ void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod*, const byte*) override;
+ void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
+ Common::Point getMousePos() const override;
+ void setMousePos(const Common::Point &pos) const override;
+ void setShakePos(int shakeXOffset, int shakeYOffset) const override;
+ void clearRect(const Common::Rect &r) const override;
+ Common::Point getRealCoords(Common::Point &pos) const override;
+ static bool validateMode(Common::Platform p) { return (p == Common::kPlatformDOS) && checkDriver(&_driverFile, 1); }
+private:
+ void setupRenderProc() override;
+ const uint16 _centerX;
+ const uint16 _centerY;
+ byte _monochromePalette[6];
+ const byte *_monochromePatterns;
+ typedef void (*LineProc)(byte*&, const byte*, int, int, int, const byte*, const byte*);
+ LineProc _renderLine;
+ static const char *_driverFile;
+};
+
+SCI0_HerculesDriver::SCI0_HerculesDriver(uint32 monochromeColor, bool rgbRendering, bool cropImage) : SCI0_DOSPreVGADriver(2, cropImage ? 640 : 720, cropImage ? 300 : 350, rgbRendering),
+ _centerX(cropImage ? 0 : 40), _centerY(cropImage ? 0 : 25), _monochromePatterns(nullptr), _renderLine(nullptr) {
+ _monochromePalette[0] = _monochromePalette[1] = _monochromePalette[2] = 0;
+ _monochromePalette[3] = (monochromeColor >> 16) & 0xff;
+ _monochromePalette[4] = (monochromeColor >> 8) & 0xff;
+ _monochromePalette[5] = monochromeColor & 0xff;
+ assignPalette(_monochromePalette);
+ bool unused = false;
+
+ if (!(_monochromePatterns = SciGfxDrvInternal::monochrInit(_driverFile, unused)))
+ GFXDRV_ERR_OPEN(_driverFile);
+}
+
+SCI0_HerculesDriver::~SCI0_HerculesDriver() {
+ delete[] _monochromePatterns;
+}
+
+void SCI0_HerculesDriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod*, const byte*) {
+ GFXDRV_ASSERT_READY;
+
+ byte *dst = _compositeBuffer;
+ byte sw = destY & 1;
+ src += (srcY * pitch + srcX);
+ destY = (destY & ~1) * 3 / 2 + (destY & 1);
+ int ty = destY & 7;
+ int rh = 0;
+
+ for (int i = 0; i < h; ++i) {
+ const byte *src2 = src;
+ _renderLine(dst, src2, w, srcX & 3, ty, _monochromePatterns, _internalPalette);
+ ty = (ty + 1) & 7;
+ ++rh;
+
+ if (sw & 1)
+ sw ^= 2;
+
+ if (sw != 3) {
+ src += pitch;
+ sw ^= 1;
+ } else {
+ --i;
+ }
+ }
+
+ g_system->copyRectToScreen(_compositeBuffer, (w << 1) * _pixelSize, (destX << 1) + _centerX, destY + _centerY, w << 1, rh);
+}
+
+void SCI0_HerculesDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
+ GFXDRV_ASSERT_READY;
+ // Instead of implementing the original cursor rendering code, we rely on the 8 bit cursor that
+ // has already been generated by the engine. We simply convert the colors as needed and scale the cursor...
+ assert(keycolor == 1);
+ keycolor = 0x0f;
+ int alt = 0;
+ const byte *s = reinterpret_cast<const byte *>(cursor);
+ byte *d = _compositeBuffer;
+
+ for (uint i = 0; i < h; ++i) {
+ for (uint ii = 0; ii < (w << 1); ++ii) {
+ *d++ = *s ? (*s ^ 0x0e) : 0;
+ if (ii & 1)
+ ++s;
+ }
+ if (i & 1) {
+ alt ^= 1;
+ if (alt) {
+ s -= w;
+ --i;
+ }
+ }
+ }
+
+ CursorMan.replaceCursor(_compositeBuffer, w << 1, (h & ~1) * 3 / 2 + (h & 1), hotspotX << 1, (hotspotY & ~1) * 3 / 2 + (hotspotY & 1), keycolor);
+}
+
+Common::Point SCI0_HerculesDriver::getMousePos() const {
+ Common::Point res = GfxDriver::getMousePos();
+ res.x = CLIP<int>(res.x - _centerX, 0, 639) >> 1;
+ res.y = (CLIP<int>(res.y - _centerY, 0, 299) * 2 + 1) / 3;
+ return res;
+}
+
+void SCI0_HerculesDriver::setMousePos(const Common::Point &pos) const {
+ g_system->warpMouse((pos.x << 1) + _centerX, (pos.y & ~1) * 3 / 2 + (pos.y & 1) + _centerY);
+}
+
+void SCI0_HerculesDriver::setShakePos(int shakeXOffset, int shakeYOffset) const {
+ g_system->setShakePos(shakeXOffset << 1, (shakeYOffset & ~1) * 3 / 2 + (shakeYOffset & 1));
+}
+
+void SCI0_HerculesDriver::clearRect(const Common::Rect &r) const {
+ Common::Rect r2((r.left << 1) + _centerX, (r.top & ~1) * 3 / 2 + (r.top & 1) + _centerY, (r.right << 1) + 40, (r.bottom & ~1) * 3 / 2 + (r.bottom & 1) + _centerY);
+ GfxDriver::clearRect(r2);
+}
+
+Common::Point SCI0_HerculesDriver::getRealCoords(Common::Point &pos) const {
+ return Common::Point((pos.x << 1) + _centerX, (pos.y & ~1) * 3 / 2 + (pos.y & 1) + _centerY);
+}
+
+template <typename T> void herculesRenderLine(byte *&dst, const byte *src, int w, int tx, int ty, const byte *patterns, const byte *pal) {
+ T *d = reinterpret_cast<T*>(dst);
+ const T *p = reinterpret_cast<const T*>(pal);
+
+ for (int i = 0; i < w; ++i) {
+ byte pt = patterns[((*src++ & 0x0f) << 3) + ty] >> (6 - (tx << 1));
+ if (sizeof(T) == 1) {
+ *d++ = (pt >> 1) & 1;
+ *d++ = pt & 1;
+ } else {
+ *d++ = p[(pt >> 1) & 1];
+ *d++ = p[pt & 1];
+ }
+ tx = (tx + 1) & 3;
+ }
+
+ dst = reinterpret_cast<byte*>(d);
+}
+
+void SCI0_HerculesDriver::setupRenderProc() {
+ static const LineProc lineProcs[] = {
+ &herculesRenderLine<byte>,
+ &herculesRenderLine<uint16>,
+ &herculesRenderLine<uint32>
+ };
+
+ assert((_pixelSize >> 1) < ARRAYSIZE(lineProcs));
+ _renderLine = lineProcs[_pixelSize >> 1];
+}
+
+const char *SCI0_HerculesDriver::_driverFile = "HERCMONO.DRV";
+
+SCI_GFXDRV_VALIDATE_IMPL(SCI0_Hercules)
+
+GfxDriver *SCI0_HerculesDriver_create(int rgbRendering, ...) {
+ static const uint32 monochromeColors[] = { 0xffbf66, 0x66ff66, 0xffffff };
+ va_list args;
+ va_start(args, rgbRendering);
+ int config = CLIP<int>(va_arg(args, int), 0, ARRAYSIZE(monochromeColors));
+ va_end(args);
+
+ return new SCI0_HerculesDriver(monochromeColors[config], rgbRendering != 0, false);
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/drivers/init.cpp b/engines/sci/graphics/drivers/init.cpp
new file mode 100644
index 00000000000..431cad229d9
--- /dev/null
+++ b/engines/sci/graphics/drivers/init.cpp
@@ -0,0 +1,167 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "sci/graphics/drivers/gfxdriver.h"
+#include "sci/sci.h"
+#include "common/config-manager.h"
+#include "common/language.h"
+#include "common/platform.h"
+
+namespace Sci {
+
+#define SCI_GFXDRV_DCL1(name) \
+ extern GfxDriver *name##Driver_create(int, ...)
+
+#define SCI_GFXDRV_DCL2(name) \
+ extern bool name##Driver_validateMode(Common::Platform); \
+ extern GfxDriver *name##Driver_create(int, ...)
+
+SCI_GFXDRV_DCL1(GfxDefault);
+SCI_GFXDRV_DCL1(UpscaledGfx);
+SCI_GFXDRV_DCL1(PC98Gfx16Colors);
+SCI_GFXDRV_DCL1(WindowsGfx256Colors);
+SCI_GFXDRV_DCL2(SCI1_EGA);
+SCI_GFXDRV_DCL2(SCI1_VGAGreyScale);
+SCI_GFXDRV_DCL2(SCI0_CGA);
+SCI_GFXDRV_DCL2(SCI0_CGABW);
+SCI_GFXDRV_DCL2(SCI0_Hercules);
+SCI_GFXDRV_DCL2(SCI0_PC98Gfx8Colors);
+SCI_GFXDRV_DCL2(SCI1_PC98Gfx8Colors);
+SCI_GFXDRV_DCL2(WindowsGfx16Colors);
+
+#undef SCI_GFXDRV_DCL1
+#undef SCI_GFXDRV_DCL2
+
+enum HiresSetting {
+ kUnused = -1,
+ kDisable = 0,
+ kEnable = 1
+};
+
+struct GfxDriverInfo {
+ Common::RenderMode renderMode;
+ Common::Platform platform;
+ SciVersion versionMin;
+ SciVersion versionMax;
+ SciGameId gameId;
+ Common::Language language;
+ HiresSetting hires;
+ bool (*validateMode)(Common::Platform);
+ GfxDriver *(*createDriver)(int, ...);
+ int config;
+};
+
+#define INITPROCS1(x) nullptr, x##Driver_create
+#define INITPROCS2(x) x##Driver_validateMode, x##Driver_create
+
+static const GfxDriverInfo _gfxDriverInfos[] = {
+ // Selected modes
+ { Common::kRenderEGA, Common::kPlatformUnknown, SCI_VERSION_1_EARLY, SCI_VERSION_1_1, GID_ALL, Common::UNK_LANG, kUnused, INITPROCS2(SCI1_EGA), 0 },
+ { Common::kRenderVGAGrey, Common::kPlatformUnknown, SCI_VERSION_1_EARLY, SCI_VERSION_1_1, GID_ALL, Common::UNK_LANG, kUnused, INITPROCS2(SCI1_VGAGreyScale), 0 },
+ { Common::kRenderCGA, Common::kPlatformUnknown, SCI_VERSION_0_EARLY, SCI_VERSION_1_EGA_ONLY, GID_ALL, Common::UNK_LANG, kUnused, INITPROCS2(SCI0_CGA), 0 },
+ { Common::kRenderCGA_BW, Common::kPlatformUnknown, SCI_VERSION_0_EARLY, SCI_VERSION_1_EGA_ONLY, GID_ALL, Common::UNK_LANG, kUnused, INITPROCS2(SCI0_CGABW), 2 },
+ { Common::kRenderHercA, Common::kPlatformUnknown, SCI_VERSION_0_EARLY, SCI_VERSION_1_EGA_ONLY, GID_ALL, Common::UNK_LANG, kUnused, INITPROCS2(SCI0_Hercules), 0 },
+ { Common::kRenderHercG, Common::kPlatformUnknown, SCI_VERSION_0_EARLY, SCI_VERSION_1_EGA_ONLY, GID_ALL, Common::UNK_LANG, kUnused, INITPROCS2(SCI0_Hercules), 1 },
+ { Common::kRenderPC98_8c, Common::kPlatformUnknown, SCI_VERSION_0_LATE, SCI_VERSION_0_LATE, GID_PQ2, Common::UNK_LANG, kUnused, INITPROCS2(SCI0_PC98Gfx8Colors), 1 },
+ { Common::kRenderPC98_8c, Common::kPlatformUnknown, SCI_VERSION_01, SCI_VERSION_01, GID_ALL, Common::UNK_LANG, kUnused, INITPROCS2(SCI0_PC98Gfx8Colors), 0 },
+ { Common::kRenderPC98_8c, Common::kPlatformUnknown, SCI_VERSION_1_LATE, SCI_VERSION_1_LATE, GID_ALL, Common::UNK_LANG, kUnused, INITPROCS2(SCI1_PC98Gfx8Colors), 0 },
+ { Common::kRenderWin16c, Common::kPlatformUnknown, SCI_VERSION_1_1, SCI_VERSION_1_1, GID_ALL, Common::UNK_LANG, kUnused, INITPROCS2(WindowsGfx16Colors), 0 },
+ // Default modes
+ { Common::kRenderDefault, Common::kPlatformPC98, SCI_VERSION_0_LATE, SCI_VERSION_0_LATE, GID_PQ2, Common::UNK_LANG, kUnused, INITPROCS1(PC98Gfx16Colors), 2 },
+ { Common::kRenderDefault, Common::kPlatformPC98, SCI_VERSION_01, SCI_VERSION_01, GID_ALL, Common::UNK_LANG, kUnused, INITPROCS1(PC98Gfx16Colors), 0 },
+ { Common::kRenderDefault, Common::kPlatformPC98, SCI_VERSION_1_EARLY, SCI_VERSION_1_LATE, GID_ALL, Common::UNK_LANG, kUnused, INITPROCS1(PC98Gfx16Colors), 1 },
+ { Common::kRenderDefault, Common::kPlatformWindows, SCI_VERSION_1_1, SCI_VERSION_1_1, GID_ALL, Common::UNK_LANG, kDisable, INITPROCS1(WindowsGfx256Colors), 0 },
+ { Common::kRenderDefault, Common::kPlatformWindows, SCI_VERSION_1_1, SCI_VERSION_1_1, GID_KQ6, Common::UNK_LANG, kEnable, INITPROCS1(WindowsGfx256Colors), 1 },
+ { Common::kRenderDefault, Common::kPlatformDOS, SCI_VERSION_1_1, SCI_VERSION_1_1, GID_KQ6, Common::UNK_LANG, kEnable, INITPROCS1(WindowsGfx256Colors), 1 },
+ { Common::kRenderDefault, Common::kPlatformUnknown, SCI_VERSION_0_EARLY, SCI_VERSION_1_1, GID_ALL, Common::KO_KOR, kUnused, INITPROCS1(UpscaledGfx), 0 },
+ { Common::kRenderDefault, Common::kPlatformUnknown, SCI_VERSION_0_EARLY, SCI_VERSION_1_EGA_ONLY, GID_ALL, Common::UNK_LANG, kUnused, INITPROCS1(GfxDefault), 0 },
+ { Common::kRenderDefault, Common::kPlatformUnknown, SCI_VERSION_1_EARLY, SCI_VERSION_1_1, GID_ALL, Common::UNK_LANG, kUnused, INITPROCS1(GfxDefault), 1 }
+};
+
+#undef INITPROCS1
+#undef INITPROCS2
+
+} // End of namespace Sci
+
+namespace SciGfxDriver {
+using namespace Sci;
+
+Common::RenderMode getRenderMode() {
+ // Check if the selected render mode is available for the game. This is quite specific for each game. Sometime it
+ // is only EGA, sometimes only CGA b/w without CGA 4 colors, etc. Also set default mode if undithering is enabled.
+ bool undither = ConfMan.getBool("disable_dithering");
+ Common::RenderMode selectedMode = ConfMan.hasKey("render_mode") ? Common::parseRenderMode(ConfMan.get("render_mode")) : Common::kRenderDefault;
+ Common::RenderMode result = selectedMode;
+ Common::Language lang = g_sci->getLanguage();
+ Common::Platform platform = g_sci->getPlatform();
+ SciVersion version = getSciVersion();
+
+ // No extra modes supported for the Korean fan-patched games.
+ // Also set default mode if undithering is enabled for a SCI0 game and the render mode is either set to kRenderEGA
+ // or kRenderPC98_16c (probably redundant nowadays, but why not make sure everything works as intended).
+ if (lang == Common::KO_KOR || (undither && ((selectedMode == Common::kRenderEGA && (version <= SCI_VERSION_0_LATE || version == SCI_VERSION_1_EGA_ONLY)) || selectedMode == Common::kRenderPC98_16c)))
+ result = Common::kRenderDefault;
+
+ if (result == Common::kRenderDefault)
+ return result;
+
+ // Now we just go over the first part of the table and if we find a config for the selected render mode and check
+ // if the mode is usable. Otherwise we return the default mode.
+ for (const GfxDriverInfo *info = _gfxDriverInfos; info->renderMode != Common::kRenderDefault; ++info) {
+ if (info->renderMode == selectedMode && info->versionMin <= version && version <= info->versionMax && (info->gameId == GID_ALL || info->gameId == g_sci->getGameId())
+ && (info->language == Common::UNK_LANG || info->language == lang) && (info->hires == kUnused || (info->hires == kEnable) == g_sci->useHiresGraphics())) {
+ result = (info->validateMode == nullptr || info->validateMode(platform)) ? selectedMode : Common::kRenderDefault;
+ break;
+ }
+ }
+
+ return result;
+}
+
+GfxDriver *create(Common::RenderMode renderMode, int width, int height) {
+ GfxDriver *result = nullptr;
+
+ int requestRGB = (int)(ConfMan.hasKey("palette_mods") && ConfMan.getBool("palette_mods")) || (ConfMan.hasKey("rgb_rendering") && ConfMan.getBool("rgb_rendering"));
+ SciVersion version = getSciVersion();
+ SciGameId gameId = g_sci->getGameId();
+ Common::Language lang = g_sci->getLanguage();
+ Common::Platform platform = g_sci->getPlatform();
+ bool hires = g_sci->useHiresGraphics();
+
+ bool undither = ConfMan.hasKey("disable_dithering") ? ConfMan.getBool("disable_dithering") : false;
+ bool winCursors = ConfMan.hasKey("windows_cursors") ? ConfMan.getBool("windows_cursors") : false;
+
+ // If a specific render mode is requested, we try to find a driver that supports it. Otherwise, we try to find a
+ // driver that supports the current platform, game and version.
+ for (const GfxDriverInfo *info = _gfxDriverInfos; info < &_gfxDriverInfos[ARRAYSIZE(_gfxDriverInfos)]; ++info) {
+ if (((info->renderMode == Common::kRenderDefault && (info->platform == Common::kPlatformUnknown || info->platform == platform)) || (renderMode != Common::kRenderDefault && info->renderMode == renderMode))
+ && version >= info->versionMin && version <= info->versionMax && (info->gameId == GID_ALL || info->gameId == gameId) && (info->language == Common::UNK_LANG || info->language == lang) && (info->hires == kUnused || (info->hires == kEnable) == hires)) {
+ result = info->createDriver(requestRGB, info->config, width, height, undither, winCursors, hires);
+ break;
+ }
+ }
+
+ return result;
+}
+
+} // End of namespace SciGfxDriver
+
diff --git a/engines/sci/graphics/drivers/pc98_16col.cpp b/engines/sci/graphics/drivers/pc98_16col.cpp
new file mode 100644
index 00000000000..6415aa30775
--- /dev/null
+++ b/engines/sci/graphics/drivers/pc98_16col.cpp
@@ -0,0 +1,244 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "common/system.h"
+#include "graphics/cursorman.h"
+#include "sci/graphics/drivers/gfxdriver_intern.h"
+
+namespace Sci {
+
+class PC98Gfx16ColorsDriver final : public UpscaledGfxDriver {
+public:
+ enum SjisFontStyle {
+ kFontStyleNone,
+ kFontStyleTextMode,
+ kFontStyleSpecialSCI1
+ };
+
+ PC98Gfx16ColorsDriver(int textAlignX, bool cursorScaleWidth, bool cursorScaleHeight, SjisFontStyle sjisFontStyle, bool rgbRendering, bool needsUnditheringPalette);
+ ~PC98Gfx16ColorsDriver() override;
+ void initScreen(const Graphics::PixelFormat *format) override;
+ void setPalette(const byte*, uint, uint, bool, const PaletteMod*, const byte*) override {}
+ void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
+ byte remapTextColor(byte color) const override;
+private:
+ const byte *_convPalette;
+ const byte *_textModePalette;
+ const bool _cursorScaleHeightOnly;
+ SjisFontStyle _fontStyle;
+};
+
+PC98Gfx16ColorsDriver::PC98Gfx16ColorsDriver(int textAlignX, bool cursorScaleWidth, bool cursorScaleHeight, SjisFontStyle sjisFontStyle, bool rgbRendering, bool needsUnditheringPalette) :
+ UpscaledGfxDriver(textAlignX, cursorScaleWidth && cursorScaleHeight, rgbRendering), _textModePalette(nullptr), _fontStyle(sjisFontStyle),
+ _cursorScaleHeightOnly(!cursorScaleWidth && cursorScaleHeight), _convPalette(nullptr) {
+ // Palette taken from driver file (identical for all versions of the
+ // driver I have seen so far, also same for SCI0 and SCI1)
+ static const byte pc98colorsV16[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x07, 0x07,
+ 0x07, 0x00, 0x00, 0x07, 0x00, 0x07, 0x05, 0x07, 0x00, 0x09, 0x09, 0x09,
+ 0x06, 0x06, 0x06, 0x00, 0x00, 0x0f, 0x07, 0x0f, 0x06, 0x00, 0x0f, 0x0f,
+ 0x0f, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f
+ };
+
+ byte *col = new byte[768]();
+ const byte *s = pc98colorsV16;
+
+ for (uint i = 0; i < sizeof(pc98colorsV16) / 3; ++i) {
+ int a = ((i & 6) == 4 || (i & 6) == 2 ? i ^ 6 : i) * 3;
+ col[a + 0] = (s[1] * 0x11);
+ col[a + 1] = (s[0] * 0x11);
+ col[a + 2] = (s[2] * 0x11);
+ s += 3;
+ }
+
+ if (_fontStyle == kFontStyleTextMode) {
+ byte *d = &col[48];
+ for (uint8 i = 0; i < 8; ++i) {
+ *d++ = (i & 4) ? 0xff : 0;
+ *d++ = (i & 2) ? 0xff : 0;
+ *d++ = (i & 1) ? 0xff : 0;
+ }
+ }
+
+ if (needsUnditheringPalette) {
+ // We store the text mode color separately, since we need the slots for the undithering.
+ if (_fontStyle == kFontStyleTextMode) {
+ byte *tpal = new byte[24]();
+ memcpy(tpal, &col[48], 24);
+ _textModePalette = tpal;
+ }
+ // For the undithered mode, we generate the missing colors using the same formula as for EGA.
+ byte *d = &col[48];
+ for (int i = 16; i < 256; i++) {
+ const byte *s1 = &col[(i & 0x0f) * 3];
+ const byte *s2 = &col[(i >> 4) * 3];
+ for (int ii = 0; ii < 3; ++ii)
+ *d++ = (byte)(0.5 + (pow(0.5 * ((pow(*s1++ / 255.0, 2.2 / 1.0) * 255.0) + (pow(*s2++ / 255.0, 2.2 / 1.0) * 255.0)) / 255.0, 1.0 / 2.2) * 255.0));
+ }
+ }
+
+ _convPalette = col;
+}
+
+PC98Gfx16ColorsDriver::~PC98Gfx16ColorsDriver() {
+ delete[] _convPalette;
+ delete[] _textModePalette;
+}
+
+void renderPC98GlyphSpecial(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h, int transpCol) {
+ assert(h == 16); // This is really not suitable for anything but the special SCI1 PC98 glyph drawing
+ dstPitch -= w;
+ srcPitch -= w;
+
+ while (h--) {
+ if (h > 10 || h < 5) {
+ for (int i = 0; i < w - 1; ++i) {
+ uint8 a = *src++;
+ uint8 b = *src;
+ if (a != transpCol)
+ *dst = a;
+ else if (b != transpCol)
+ *dst = b;
+ ++dst;
+ }
+ byte l = *src++;
+ if (l != transpCol)
+ *dst = l;
+ ++dst;
+ } else {
+ for (int i = 0; i < w; ++i) {
+ byte in = *src++;
+ if (in != transpCol)
+ *dst = in;
+ ++dst;
+ }
+ }
+ src += srcPitch;
+ dst += dstPitch;
+ }
+}
+
+void PC98Gfx16ColorsDriver::initScreen(const Graphics::PixelFormat *format) {
+ UpscaledGfxDriver::initScreen(format);
+
+ assert(_convPalette);
+ GfxDefaultDriver::setPalette(_convPalette, 0, 256, true, nullptr, nullptr);
+
+ if (_fontStyle == kFontStyleTextMode)
+ _renderGlyph = &SciGfxDrvInternal::renderPC98GlyphFat;
+
+ if (_fontStyle != kFontStyleSpecialSCI1)
+ return;
+
+ _renderGlyph = &renderPC98GlyphSpecial;
+}
+
+void PC98Gfx16ColorsDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
+ GFXDRV_ASSERT_READY;
+ if (!_cursorScaleHeightOnly) {
+ UpscaledGfxDriver::replaceCursor(cursor, w, h, hotspotX, hotspotY, keycolor);
+ return;
+ }
+
+ // Special case for PQ2 which scales the cursor height (but not the width)
+ adjustCursorBuffer(w, h << 1);
+ const byte *s = reinterpret_cast<const byte*>(cursor);
+ byte *d = _compositeBuffer;
+
+ for (uint i = 0; i < h; ++i) {
+ memcpy(d, s, w);
+ d += w;
+ memcpy(d, s, w);
+ d += w;
+ s += w;
+ }
+
+ CursorMan.replaceCursor(_compositeBuffer, w, h << 1, hotspotX, hotspotY << 1, keycolor);
+}
+
+byte PC98Gfx16ColorsDriver::remapTextColor(byte color) const {
+ // Always black for QFG and SCI1. For QFG, this is on purpose. The code just copies the inverted glyph data
+ // into all 4 vmem planes. For SCI1 the driver opcode actually has a pen color argument, but it isn't put
+ // to any use. Not sure if it is intended.
+ if (_fontStyle != kFontStyleTextMode)
+ return 0;
+
+ color &= 7;
+ // This seems to be a bug in the original PQ2 interpreter, which I replicate, so that we get the same colors.
+ // What they were trying to do is just getting the rgb bits in the right order (switch red and green). But
+ // instead, before checking and setting the bits, they also copy the full color byte to the target color. So,
+ // the extra bits come just on top. The result: All green and red colors are turned into yellow, all magenta
+ // and cyan colors are turned into white.
+ if (color & 2)
+ color |= 4;
+ if (color & 4)
+ color |= 2;
+ // This is the blue color that PQ2 uses basically for all Japanese text...
+ if (color == 0)
+ color = 1;
+
+ byte textCol = color;
+ color += 0x10;
+
+ if (_textModePalette) {
+ // If we have used up the whole space of the CLUT8 for the undithering, we try
+ // to relocate the color which will work for all text mode colors with the default
+ // palette that is used by the PC-98 ports...
+ for (int i = 0; i < 256; ++i) {
+ if (_convPalette[i * 3] != _textModePalette[textCol * 3] || _convPalette[i * 3 + 1] != _textModePalette[textCol * 3 + 1] || _convPalette[i * 3 + 2] != _textModePalette[textCol * 3 + 2])
+ continue;
+ color = i;
+ break;
+ }
+ if (color >= 16)
+ color = 0;
+ }
+ return color;
+}
+
+GfxDriver *PC98Gfx16ColorsDriver_create(int rgbRendering, ...) {
+ va_list args;
+ va_start(args, rgbRendering);
+ int config = va_arg(args, int);
+ va_arg(args, int);
+ va_arg(args, int);
+ bool undither = (va_arg(args, int) != 0);
+ va_end(args);
+
+ GfxDriver *result = nullptr;
+ if (config == 0)
+ result = new PC98Gfx16ColorsDriver(8, false, false, PC98Gfx16ColorsDriver::kFontStyleNone, rgbRendering != 0, true);
+ else if (config == 1)
+ result = new PC98Gfx16ColorsDriver(1, true, true, PC98Gfx16ColorsDriver::kFontStyleSpecialSCI1, rgbRendering != 0, true);
+ else if (config == 2) {
+ // PQ2 is a bit special, probably the oldest of the PC-98 ports. Unlike all the others, it uses text mode print,
+ // so the text color is a system color outside the normal 16 colors palette. The original does not even have a
+ // 16 colors mode driver. Only the 8 colors mode, where the colors are identical for text and graphics mode.
+ // But we do want to provide the 16 colors mode, since it is not a big deal (i.e., it does not require data
+ // from a driver file and the fat print is also already there for the 8 colors mode). So we just make the
+ // necessary adjustments.
+ result = new PC98Gfx16ColorsDriver(8, false, true, PC98Gfx16ColorsDriver::kFontStyleTextMode, rgbRendering != 0, undither);
+ }
+ return result;
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/drivers/pc98_8col_sci0.cpp b/engines/sci/graphics/drivers/pc98_8col_sci0.cpp
new file mode 100644
index 00000000000..20e5654a188
--- /dev/null
+++ b/engines/sci/graphics/drivers/pc98_8col_sci0.cpp
@@ -0,0 +1,159 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "common/system.h"
+#include "graphics/cursorman.h"
+#include "sci/graphics/drivers/gfxdriver_intern.h"
+
+namespace Sci {
+
+class SCI0_PC98Gfx8ColorsDriver final : public UpscaledGfxDriver {
+public:
+ SCI0_PC98Gfx8ColorsDriver(bool cursorScaleHeight, bool useTextModeForSJISChars, bool rgbRendering);
+ ~SCI0_PC98Gfx8ColorsDriver() override;
+ void initScreen(const Graphics::PixelFormat *format) override;
+ void setPalette(const byte*, uint, uint, bool, const PaletteMod*, const byte*) override {}
+ void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
+ byte remapTextColor(byte color) const override;
+ static bool validateMode(Common::Platform p) { return (p == Common::kPlatformPC98) && checkDriver(_driverFiles, 2); }
+private:
+ const byte *_convPalette;
+ const bool _cursorScaleHeightOnly;
+ const bool _useTextMode;
+ static const char *_driverFiles[2];
+};
+
+SCI0_PC98Gfx8ColorsDriver::SCI0_PC98Gfx8ColorsDriver(bool cursorScaleHeight, bool useTextModeForSJISChars, bool rgbRendering) :
+ UpscaledGfxDriver(8, false, rgbRendering), _cursorScaleHeightOnly(cursorScaleHeight), _useTextMode(useTextModeForSJISChars), _convPalette(nullptr) {
+ byte *col = new byte[8 * 3]();
+ _convPalette = col;
+
+ for (uint8 i = 0; i < 8; ++i) {
+ *col++ = (i & 4) ? 0xff : 0;
+ *col++ = (i & 2) ? 0xff : 0;
+ *col++ = (i & 1) ? 0xff : 0;
+ }
+}
+
+SCI0_PC98Gfx8ColorsDriver::~SCI0_PC98Gfx8ColorsDriver() {
+ delete[] _convPalette;
+}
+
+void pc98SimpleDither(byte *dst, const byte *src, int pitch, int w, int h) {
+ int dstPitch = pitch << 1;
+ byte *d1 = dst;
+ byte *d2 = d1 + dstPitch;
+ pitch -= w;
+ dstPitch += (pitch << 1);
+
+ while (h--) {
+ for (int i = 0; i < w; ++i) {
+ uint8 v = *src++;
+ d1[0] = d2[0] = (v & 7);
+ d1[1] = d2[1] = (v & 8) ? (v & 7) : 0;
+ d1 += 2;
+ d2 += 2;
+ }
+ src += pitch;
+ d1 += dstPitch;
+ d2 += dstPitch;
+ }
+}
+
+void SCI0_PC98Gfx8ColorsDriver::initScreen(const Graphics::PixelFormat *format) {
+ UpscaledGfxDriver::initScreen(format);
+ _renderScaled = &pc98SimpleDither;
+ if (_useTextMode)
+ _renderGlyph = &SciGfxDrvInternal::renderPC98GlyphFat;
+ assert(_convPalette);
+ GfxDefaultDriver::setPalette(_convPalette, 0, 8, true, nullptr, nullptr);
+}
+
+void SCI0_PC98Gfx8ColorsDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
+ GFXDRV_ASSERT_READY;
+ adjustCursorBuffer(w, _cursorScaleHeightOnly ? h << 1 : h);
+ const byte *s = reinterpret_cast<const byte*>(cursor);
+ byte *d = _compositeBuffer;
+ uint32 newKeyColor = 0xFF;
+
+ for (uint i = 0; i < h; ++i) {
+ for (uint ii = 0; ii < w; ++ii) {
+ byte col = *s++;
+ *d++ = (col == keycolor) ? newKeyColor : (col & 7);
+ }
+ }
+
+ // Special case for PQ2 which 2x scales the cursor height
+ if (_cursorScaleHeightOnly) {
+ s = _compositeBuffer + h * w - w;
+ d = _compositeBuffer + h * w * 2 - w;
+
+ for (uint i = 0; i < h; ++i) {
+ memcpy(d, s, w);
+ d -= w;
+ memcpy(d, s, w);
+ d -= w;
+ s -= w;
+ }
+ h <<= 1;
+ hotspotX <<= 1;
+ }
+
+ CursorMan.replaceCursor(_compositeBuffer, w, h, hotspotX, hotspotY, newKeyColor);
+}
+
+byte SCI0_PC98Gfx8ColorsDriver::remapTextColor(byte color) const {
+ // Always black. For QFG, this is on purpose. The code just copies the inverted glyph data into all 4 vmem planes.
+ if (!_useTextMode)
+ return 0;
+
+ color &= 7;
+ // This seems to be a bug in the original PQ2 interpreter, which I replicate, so that we get the same colors.
+ // What they were trying to do is just getting the rgb bits in the right order (switch red and green). But
+ // instead, before checking and setting the bits, they also copy the full color byte to the target color. So,
+ // the extra bits come just on top. The result: All green and red colors are turned into yellow, all magenta
+ // and cyan colors are turned into white.
+ if (color & 2)
+ color |= 4;
+ if (color & 4)
+ color |= 2;
+ // This is the blue color that PQ2 uses basically for all Japanese text...
+ if (color == 0)
+ color = 1;
+
+ return color;
+}
+
+const char *SCI0_PC98Gfx8ColorsDriver::_driverFiles[2] = { "9801V8M.DRV", "9801VID.DRV" };
+
+SCI_GFXDRV_VALIDATE_IMPL(SCI0_PC98Gfx8Colors)
+
+GfxDriver *SCI0_PC98Gfx8ColorsDriver_create(int rgbRendering, ...) {
+ va_list args;
+ va_start(args, rgbRendering);
+ bool conf = (va_arg(args, int) != 0);
+ va_end(args);
+
+ return new SCI0_PC98Gfx8ColorsDriver(conf, conf, rgbRendering != 0);
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/drivers/pc98_8col_sci1.cpp b/engines/sci/graphics/drivers/pc98_8col_sci1.cpp
new file mode 100644
index 00000000000..738707c558a
--- /dev/null
+++ b/engines/sci/graphics/drivers/pc98_8col_sci1.cpp
@@ -0,0 +1,221 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "common/file.h"
+#include "common/system.h"
+#include "graphics/cursorman.h"
+#include "sci/graphics/drivers/gfxdriver_intern.h"
+
+namespace Sci {
+
+class SCI1_PC98Gfx8ColorsDriver final : public UpscaledGfxDriver {
+public:
+ SCI1_PC98Gfx8ColorsDriver(bool rgbRendering);
+ ~SCI1_PC98Gfx8ColorsDriver() override;
+ void initScreen(const Graphics::PixelFormat *format) override;
+ void setPalette(const byte*, uint, uint, bool, const PaletteMod*, const byte*) override {}
+ void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) override;
+ void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
+ byte remapTextColor(byte) const override;
+ static bool validateMode(Common::Platform p) { return (p == Common::kPlatformPC98) && checkDriver(&_driverFile, 1); }
+private:
+ const byte *_ditheringTable;
+ const byte *_convPalette;
+ static const char *_driverFile;
+};
+
+SCI1_PC98Gfx8ColorsDriver::SCI1_PC98Gfx8ColorsDriver(bool rgbRendering) : UpscaledGfxDriver(1, true, rgbRendering), _ditheringTable(nullptr), _convPalette(nullptr) {
+ Common::File drv;
+ if (!drv.open(_driverFile))
+ GFXDRV_ERR_OPEN(_driverFile);
+
+ uint16 eprcOffs = 0;
+
+ uint32 cmd = drv.readUint32LE();
+ if ((cmd & 0xFF) == 0xE9)
+ eprcOffs = ((cmd >> 8) & 0xFFFF) + 3;
+
+ if (!eprcOffs || drv.readUint32LE() != 0x87654321 || !drv.skip(1) || !drv.seek(drv.readByte(), SEEK_CUR) || !drv.seek(drv.readByte(), SEEK_CUR))
+ GFXDRV_ERR_VERSION(_driverFile);
+
+ uint32 pos = (drv.pos() + 1) & ~1;
+
+ drv.seek(pos + 2);
+ drv.seek(drv.readUint16LE());
+ byte *buff = new byte[190];
+ drv.read(buff, 190);
+
+ uint16 tableOffs = 0;
+ int step = 0;
+ for (int i = 0; i < 182 && !tableOffs; ++i) {
+ uint32 c = READ_BE_UINT32(buff + i);
+ if (step == 0 && ((c & 0xFFF0FFF0) != 0xD1E0D1E0 || (READ_BE_UINT32(buff + i + 4) ^ c)))
+ continue;
+
+ if (step == 0) {
+ step = 1;
+ i += 7;
+ continue;
+ }
+
+ if (c >> 20 != 0x81C || ((READ_BE_UINT32(buff + i + 4) >> 20) ^ (c >> 20)))
+ continue;
+
+ if ((c & 0xFFFF) == READ_BE_UINT16(buff + i + 6))
+ tableOffs = FROM_BE_16(c);
+ }
+ delete[] buff;
+
+ if (!tableOffs)
+ error("SCI1_PC98Gfx8ColorsDriver: Failed to load dithering data from '%s'", _driverFile);
+
+ drv.seek(tableOffs);
+ byte *dmx = new byte[96]();
+ drv.read(dmx, 96);
+
+ if (drv.readUint16LE() != 0xA800 || drv.readUint16LE() != 0xB000)
+ GFXDRV_ERR_VERSION(_driverFile);
+
+ drv.close();
+
+ byte *dt = new byte[1536]();
+ _ditheringTable = dt;
+
+ for (uint16 i = 0; i < 256; ++i) {
+ for (int ii = 0; ii < 6; ++ii)
+ *dt++ = (dmx[(i >> 4) * 6 + ii] & 0xCC) | (dmx[(i & 0x0f) * 6 + ii] & 0x33);
+ }
+
+ delete[] dmx;
+
+ _textAlignX = 1;
+
+ byte *col = new byte[8 * 3]();
+ _convPalette = col;
+
+ for (uint8 i = 0; i < 8; ++i) {
+ *col++ = (i & 2) ? 0xff : 0;
+ *col++ = (i & 1) ? 0xff : 0;
+ *col++ = (i & 4) ? 0xff : 0;
+ }
+}
+
+SCI1_PC98Gfx8ColorsDriver::~SCI1_PC98Gfx8ColorsDriver() {
+ delete[] _ditheringTable;
+ delete[] _convPalette;
+}
+
+void renderPlanarMatrix(byte *dst, const byte *src, int pitch, int w, int h, const byte *tbl) {
+ int dstPitch = pitch << 1;
+ byte *d1 = dst;
+ byte *d2 = d1 + dstPitch;
+ pitch -= w;
+ dstPitch += (pitch << 1);
+
+ while (h--) {
+ byte sh = 0;
+ for (int i = 0; i < (w >> 1); ++i) {
+ const byte *c = &tbl[(src[0] << 4 | src[1]) * 6];
+ for (int ii = sh; ii < sh + 4; ++ii) {
+ *d1++ = (((c[0] >> (7 - ii)) & 1) << 2) | (((c[1] >> (7 - ii)) & 1) << 1) | ((c[2] >> (7 - ii)) & 1);
+ *d2++ = (((c[3] >> (7 - ii)) & 1) << 2) | (((c[4] >> (7 - ii)) & 1) << 1) | ((c[5] >> (7 - ii)) & 1);
+ }
+ src += 2;
+ sh ^= 4;
+ }
+
+ src += pitch;
+ d1 += dstPitch;
+ d2 += dstPitch;
+ }
+}
+
+void SCI1_PC98Gfx8ColorsDriver::initScreen(const Graphics::PixelFormat *format) {
+ UpscaledGfxDriver::initScreen(format);
+
+ _renderGlyph = &SciGfxDrvInternal::renderPC98GlyphFat;
+
+ assert(_convPalette);
+ GfxDefaultDriver::setPalette(_convPalette, 0, 8, true, nullptr, nullptr);
+}
+
+void SCI1_PC98Gfx8ColorsDriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) {
+ GFXDRV_ASSERT_READY;
+ assert (h >= 0 && w >= 0);
+
+ byte diff = srcX & 7;
+ srcX &= ~7;
+ destX &= ~7;
+ w = (w + diff + 7) & ~7;
+
+ src += (srcY * pitch + srcX * _srcPixelSize);
+ if (src != _currentBitmap)
+ SciGfxDrvInternal::updateBitmapBuffer(_currentBitmap, _virtualW * _srcPixelSize, src, pitch, destX * _srcPixelSize, destY, w * _srcPixelSize, h);
+
+ byte *scb = _scaledBitmap + (destY << 1) * _screenW * _srcPixelSize + (destX << 1) * _srcPixelSize;
+ renderPlanarMatrix(scb, src, pitch, w, h, _ditheringTable);
+
+ updateScreen(destX << 1, destY << 1, w << 1, h << 1, palMods, palModMapping);
+}
+
+void SCI1_PC98Gfx8ColorsDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
+ GFXDRV_ASSERT_READY;
+ adjustCursorBuffer(w << 1, h << 1);
+ const byte *s = reinterpret_cast<const byte*>(cursor);
+ byte *d1 = _compositeBuffer;
+ uint32 newKeyColor = 0xFF;
+
+ int dstPitch = (w << 1);
+ byte *d2 = _compositeBuffer + dstPitch;
+
+ for (uint i = 0; i < h; ++i) {
+ for (uint ii = 0; ii < w; ++ii) {
+ byte col = *s++;
+ if (col == keycolor) {
+ *d1++ = *d2++ = newKeyColor;
+ *d1++ = *d2++ = newKeyColor;
+ } else {
+ *d1++ = *d2++ = (col & 7);
+ *d1++ = *d2++ = (col & 8) ? (col & 7) : 0;
+ }
+ }
+ d1 += dstPitch;
+ d2 += dstPitch;
+ }
+
+ CursorMan.replaceCursor(_compositeBuffer, w << 1, h << 1, hotspotX << 1, hotspotY << 1, newKeyColor);
+}
+
+byte SCI1_PC98Gfx8ColorsDriver::remapTextColor(byte) const {
+ // Always black. The driver opcode actually has a pen color argument, but it isn't put to any use. Not sure if it is intended.
+ return 0;
+}
+
+const char *SCI1_PC98Gfx8ColorsDriver::_driverFile = "9801V8.DRV";
+
+SCI_GFXDRV_VALIDATE_IMPL(SCI1_PC98Gfx8Colors)
+
+GfxDriver *SCI1_PC98Gfx8ColorsDriver_create(int rgbRendering, ...) {
+ return new SCI1_PC98Gfx8ColorsDriver(rgbRendering != 0);
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/drivers/upscaled.cpp b/engines/sci/graphics/drivers/upscaled.cpp
new file mode 100644
index 00000000000..b25ed10cab8
--- /dev/null
+++ b/engines/sci/graphics/drivers/upscaled.cpp
@@ -0,0 +1,193 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "common/system.h"
+#include "graphics/cursorman.h"
+#include "sci/graphics/drivers/gfxdriver_intern.h"
+
+namespace Sci {
+
+UpscaledGfxDriver::UpscaledGfxDriver(int16 textAlignX, bool scaleCursor, bool rgbRendering) :
+ UpscaledGfxDriver(640, 400, textAlignX, scaleCursor, rgbRendering) {
+}
+
+UpscaledGfxDriver::UpscaledGfxDriver(uint16 scaledW, uint16 scaledH, int16 textAlignX, bool scaleCursor, bool rgbRendering) :
+ GfxDefaultDriver(scaledW, scaledH, false, rgbRendering), _textAlignX(textAlignX), _scaleCursor(scaleCursor), _needCursorBuffer(false),
+ _scaledBitmap(nullptr), _renderScaled(nullptr), _renderGlyph(nullptr), _cursorWidth(0), _cursorHeight(0), _hScaleMult(2), _vScaleMult(2), _vScaleDiv(1) {
+ _virtualW = 320;
+ _virtualH = 200;
+}
+
+UpscaledGfxDriver::~UpscaledGfxDriver() {
+ delete[] _scaledBitmap;
+}
+
+void renderGlyph(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h, int transpCol) {
+ dstPitch -= w;
+ srcPitch -= w;
+
+ while (h--) {
+ for (int i = 0; i < w; ++i) {
+ byte in = *src++;
+ if (in != transpCol)
+ *dst = in;
+ ++dst;
+ }
+ src += srcPitch;
+ dst += dstPitch;
+ }
+}
+
+void UpscaledGfxDriver::initScreen(const Graphics::PixelFormat *format) {
+ GfxDefaultDriver::initScreen(format);
+ _scaledBitmap = new byte[_screenW * _screenH * _srcPixelSize]();
+
+ static const ScaledRenderProc scaledRenderProcs[] = {
+ &SciGfxDrvInternal::scale2x<byte>,
+ &SciGfxDrvInternal::scale2x<uint16>,
+ &SciGfxDrvInternal::scale2x<uint32>
+ };
+ assert((_srcPixelSize >> 1) < ARRAYSIZE(scaledRenderProcs));
+ _renderScaled = scaledRenderProcs[_srcPixelSize >> 1];
+ _renderGlyph = &renderGlyph;
+}
+
+void UpscaledGfxDriver::setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod *palMods, const byte *palModMapping) {
+ GFXDRV_ASSERT_READY;
+ if (_pixelSize == 1) {
+ GfxDefaultDriver::setPalette(colors, start, num, update, palMods, palModMapping);
+ return;
+ }
+ updatePalette(colors, start, num);
+ if (update)
+ updateScreen(0, 0, _screenW, _screenH, palMods, palModMapping);
+ if (_cursorUsesScreenPalette)
+ CursorMan.replaceCursorPalette(_currentPalette, 0, 256);
+}
+
+void UpscaledGfxDriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) {
+ GFXDRV_ASSERT_READY;
+ assert (h >= 0 && w >= 0);
+
+ src += (srcY * pitch + srcX * _srcPixelSize);
+ if (src != _currentBitmap)
+ SciGfxDrvInternal::updateBitmapBuffer(_currentBitmap, _virtualW * _srcPixelSize, src, pitch, destX * _srcPixelSize, destY, w * _srcPixelSize, h);
+
+ int realWidth = 0;
+ int realHeight = 0;
+
+ // We need to scale and color convert the bitmap in separate functions, because we want
+ // to keep the scaled non-color-modified bitmap for palette updates in rgb rendering mode.
+ renderBitmap(src, pitch, destX, destY, w, h, realWidth, realHeight);
+
+ Common::Point p(destX, destY);
+ p = getRealCoords(p);
+
+ updateScreen(p.x, p.y, realWidth, realHeight, palMods, palModMapping);
+}
+
+void UpscaledGfxDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
+ GFXDRV_ASSERT_READY;
+ if (_scaleCursor) {
+ adjustCursorBuffer(w << 1, h << 1);
+ SciGfxDrvInternal::scale2x<byte>(_compositeBuffer, reinterpret_cast<const byte*>(cursor), w, w, h);
+ CursorMan.replaceCursor(_compositeBuffer, w << 1, h << 1, hotspotX << 1, hotspotY << 1, keycolor);
+ } else {
+ CursorMan.replaceCursor(cursor, w, h, hotspotX, hotspotY, keycolor);
+ }
+}
+
+Common::Point UpscaledGfxDriver::getMousePos() const {
+ Common::Point res = GfxDriver::getMousePos();
+ res.x /= _hScaleMult;
+ res.y = res.y * _vScaleDiv / _vScaleMult;
+ return res;
+}
+
+void UpscaledGfxDriver::setMousePos(const Common::Point &pos) const {
+ g_system->warpMouse(pos.x * _hScaleMult, pos.y * _vScaleMult / _vScaleDiv);
+}
+
+void UpscaledGfxDriver::setShakePos(int shakeXOffset, int shakeYOffset) const {
+ g_system->setShakePos(shakeXOffset * _hScaleMult, shakeYOffset * _vScaleMult / _vScaleDiv);
+}
+
+void UpscaledGfxDriver::clearRect(const Common::Rect &r) const {
+ Common::Rect r2(r.left * _hScaleMult, r.top * _vScaleMult / _vScaleDiv, r.right * _hScaleMult, r.bottom * _vScaleMult / _vScaleDiv);
+ GfxDriver::clearRect(r2);
+}
+
+Common::Point UpscaledGfxDriver::getRealCoords(Common::Point &pos) const {
+ return Common::Point(pos.x * _hScaleMult, pos.y * _vScaleMult / _vScaleDiv);
+}
+
+void UpscaledGfxDriver::drawTextFontGlyph(const byte *src, int pitch, int hiresDestX, int hiresDestY, int hiresW, int hiresH, int transpColor, const PaletteMod *palMods, const byte *palModMapping) {
+ GFXDRV_ASSERT_READY;
+ hiresDestX &= ~(_textAlignX - 1);
+ byte *scb = _scaledBitmap + hiresDestY * _screenW * _srcPixelSize + hiresDestX * _srcPixelSize;
+ _renderGlyph(scb, _screenW, src, pitch, hiresW, hiresH, transpColor);
+ updateScreen(hiresDestX, hiresDestY, hiresW, hiresH, palMods, palModMapping);
+}
+
+void UpscaledGfxDriver::updateScreen(int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) {
+ byte *buff = _compositeBuffer;
+ int pitch = w * _pixelSize;
+ byte *scb = _scaledBitmap + destY * _screenW * _srcPixelSize + destX * _srcPixelSize;
+ if (palMods && palModMapping) {
+ _colorConvMod(buff, scb, _screenW, w, h, _currentPalette, _internalPalette, _format, palMods, palModMapping);
+ } else if (_pixelSize != _srcPixelSize) {
+ _colorConv(buff, scb, _screenW, w, h, _internalPalette);
+ } else {
+ buff = scb;
+ pitch = _screenW *_pixelSize;
+ }
+
+ g_system->copyRectToScreen(buff, pitch, destX, destY, w, h);
+}
+
+void UpscaledGfxDriver::adjustCursorBuffer(uint16 newWidth, uint16 newHeight) {
+ // For configs which need/have the composite buffer for other purposes, we can skip this.
+ if (!_compositeBuffer)
+ _needCursorBuffer = true;
+ else if (!_needCursorBuffer)
+ return;
+
+ if (_cursorWidth * _cursorHeight < newWidth * newHeight) {
+ delete[] _compositeBuffer;
+ _compositeBuffer = new byte[newWidth * newHeight * _srcPixelSize]();
+ _cursorWidth = newWidth;
+ _cursorHeight = newHeight;
+ }
+}
+
+void UpscaledGfxDriver::renderBitmap(const byte *src, int pitch, int dx, int dy, int w, int h, int &realWidth, int &realHeight) {
+ byte *scb = _scaledBitmap + (dy << 1) * _screenW * _srcPixelSize + (dx << 1) * _srcPixelSize;
+ _renderScaled(scb, src, pitch, w, h);
+ realWidth = w << 1;
+ realHeight = h << 1;
+}
+
+GfxDriver *UpscaledGfxDriver_create(int rgbRendering, ...) {
+ return new UpscaledGfxDriver(1, true, rgbRendering != 0);
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/drivers/vgagrey.cpp b/engines/sci/graphics/drivers/vgagrey.cpp
new file mode 100644
index 00000000000..991e44e5db1
--- /dev/null
+++ b/engines/sci/graphics/drivers/vgagrey.cpp
@@ -0,0 +1,69 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "common/system.h"
+#include "sci/graphics/drivers/gfxdriver_intern.h"
+
+namespace Sci {
+
+class SCI1_VGAGreyScaleDriver final : public GfxDefaultDriver {
+public:
+ SCI1_VGAGreyScaleDriver(bool rgbRendering);
+ ~SCI1_VGAGreyScaleDriver() override;
+ void setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod *palMods, const byte *palModMapping) override;
+ static bool validateMode(Common::Platform p) { return (p == Common::kPlatformDOS || p == Common::kPlatformWindows) && checkDriver(&_driverFile, 1); }
+private:
+ byte *_greyScalePalette;
+ static const char *_driverFile;
+};
+
+SCI1_VGAGreyScaleDriver::SCI1_VGAGreyScaleDriver(bool rgbRendering) : GfxDefaultDriver(320, 200, false, rgbRendering), _greyScalePalette(nullptr) {
+ _greyScalePalette = new byte[_numColors * 3]();
+}
+
+SCI1_VGAGreyScaleDriver::~SCI1_VGAGreyScaleDriver() {
+ delete[] _greyScalePalette;
+}
+
+void SCI1_VGAGreyScaleDriver::setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod *palMods, const byte *palModMapping) {
+ GFXDRV_ASSERT_READY;
+ byte *d = _greyScalePalette;
+ for (uint i = 0; i < num; ++i) {
+ // In the driver files I inspected there were never any other color distributions than this.
+ // So I guess it is safe to hardcode that instead of loading it from the driver file.
+ d[0] = d[1] = d[2] = (colors[0] * 77 + colors[1] * 150 + colors[2] * 28) >> 8;
+ colors += 3;
+ d += 3;
+ }
+
+ GfxDefaultDriver::setPalette(_greyScalePalette, start, num, update, palMods, palModMapping);
+}
+
+const char *SCI1_VGAGreyScaleDriver::_driverFile = "VGA320BW.DRV";
+
+SCI_GFXDRV_VALIDATE_IMPL(SCI1_VGAGreyScale)
+
+GfxDriver *SCI1_VGAGreyScaleDriver_create(int rgbRendering, ...) {
+ return new SCI1_VGAGreyScaleDriver(rgbRendering != 0);
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/drivers/win16col.cpp b/engines/sci/graphics/drivers/win16col.cpp
new file mode 100644
index 00000000000..d35cf609122
--- /dev/null
+++ b/engines/sci/graphics/drivers/win16col.cpp
@@ -0,0 +1,184 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "common/file.h"
+#include "common/system.h"
+#include "graphics/cursorman.h"
+#include "sci/graphics/drivers/gfxdriver_intern.h"
+
+namespace Sci {
+
+class WindowsGfx16ColorsDriver final : public SCI1_EGADriver {
+public:
+ // The original does not take into account the extra lines required for the 200->440 vertical scaling. There is a noticeable dithering glitch every 11th line, as the
+ // two pixels of the checkerbox pattern appear in the wrong order. I have implemented a fix for this which can be activated with the fixDithering parameter.
+ WindowsGfx16ColorsDriver(bool fixDithering, bool rgbRendering);
+ ~WindowsGfx16ColorsDriver() override {}
+ void initScreen(const Graphics::PixelFormat *format) override;
+ void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
+ Common::Point getRealCoords(Common::Point &pos) const override;
+ static bool validateMode(Common::Platform p) { return (p == Common::kPlatformWindows && checkDriver(&_driverFile, 1)); }
+private:
+ void loadData() override;
+ void renderBitmap(byte *dst, const byte *src, int pitch, int y, int w, int h, const byte *patterns, const byte *palette, uint16 &realWidth, uint16 &realHeight) override;
+ LineProc _renderLine2;
+ const bool _enhancedDithering;
+ static const char *_driverFile;
+};
+
+WindowsGfx16ColorsDriver::WindowsGfx16ColorsDriver(bool enhancedDithering, bool rgbRendering) : SCI1_EGADriver(rgbRendering), _enhancedDithering(enhancedDithering), _renderLine2(nullptr) {
+ static const byte win16Colors[48] = {
+ 0x00, 0x00, 0x00, 0xA8, 0x00, 0x57, 0x00, 0xA8, 0x57, 0xA8, 0xA8, 0x57,
+ 0x00, 0x00, 0xA8, 0xA8, 0x57, 0xA8, 0x57, 0xA8, 0xA8, 0x87, 0x88, 0x8F,
+ 0xC0, 0xC7, 0xC8, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+ };
+
+ _convPalette = win16Colors;
+ _vScaleMult = 11;
+ _vScaleDiv = 5;
+}
+
+template <typename T, bool extScale> void win16ColRenderLine(byte *&dst, const byte *src, int w, const byte *patterns, const byte *pal, bool swap) {
+ const T *p = reinterpret_cast<const T*>(pal);
+ T *d1 = reinterpret_cast<T*>(dst);
+ T *d2 = d1 + (w << 1);
+ T *d3 = d2 + (w << 1);
+ T *&d3r = swap ? d2 : d1;
+
+ if (swap)
+ SWAP(d1, d2);
+
+ for (int i = 0; i < w; ++i) {
+ byte pt = patterns[*src++];
+ if (sizeof(T) == 1) {
+ *d1++ = d2[1] = pt & 0x0F;
+ *d1++ = *d2++ = pt >> 4;
+ } else {
+ *d1++ = d2[1] = p[pt & 0x0F];
+ *d1++ = *d2++ = p[pt >> 4];
+ }
+ d2++;
+
+ if (extScale) {
+ *d3++ = *(d3r - 2);
+ *d3++ = *(d3r - 1);
+ }
+ }
+
+ dst = reinterpret_cast<byte*>(extScale ? d3 : (swap ? d1 : d2));
+}
+
+void WindowsGfx16ColorsDriver::initScreen(const Graphics::PixelFormat *format) {
+ SCI1_EGADriver::initScreen(format);
+
+ static const LineProc lineProcs[] = {
+ &win16ColRenderLine<byte, false>,
+ &win16ColRenderLine<byte, true>,
+ &win16ColRenderLine<uint16, false>,
+ &win16ColRenderLine<uint16, true>,
+ &win16ColRenderLine<uint32, false>,
+ &win16ColRenderLine<uint32, true>
+ };
+
+ assert((_pixelSize | 1) < ARRAYSIZE(lineProcs));
+ _renderLine = lineProcs[_pixelSize & ~1];
+ _renderLine2 = lineProcs[_pixelSize | 1];
+}
+
+void WindowsGfx16ColorsDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
+ GFXDRV_ASSERT_READY;
+ // The original windows interpreter always renders the cursor as b/w, regardless of which cursor views (the DOS
+ // cursors or the new Windows ones) the user selects. This is also regardless of color mode (16 or 256 colors).
+ byte col1 = SciGfxDrvInternal::findColorInPalette(0x00000000, _convPalette, _numColors);
+ byte col2 = SciGfxDrvInternal::findColorInPalette(0x00FFFFFF, _convPalette, _numColors);
+ SciGfxDrvInternal::renderWinMonochromeCursor(_compositeBuffer, cursor, _currentPalette, w, h, hotspotX, hotspotY, col1, col2, keycolor, false);
+ CursorMan.replaceCursor(_compositeBuffer, w, h, hotspotX, hotspotY, keycolor);
+}
+
+Common::Point WindowsGfx16ColorsDriver::getRealCoords(Common::Point &pos) const {
+ return Common::Point(pos.x << 1, (pos.y << 1) + (pos.y + 4) / 5);
+}
+
+void WindowsGfx16ColorsDriver::loadData() {
+ Common::File file;
+ if (!file.open(_driverFile))
+ GFXDRV_ERR_OPEN(_driverFile);
+
+ int64 sz = file.size();
+ byte *buf = new byte[sz];
+ file.read(buf, sz);
+ file.close();
+
+ // We can keep the search for the table simple, since there are only two supported executables (KQ6
+ // Windows and SQ4 Windows) and both contain the following value only within the pattern table...
+ uint32 srch = FROM_LE_32(0xCC4C4404);
+
+ const byte *tblOffs = nullptr;
+ for (const byte *pos = buf; pos < buf + sz - 67 && tblOffs == nullptr; ++pos) {
+ // We check three times, just to be sure. Checking once would actually suffice.
+ if (READ_UINT32(pos) != srch || READ_UINT32(pos + 8) != srch || READ_UINT32(pos + 64) != srch)
+ continue;
+ tblOffs = pos - 4;
+ }
+
+ if (tblOffs == nullptr)
+ error("%s(): Failed to load 16 colors match table", __FUNCTION__);
+
+ byte *tbl = new byte[512];
+ memcpy(tbl, tblOffs, 512);
+ _egaMatchTable = tbl;
+
+ delete[] buf;
+
+ _colAdjust = (_egaMatchTable[482] == 0x79) ? 4 : 0;
+ _numColors = 16;
+}
+
+void WindowsGfx16ColorsDriver::renderBitmap(byte *dst, const byte *src, int pitch, int y, int w, int h, const byte *patterns, const byte *palette, uint16 &realWidth, uint16 &realHeight) {
+ const byte *dst0 = dst;
+ byte mod = (y + 4) % 5;
+ byte swap = _enhancedDithering ? ((y + 4) / 5) & 1 : 0;
+ for (int i = 0; i < h; ++i) {
+ if (++mod == 5) {
+ _renderLine2(dst, src, w, patterns, palette, swap);
+ if (_enhancedDithering)
+ swap ^= 1;
+ mod = 0;
+ } else {
+ _renderLine(dst, src, w, patterns, palette, swap);
+ }
+ src += pitch;
+ }
+ realWidth = w << 1;
+ realHeight = (dst - dst0) / (realWidth * _pixelSize);
+}
+
+const char *WindowsGfx16ColorsDriver::_driverFile = "SCIWV.EXE";
+
+SCI_GFXDRV_VALIDATE_IMPL(WindowsGfx16Colors)
+
+GfxDriver *WindowsGfx16ColorsDriver_create(int rgbRendering, ...) {
+ return new WindowsGfx16ColorsDriver(true, rgbRendering != 0);
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/drivers/win256col.cpp b/engines/sci/graphics/drivers/win256col.cpp
new file mode 100644
index 00000000000..33fba8e1314
--- /dev/null
+++ b/engines/sci/graphics/drivers/win256col.cpp
@@ -0,0 +1,259 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "common/system.h"
+#include "graphics/cursorman.h"
+#include "sci/graphics/drivers/gfxdriver_intern.h"
+
+namespace Sci {
+
+class WindowsGfx256ColorsDriver final : public UpscaledGfxDriver {
+public:
+ WindowsGfx256ColorsDriver(bool coloredDosStyleCursors, bool smallWindow, bool rgbRendering);
+ ~WindowsGfx256ColorsDriver() override {}
+ void initScreen(const Graphics::PixelFormat *format) override;
+ void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) override;
+ void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
+ Common::Point getRealCoords(Common::Point &pos) const override;
+ void setColorMap(const byte *colorMap) override { _colorMap = colorMap; }
+ void setFlags(uint32 flags) override;
+ void clearFlags(uint32 flags) override;
+ bool supportsHiResGraphics() const override { return !_smallWindow; }
+ bool driverBasedTextRendering() const override { return false; }
+protected:
+ typedef void (*LineProc)(byte*&, const byte*, int, int, int);
+ LineProc _renderLine;
+private:
+ typedef void (*LineProcSpec)(byte*&, const byte*, int, int, const byte*);
+ LineProcSpec _renderLine2;
+ void renderBitmap(const byte *src, int pitch, int dx, int dy, int w, int h, int &realWidth, int &realHeight) override;
+ uint32 _flags;
+ const byte *_colorMap;
+ const bool _smallWindow;
+ const bool _dosStyleCursors;
+ uint16 _vScaleMult2;
+};
+
+WindowsGfx256ColorsDriver::WindowsGfx256ColorsDriver(bool coloredDosStyleCursors, bool smallWindow,bool rgbRendering) :
+ UpscaledGfxDriver(smallWindow ? 320 : 640, smallWindow ? 240 : 440, 1, coloredDosStyleCursors && !smallWindow, rgbRendering), _dosStyleCursors(coloredDosStyleCursors), _smallWindow(smallWindow),
+ _renderLine(nullptr), _renderLine2(nullptr), _flags(0), _colorMap(nullptr), _vScaleMult2(smallWindow ? 1 : 2) {
+ _virtualW = 320;
+ _virtualH = 200;
+ if (smallWindow)
+ _hScaleMult = 1;
+ _vScaleMult = _smallWindow ? 6 : 11;
+ _vScaleDiv = 5;
+}
+
+void largeWindowRenderLine(byte *&dst, const byte *src, int pitch, int w, int ty) {
+ int dstPitch = pitch;
+ int dstPitch2 = pitch - (w << 1);
+ byte *d1 = dst;
+ byte *d2 = d1 + dstPitch;
+
+ if (ty == 5) {
+ byte *d3 = d2 + dstPitch;
+ for (int i = 0; i < w; ++i) {
+ d1[0] = d1[1] = d2[0] = d2[1] = d3[0] = d3[1] = *src++;
+ d1 += 2;
+ d2 += 2;
+ d3 += 2;
+ }
+ dst = d3 + dstPitch2;
+ } else {
+ for (int i = 0; i < w; ++i) {
+ d1[0] = d1[1] = d2[0] = d2[1] = *src++;
+ d1 += 2;
+ d2 += 2;
+ }
+ dst = d2 + dstPitch2;
+ }
+}
+
+void largeWindowRenderLineMovie(byte *&dst, const byte *src, int pitch, int w, const byte*) {
+ int dstPitch = pitch;
+ int dstPitch2 = pitch - (w << 1);
+ byte *d1 = dst;
+ byte *d2 = d1 + dstPitch;
+
+ for (int i = 0; i < w; ++i) {
+ d1[0] = d1[1] = d2[0] = d2[1] = *src++;
+ d1 += 2;
+ d2 += 2;
+ }
+ dst = d2 + dstPitch2;
+}
+
+void smallWindowRenderLine(byte *&dst, const byte *src, int pitch, int w, int ty) {
+ int dstPitch = pitch;
+ int dstPitch2 = pitch - w;
+ byte *d1 = dst;
+
+ if (ty == 5) {
+ byte *d2 = d1 + dstPitch;
+ for (int i = 0; i < w; ++i)
+ *d1++ = *d2++ = *src++;
+ dst = d2 + dstPitch2;
+ } else {
+ for (int i = 0; i < w; ++i)
+ *d1++ = *src++;
+ dst = d1 + dstPitch2;
+ }
+}
+
+void smallWindowRenderLineMovie(byte *&dst, const byte *src, int pitch, int w, const byte*) {
+ int dstPitch = pitch - w;
+ byte *d1 = dst;
+
+ for (int i = 0; i < w; ++i)
+ *d1++ = *src++;
+ dst = d1 + dstPitch;
+}
+
+void hiresRenderLine(byte *&dst, const byte *src, int pitch, int w, const byte *colorMap) {
+ if (!colorMap) {
+ memcpy(dst, src, w);
+ } else {
+ byte *d = dst;
+ for (int i = 0; i < w; ++i)
+ *d++ = colorMap[*src++];
+ }
+ dst += pitch;
+}
+
+void renderLineDummy(byte *&, const byte* , int, int, const byte*) {
+}
+
+void WindowsGfx256ColorsDriver::initScreen(const Graphics::PixelFormat *format) {
+ UpscaledGfxDriver::initScreen(format);
+ _renderLine = _smallWindow ? &smallWindowRenderLine : &largeWindowRenderLine;
+ _renderLine2 = _smallWindow ? &renderLineDummy : &hiresRenderLine;
+}
+
+void WindowsGfx256ColorsDriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) {
+ GFXDRV_ASSERT_READY;
+ assert (h >= 0 && w >= 0);
+
+ if (!(_flags & (kHiResMode | kMovieMode))) {
+ UpscaledGfxDriver::copyRectToScreen(src, srcX, srcY, pitch, destX, destY, w, h, palMods, palModMapping);
+ return;
+ }
+
+ if (_flags & kMovieMode) {
+ destX = (_screenW >> 1) - (w & ~1) * _hScaleMult / 2;
+ destY = (_screenH >> 1) - (h & ~1) * _vScaleMult2 / 2;
+ }
+
+ src += (srcY * pitch + srcX * _srcPixelSize);
+ byte *dst = _scaledBitmap + destY * _screenW * _srcPixelSize + destX * _srcPixelSize;
+
+ for (int i = 0; i < h; ++i) {
+ _renderLine2(dst, src, _screenW, w, _colorMap);
+ src += pitch;
+ }
+
+ if (_flags & kMovieMode) {
+ w *= _hScaleMult;
+ h *= _vScaleMult2;
+ }
+
+ updateScreen(destX, destY, w, h, palMods, palModMapping);
+}
+
+void WindowsGfx256ColorsDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
+ GFXDRV_ASSERT_READY;
+ if (_dosStyleCursors) {
+ // The original windows interpreter always renders the cursor as b/w, regardless of which cursor views (the DOS
+ // cursors or the new Windows ones) the user selects. This is also regardless of color mode (16 or 256 colors).
+ // It is a technical limitation on Windows 95 with VGA hardware that mouse cursors have to be b/w.
+ // Instead, we use the colored DOS style cursors as a default, since there was consensus to do that.
+ UpscaledGfxDriver::replaceCursor(cursor, w, h, hotspotX, hotspotY, keycolor);
+ return;
+ }
+ adjustCursorBuffer(w << 1, h << 1);
+
+ if (_pixelSize == 1)
+ copyCurrentPalette(_currentPalette, 0, _numColors);
+
+ byte col1 = SciGfxDrvInternal::findColorInPalette(0x00000000, _currentPalette, _numColors);
+ byte col2 = SciGfxDrvInternal::findColorInPalette(0x00FFFFFF, _currentPalette, _numColors);
+ SciGfxDrvInternal::renderWinMonochromeCursor(_compositeBuffer, cursor, _currentPalette, w, h, hotspotX, hotspotY, col1, col2, keycolor, _smallWindow);
+ CursorMan.replaceCursor(_compositeBuffer, w, h, hotspotX, hotspotY, keycolor);
+}
+
+Common::Point WindowsGfx256ColorsDriver::getRealCoords(Common::Point &pos) const {
+ return Common::Point(pos.x * _hScaleMult, pos.y * _vScaleMult2 + (pos.y + 4) / 5);
+}
+
+void WindowsGfx256ColorsDriver::setFlags(uint32 flags) {
+ flags ^= (_flags & flags);
+ if (!flags)
+ return;
+
+ if (flags & kMovieMode)
+ _renderLine2 = _smallWindow ? &smallWindowRenderLineMovie : &largeWindowRenderLineMovie;
+
+ _flags |= flags;
+}
+
+void WindowsGfx256ColorsDriver::clearFlags(uint32 flags) {
+ flags &= _flags;
+ if (!flags)
+ return;
+
+ if (flags & kMovieMode)
+ _renderLine2 = _smallWindow ? &renderLineDummy : &hiresRenderLine;
+
+ _flags &= ~flags;
+}
+
+void WindowsGfx256ColorsDriver::renderBitmap(const byte *src, int pitch, int dx, int dy, int w, int h, int &realWidth, int &realHeight) {
+ assert(_renderLine);
+
+ byte *dst = _scaledBitmap + (dy * _vScaleMult2 + (dy + 4) / 5) * _screenW * _srcPixelSize + dx *_hScaleMult * _srcPixelSize;
+ const byte *dstart = dst;
+ dy = (dy + 4) % 5;
+
+ while (h--) {
+ _renderLine(dst, src, _screenW, w, ++dy);
+ dy %= 5;
+ src += pitch;
+ }
+
+ realWidth = w * _hScaleMult;
+ realHeight = (dst - dstart) / _screenW;
+}
+
+GfxDriver *WindowsGfx256ColorsDriver_create(int rgbRendering, ...) {
+ va_list args;
+ va_start(args, rgbRendering);
+ int config = va_arg(args, int);
+ va_arg(args, int);
+ va_arg(args, int);
+ va_arg(args, int);
+ bool winCursors = (va_arg(args, int) != 0);
+ va_end(args);
+
+ return new WindowsGfx256ColorsDriver(!winCursors, config == 0, rgbRendering != 0);
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/fontsjis.cpp b/engines/sci/graphics/fontsjis.cpp
index 462373cce6b..ba2dc499d29 100644
--- a/engines/sci/graphics/fontsjis.cpp
+++ b/engines/sci/graphics/fontsjis.cpp
@@ -21,7 +21,7 @@
#include "sci/sci.h"
#include "sci/engine/state.h"
-#include "sci/graphics/gfxdrivers.h"
+#include "sci/graphics/drivers/gfxdriver.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/scifont.h"
#include "sci/graphics/fontsjis.h"
diff --git a/engines/sci/graphics/gfxdrivers.cpp b/engines/sci/graphics/gfxdrivers.cpp
deleted file mode 100644
index ecdb45004ab..00000000000
--- a/engines/sci/graphics/gfxdrivers.cpp
+++ /dev/null
@@ -1,2267 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "common/events.h"
-#include "common/system.h"
-
-#include "engines/util.h"
-
-#include "graphics/cursorman.h"
-#include "graphics/paletteman.h"
-
-#include "sci/graphics/gfxdrivers.h"
-#include "sci/resource/resource.h"
-#include "sci/sci.h"
-
-namespace Sci {
-
-#define GFXDRV_ASSERT_READY \
- if (!_ready) \
- error("%s(): initScreen() must be called before using this method", __FUNCTION__)
-
-#define GFXDRV_ERR_OPEN(x) \
- error("%s(): Failed to open '%s'", __FUNCTION__, x)
-
-#define GFXDRV_ERR_VERSION(x) \
- error("%s(): Driver file '%s' unknown version", __FUNCTION__, x)
-
-Common::Point GfxDriver::getMousePos() const {
- return g_system->getEventManager()->getMousePos();
-}
-
-void GfxDriver::setMousePos(const Common::Point &pos) const {
- g_system->warpMouse(pos.x, pos.y);
-}
-
-void GfxDriver::setShakePos(int shakeXOffset, int shakeYOffset) const {
- g_system->setShakePos(shakeXOffset, shakeYOffset);
-}
-
-void GfxDriver::clearRect(const Common::Rect &r) const {
- GFXDRV_ASSERT_READY;
- g_system->fillScreen(r, 0);
-}
-
-void GfxDriver::copyCurrentPalette(byte *dest, int start, int num) const {
- assert(dest);
- assert(start + num <= 256);
- g_system->getPaletteManager()->grabPalette(dest, start, num);
-}
-
-bool GfxDriver::checkDriver(const char *const *driverNames, int listSize) {
- Common::String missing;
- while (listSize-- && *driverNames) {
- if (Common::File::exists(*driverNames))
- return true;
- if (!missing.empty())
- missing += " or ";
- missing += "'" + Common::String(*driverNames) + "'";
- ++driverNames;
- }
- warning("Driver file %s not found. Starting game in default mode", missing.c_str());
- return false;
-}
-
-GfxDefaultDriver::GfxDefaultDriver(uint16 screenWidth, uint16 screenHeight, bool isSCI0, bool rgbRendering) : GfxDriver(screenWidth, screenHeight, 0), _cursorUsesScreenPalette(true), _colorConv(nullptr), _colorConvMod(nullptr),
- _srcPixelSize(1), _requestRGBMode(rgbRendering), _compositeBuffer(nullptr), _currentBitmap(nullptr), _internalPalette(nullptr), _currentPalette(nullptr), _virtualW(screenWidth), _virtualH(screenHeight), _alwaysCreateBmpBuffer(!isSCI0) {
- switch (g_sci->getResMan()->getViewType()) {
- case kViewEga:
- _numColors = 16; // QFG PC-98 with 8 colors also reports 16 here
- break;
- case kViewAmiga:
- _numColors = 32;
- break;
- case kViewAmiga64:
- _numColors = 64;
- break;
- case kViewVga:
- case kViewVga11:
- _numColors = 256;
- break;
- default:
- break;
- }
-
- if (_numColors == 0)
- error("GfxDefaultDriver: Unknown view type");
-}
-
-GfxDefaultDriver::~GfxDefaultDriver() {
- delete[] _compositeBuffer;
- delete[] _currentBitmap;
- delete[] _internalPalette;
- delete[] _currentPalette;
-}
-
-template <typename T> void colorConvert(byte *dst, const byte *src, int pitch, int w, int h, const byte *pal) {
- T *d = reinterpret_cast<T*>(dst);
- const T *p = reinterpret_cast<const T*>(pal);
- const byte *s = src;
- pitch -= w;
-
- while (h--) {
- for (int i = 0; i < w; ++i)
- *d++ = p[*s++];
- s += pitch;
- }
-}
-
-#define applyMod(a, b) MIN<uint>(a * (128 + b) / 128, 255)
-template <typename T> void colorConvertMod(byte *dst, const byte *src, int pitch, int w, int h, const byte *srcPal, const byte *internalPal, Graphics::PixelFormat &f, const PaletteMod *mods, const byte *modMapping) {
- T *d = reinterpret_cast<T*>(dst);
- const T *p = reinterpret_cast<const T*>(internalPal);
- const byte *s1 = src;
- const byte *s2 = modMapping;
- pitch -= w;
-
- while (h--) {
- for (int i = 0; i < w; ++i) {
- byte m = *s2++;
- if (m) {
- const byte *col = &srcPal[*s1++ * 3];
- *d++ = f.RGBToColor(applyMod(col[0], mods[m].r), applyMod(col[1], mods[m].g), applyMod(col[2], mods[m].b));
- } else {
- *d++ = p[*s1++];
- }
- }
- s1 += pitch;
- s2 += pitch;
- }
-}
-#undef applyMod
-
-void GfxDefaultDriver::initScreen(const Graphics::PixelFormat *srcRGBFormat) {
- Graphics::PixelFormat format8bt(Graphics::PixelFormat::createFormatCLUT8());
- initGraphics(_screenW, _screenH, srcRGBFormat ? srcRGBFormat : (_requestRGBMode ? nullptr : &format8bt));
- _format = g_system->getScreenFormat();
-
- int srcPixelSize = srcRGBFormat ? _format.bytesPerPixel : 1;
- if (srcPixelSize != _srcPixelSize || _pixelSize != _format.bytesPerPixel) {
- delete[] _compositeBuffer;
- delete[] _currentBitmap;
- delete[] _internalPalette;
- delete[] _currentPalette;
- _compositeBuffer = _currentBitmap = _internalPalette = _currentPalette = nullptr;
- }
-
- _pixelSize = _format.bytesPerPixel;
- _srcPixelSize = srcPixelSize;
-
- if (_requestRGBMode && _pixelSize == 1)
- warning("GfxDefaultDriver::initScreen(): RGB rendering not available in this ScummVM build");
-
- if (_pixelSize != _srcPixelSize) {
- uint32 bufferSize = _screenW * _screenH * _pixelSize;
- _compositeBuffer = new byte[bufferSize]();
- assert(_compositeBuffer);
- }
-
- // Not needed for SCI0, except for rgb rendering. Unfortunately, SCI_VERSION_01
- // does need it and we can't tell the version from the number of colors there.
- // That's why we have the _alwaysCreateBmpBuffer flag...
- if (_alwaysCreateBmpBuffer || _numColors > 16 || _pixelSize > 1) {
- _currentBitmap = new byte[_virtualW * _virtualH * _srcPixelSize]();
- assert(_currentBitmap);
- }
-
- if (_numColors > 16 || _pixelSize > 1) {
- // Not needed for SCI0, except for rgb rendering
- _currentPalette = new byte[256 * 3]();
- assert(_currentPalette);
- if (_pixelSize != _srcPixelSize) {
- _internalPalette = new byte[256 * _pixelSize]();
- assert(_internalPalette);
- }
- }
-
- static const ColorConvProc colorConvProcs[] = {
- &colorConvert<byte>,
- &colorConvert<uint16>,
- &colorConvert<uint32>
- };
- assert((_pixelSize >> 1) < ARRAYSIZE(colorConvProcs));
- _colorConv = colorConvProcs[_pixelSize >> 1];
-
- static const ColorConvModProc colorConvModProcs[] = {
- &colorConvertMod<byte>,
- &colorConvertMod<uint16>,
- &colorConvertMod<uint32>
- };
- assert((_pixelSize >> 1) < ARRAYSIZE(colorConvModProcs));
- _colorConvMod = colorConvModProcs[_pixelSize >> 1];
-
- _ready = true;
-}
-
-void GfxDefaultDriver::setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod *palMods, const byte *palModMapping) {
- GFXDRV_ASSERT_READY;
- if (_pixelSize > 1) {
- updatePalette(colors, start, num);
- if (update)
- copyRectToScreen(_currentBitmap, 0, 0, _virtualW, 0, 0, _virtualW, _virtualH, palMods, palModMapping);
- if (_cursorUsesScreenPalette)
- CursorMan.replaceCursorPalette(_currentPalette, 0, 256);
- } else {
- g_system->getPaletteManager()->setPalette(colors, start, num);
- }
-}
-
-void updateBitmapBuffer(byte *dst, int dstPitch, const byte *src, int srcPitch, int x, int y, int w, int h) {
- if (!dst)
- return;
-
- if (w == srcPitch && w == dstPitch) {
- memcpy(dst + y * w, src, w * h);
- } else {
- const byte *s = src;
- byte *d = dst + y * dstPitch + x;
- for (int i = 0; i < h; ++i) {
- memcpy(d, s, w);
- s += srcPitch;
- d += dstPitch;
- }
- }
-}
-
-void GfxDefaultDriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) {
- GFXDRV_ASSERT_READY;
- assert (h >= 0 && w >= 0);
-
- src += (srcY * pitch + srcX * _srcPixelSize);
- if (src != _currentBitmap)
- updateBitmapBuffer(_currentBitmap, _screenW * _srcPixelSize, src, pitch, destX * _srcPixelSize, destY, w * _srcPixelSize, h);
-
- if (_pixelSize != _srcPixelSize) {
- generateOutput(_compositeBuffer, src, pitch, w, h, palMods, palModMapping + destY * pitch + destX);
- src = _compositeBuffer;
- pitch = w * _pixelSize;
- }
-
- g_system->copyRectToScreen(src, pitch, destX, destY, w, h);
-}
-
-void GfxDefaultDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
- GFXDRV_ASSERT_READY;
- CursorMan.replaceCursor(cursor, w, h, hotspotX, hotspotY, keycolor);
- if (_pixelSize > 1 && _currentPalette != nullptr)
- CursorMan.replaceCursorPalette(_currentPalette, 0, 256);
-}
-
-void GfxDefaultDriver::replaceMacCursor(const Graphics::Cursor*) {
- // This is not needed for any non-Mac version of games at all)
- error("GfxDefaultDriver::replaceMacCursor(Graphics::Cursor*): Not implemented");
-}
-
-void GfxDefaultDriver::copyCurrentBitmap(byte *dest, uint32 size) const {
- GFXDRV_ASSERT_READY;
- assert(dest);
- assert(size <= (uint32)(_screenW * _screenH));
-
- // SCI 0 should not make calls to this method (except when using palette mods), but we have to know if it does...
- if (!_currentBitmap)
- error("GfxDefaultDriver::copyCurrentBitmap(): unexpected call");
-
- // I have changed the implementation a bit from what the engine did before. For non-rgb rendering
- // it would call OSystem::lockScreen() and then memcpy the data from there (which avoided the need
- // for the extra bitmap buffer). However, OSystem::lockScreen() is meant more as an update method
- // for the screen, the call to OSystem::unlockScreen() will turn the whole screen dirty (to be
- // updated on the next OSysten::updateScreen() call. This is not what we need here, so I rather use
- // the extra bitmap buffer (which is required for rgb rendering anyway).
- memcpy(dest, _currentBitmap, size);
-}
-
-void GfxDefaultDriver::copyCurrentPalette(byte *dest, int start, int num) const {
- GFXDRV_ASSERT_READY;
-
- if (_pixelSize == 1) {
- GfxDriver::copyCurrentPalette(dest, start, num);
- return;
- }
-
- assert(dest);
- assert(_currentPalette);
- assert(start + num <= 256);
- memcpy(dest + start * 3, _currentPalette + start * 3, num * 3);
-}
-
-void GfxDefaultDriver::drawTextFontGlyph(const byte*, int, int, int, int, int, int, const PaletteMod*, const byte*) {
- // This is only needed for scaling drivers with unscaled hires fonts.
- error("GfxDefaultDriver::drawTextFontGlyph(): Not implemented");
-}
-
-template <typename T> void updateRGBPalette(byte *dest, const byte *src, uint start, uint num, Graphics::PixelFormat &f) {
- T *dst = &reinterpret_cast<T*>(dest)[start];
- for (uint i = 0; i < num; ++i) {
- *dst++ = f.RGBToColor(src[0], src[1], src[2]);
- src += 3;
- }
-}
-
-void GfxDefaultDriver::updatePalette(const byte *colors, uint start, uint num) {
- memcpy(_currentPalette + start * 3, colors, num * 3);
- if (_pixelSize == 4)
- updateRGBPalette<uint32>(_internalPalette, colors, start, num, _format);
- else if (_pixelSize == 2)
- updateRGBPalette<uint16>(_internalPalette, colors, start, num, _format);
- else
- error("GfxDefaultDriver::updatePalette(): Unsupported pixel size %d", _pixelSize);
-}
-
-void GfxDefaultDriver::generateOutput(byte *dst, const byte *src, int pitch, int w, int h, const PaletteMod *palMods, const byte *palModMapping) {
- if (palMods && palModMapping)
- _colorConvMod(dst, src, pitch, w, h, _currentPalette, _internalPalette, _format, palMods, palModMapping);
- else
- _colorConv(dst, src, pitch, w, h, _internalPalette);
-}
-
-SCI0_DOSPreVGADriver::SCI0_DOSPreVGADriver(int numColors, int screenW, int screenH, bool rgbRendering) :
- GfxDriver(screenW, screenH, numColors), _requestRGBMode(rgbRendering), _colors(nullptr), _compositeBuffer(nullptr), _internalPalette(nullptr) {
-}
-
-SCI0_DOSPreVGADriver::~SCI0_DOSPreVGADriver() {
- delete[] _compositeBuffer;
- delete[] _internalPalette;
-}
-
-void SCI0_DOSPreVGADriver::assignPalette(const byte *colors) {
- _colors = colors;
-}
-
-void SCI0_DOSPreVGADriver::initScreen(const Graphics::PixelFormat*) {
- Graphics::PixelFormat format(Graphics::PixelFormat::createFormatCLUT8());
- initGraphics(_screenW, _screenH, _requestRGBMode ? nullptr : &format);
- format = g_system->getScreenFormat();
- _pixelSize = format.bytesPerPixel;
-
- if (_requestRGBMode && _pixelSize == 1)
- warning("SCI0_DOSPreVGADriver::initScreen(): RGB rendering not available in this ScummVM build");
-
- delete[] _compositeBuffer;
- delete[] _internalPalette;
- _internalPalette = nullptr;
- _compositeBuffer = nullptr;
-
- assert(_colors);
- if (_pixelSize == 1) {
- g_system->getPaletteManager()->setPalette(_colors, 0, _numColors);
- } else {
- byte *rgbpal = new byte[_numColors * _pixelSize]();
- assert(rgbpal);
-
- if (_pixelSize == 2)
- updateRGBPalette<uint16>(rgbpal, _colors, 0, _numColors, format);
- else if (_pixelSize == 4)
- updateRGBPalette<uint32>(rgbpal, _colors, 0, _numColors, format);
- else
- error("SCI0_DOSPreVGADriver::initScreen(): Unsupported screen format");
- _internalPalette = rgbpal;
- CursorMan.replaceCursorPalette(_colors, 0, _numColors);
- }
-
- _compositeBuffer = new byte[_screenW * _screenH * _pixelSize]();
- assert(_compositeBuffer);
-
- setupRenderProc();
-
- _ready = true;
-}
-
-void SCI0_DOSPreVGADriver::replaceMacCursor(const Graphics::Cursor*) {
- // This is not needed for SCI0 (and not for any PC version of games at all)
- error("SCI0_DOSPreVGADriver::replaceMacCursor(Graphics::Cursor*): Not implemented");
-}
-
-void SCI0_DOSPreVGADriver::copyCurrentBitmap(byte*, uint32) const {
- // This is not needed for SCI0
- error("SCI0_DOSPreVGADriver::copyCurrentBitmap(): Not implemented");
-}
-
-void SCI0_DOSPreVGADriver::copyCurrentPalette(byte *dest, int start, int num) const {
- GFXDRV_ASSERT_READY;
-
- if (_pixelSize == 1) {
- GfxDriver::copyCurrentPalette(dest, start, num);
- return;
- }
-
- assert(dest);
- memcpy(dest + start * 3, _colors + start * 3, MIN<int>(num, _numColors) * 3);
-}
-
-void SCI0_DOSPreVGADriver::drawTextFontGlyph(const byte*, int, int, int, int, int, int, const PaletteMod*, const byte*) {
- // This is only needed for scaling drivers with unscaled hires fonts.
- error("SCI0_DOSPreVGADriver::drawTextFontGlyph(): Not implemented");
-}
-
-SCI0_CGADriver::SCI0_CGADriver(bool emulateCGAModeOnEGACard, bool rgbRendering) : SCI0_DOSPreVGADriver(4, 320, 200, rgbRendering), _cgaPatterns(nullptr), _disableMode5(emulateCGAModeOnEGACard), _renderLine(nullptr) {
- static const byte cgaColors[48] = {
- /*
- // Canonical CGA palette
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0x00, 0xAA, 0xAA,
- 0xAA, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0xAA, 0x55, 0x00, 0xAA, 0xAA, 0xAA,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0x55, 0x55, 0xFF, 0xFF,
- 0xFF, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0xFF, 0xFF, 0x55, 0xFF, 0xFF, 0xFF
- */
- // Improved palette model taken from https://int10h.org/blog/2022/06/ibm-5153-color-true-cga-palette/
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x00, 0xC4, 0x00, 0x00, 0xC4, 0xC4,
- 0xC4, 0x00, 0x00, 0xC4, 0x00, 0xC4, 0xC4, 0x7E, 0x00, 0xC4, 0xC4, 0xC4,
- 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0xDC, 0x4E, 0xDC, 0x4E, 0x4E, 0xF3, 0xF3,
- 0xDC, 0x4E, 0x4E, 0xF3, 0x4E, 0xF3, 0xF3, 0xF3, 0x4E, 0xFF, 0xFF, 0xFF
- };
-
- static const byte modeColorMap[3][4] = {
- { 0, 2, 4, 6 },
- { 0, 3, 5, 7 },
- { 0, 3, 4, 7 }
- };
-
- Common::File drv;
- if (!drv.open(_driverFile))
- GFXDRV_ERR_OPEN(_driverFile);
-
- byte palIndex = 1;
- byte palIntensity = 1;
- byte mode = 4;
-
- byte colMap[4];
- memset(colMap, 0, sizeof(colMap));
-
- uint16 eprcOffs = 0;
-
- uint32 cmd = drv.readUint32LE();
- if ((cmd & 0xFF) == 0xE9)
- eprcOffs = ((cmd >> 8) & 0xFFFF) + 3;
-
- if (!eprcOffs || drv.readUint32LE() != 0x87654321 || !drv.skip(1) || !drv.seek(drv.readByte(), SEEK_CUR) || !drv.seek(drv.readByte(), SEEK_CUR))
- GFXDRV_ERR_VERSION(_driverFile);
-
- drv.skip(drv.readByte() == 0x90 ? 2 : 1);
-
- uint16 op1st = drv.readUint16LE();
- int op1len = drv.readUint16LE() - op1st;
-
- // sanity check
- assert(op1len > 0 && op1len < 0x100);
-
- drv.seek(op1st, SEEK_SET);
- byte *buf = new byte[op1len]();
- drv.read(buf, op1len);
-
- // Try figuring out the correct settings...
- for (int i = 0; i < op1len - 7; ++i) {
- uint32 cfg = READ_BE_UINT32(buf + i);
- cmd = READ_BE_UINT32(buf + 4 + i);
- if ((cmd >> 16) == 0xCD10 && (cfg & 0xff00ff) == 0xB80000) {
- mode = (cfg >> 8) & 0xff;
- } else if (cmd == 0xB40BCD10) {
- if (cfg >> 8 == 0x00B701B3) {
- palIndex = cfg & 1;
- palIntensity = (cfg >> 4) & 1;
- } else if (cfg >> 8 == 0x00B700B3) {
- colMap[0] = (cfg & 0x0f) + ((cfg & 0x10) >> 1);
- }
- }
- }
-
- delete[] buf;
-
- assert(palIndex <= 1);
- assert(palIntensity <= 1);
-
- for (int i = 1; i < 4; ++i)
- colMap[i] = modeColorMap[(!_disableMode5 && mode == 5) ? 2 : palIndex][i] + (palIntensity << 3);
-
- memset (_palette, 0, sizeof(_palette));
- for (int i = 0; i < 4; ++i) {
- for (int ii = 0; ii < 3; ++ii)
- _palette[i * 3 + ii] = cgaColors[colMap[i] * 3 + ii];
- }
-
- assignPalette(_palette);
-
- _cgaPatterns = new uint16[256]();
- // The pattern map is always located right before the driver entry point proc.
- drv.seek(eprcOffs - 512, SEEK_SET);
- for (int i = 0; i < 256; ++i)
- _cgaPatterns[i] = drv.readUint16LE();
-
- drv.close();
-}
-
-SCI0_CGADriver::~SCI0_CGADriver() {
- delete[] _cgaPatterns;
-}
-
-void SCI0_CGADriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod*, const byte*) {
- GFXDRV_ASSERT_READY;
-
- byte diff = srcX & 1;
- srcX &= ~1;
- destX &= ~1;
- w = (w + diff + 1) & ~1;
-
- src += (srcY * pitch + srcX);
-
- byte *dst = _compositeBuffer;
- int ty = destY;
-
- for (int i = 0; i < h; ++i) {
- _renderLine(dst, src, w, srcX & 3, ++ty, _cgaPatterns, _internalPalette);
- src += pitch;
- }
-
- g_system->copyRectToScreen(_compositeBuffer, w * _pixelSize, destX, destY, w, h);
-}
-
-void SCI0_CGADriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
- GFXDRV_ASSERT_READY;
- // Instead of implementing the original cursor rendering code, we rely on the 8 bit cursor
- // that has already been generated by the engine. We simply convert the colors as needed...
- assert(keycolor == 1);
- const byte *s = reinterpret_cast<const byte*>(cursor);
- byte *d = _compositeBuffer;
- for (uint i = w * h; i; --i)
- *d++ = *s++ & 3;
-
- CursorMan.replaceCursor(_compositeBuffer, w, h, hotspotX, hotspotY, keycolor);
-}
-
-
-template <typename T> void cgaRenderLine(byte *&dst, const byte *src, int w, int tx, int ty, const uint16 *patterns, const byte *pal) {
- T *d = reinterpret_cast<T*>(dst);
- const T *p = reinterpret_cast<const T*>(pal);
- w >>= 1;
-
- for (int i = 0; i < w; ++i) {
- uint16 pattern = patterns[((src[0] & 0x0f) << 4) | (src[1] & 0x0f)];
- src += 2;
- byte sh = (ty & 3) << 1;
- byte lo = ((pattern & 0xff) >> sh) | ((pattern & 0xff) << (8 - sh));
- byte hi = (pattern >> (8 + sh)) | ((pattern >> 8) << (8 - sh));
- if (sizeof(T) == 1) {
- *d++ = (lo >> (6 - (tx << 1))) & 3;
- *d++ = (hi >> (4 - (tx << 1))) & 3;
- } else {
- *d++ = p[(lo >> (6 - (tx << 1))) & 3];
- *d++ = p[(hi >> (4 - (tx << 1))) & 3];
- }
- tx ^= 2;
- }
-
- dst = reinterpret_cast<byte*>(d);
-}
-
-void SCI0_CGADriver::setupRenderProc() {
- static const LineProc lineProcs[] = {
- &cgaRenderLine<byte>,
- &cgaRenderLine<uint16>,
- &cgaRenderLine<uint32>
- };
-
- assert((_pixelSize >> 1) < ARRAYSIZE(lineProcs));
- _renderLine = lineProcs[_pixelSize >> 1];
-}
-
-const char *SCI0_CGADriver::_driverFile = "CGA320C.DRV";
-
-const byte *monochrInit(const char *drvFile, bool &earlyVersion) {
- Common::File drv;
- if (!drv.open(drvFile))
- return nullptr;
-
- uint16 eprcOffs = 0;
-
- uint32 cmd = drv.readUint32LE();
- if ((cmd & 0xFF) == 0xE9)
- eprcOffs = ((cmd >> 8) & 0xFFFF) + 3;
-
- if (!eprcOffs || drv.readUint32LE() != 0x87654321 || !drv.skip(1) || !drv.seek(drv.readByte(), SEEK_CUR) || !drv.seek(drv.readByte(), SEEK_CUR))
- GFXDRV_ERR_VERSION(drv.getName());
-
- // This is a safe assumption, as the early version pattern map is 4 times the size of the later one.
- earlyVersion = (eprcOffs > 0x500);
- uint16 size = earlyVersion ? 512 : 128;
-
- byte *result = new byte[size];
- // For CGA, the pattern map is always located before the entry point dispatcher proc.
- drv.seek(eprcOffs - size, SEEK_SET);
- drv.read(result, size);
-
- // For Hercules there are some extra vars in between, all with initial values
- // of zero. The last entry of the pattern map is definitely never zero...
- int xtraOffs = 0;
- while (result[size - 1 - xtraOffs] == 0)
- ++xtraOffs;
- if (xtraOffs != 0) {
- drv.seek(eprcOffs - size - xtraOffs, SEEK_SET);
- drv.read(result, size);
- }
-
- drv.close();
-
- if (earlyVersion) {
- uint16 *r = reinterpret_cast<uint16*>(result);
- for (int i = 0; i < 256; ++i)
- r[i] = FROM_LE_16(r[i]);
- }
-
- return result;
-}
-
-SCI0_CGABWDriver::SCI0_CGABWDriver(uint32 monochromeColor, bool rgbRendering) : SCI0_DOSPreVGADriver(2, 640, 400, rgbRendering), _monochromePatterns(nullptr), _earlyVersion(false), _renderLine(nullptr) {
- _monochromePalette[0] = _monochromePalette[1] = _monochromePalette[2] = 0;
- _monochromePalette[3] = (monochromeColor >> 16) & 0xff;
- _monochromePalette[4] = (monochromeColor >> 8) & 0xff;
- _monochromePalette[5] = monochromeColor & 0xff;
- assignPalette(_monochromePalette);
-
- if (!(_monochromePatterns = monochrInit(_driverFiles[0], _earlyVersion)) && !(_monochromePatterns = monochrInit(_driverFiles[1], _earlyVersion)))
- error("Failed to open '%s' or '%s'", _driverFiles[0], _driverFiles[1]);
-}
-
-SCI0_CGABWDriver::~SCI0_CGABWDriver() {
- delete[] _monochromePatterns;
-}
-
-void SCI0_CGABWDriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod*, const byte*) {
- GFXDRV_ASSERT_READY;
-
- byte *dst = _compositeBuffer;
- int ty = destY & 7;
-
- if (_earlyVersion) {
- ++ty;
- byte diff = srcX & 1;
- srcX &= ~1;
- destX &= ~1;
- w = (w + diff + 1) & ~1;
- }
-
- src += (srcY * pitch + srcX);
-
- for (int i = 0; i < h; ++i) {
- _renderLine(dst, src, w, srcX & 3, ty, _monochromePatterns, _internalPalette);
- ty = (ty + 1) & 7;
- src += pitch;
- }
-
- g_system->copyRectToScreen(_compositeBuffer, (w << 1) * _pixelSize, destX << 1, destY << 1, w << 1, h << 1);
-}
-
-void SCI0_CGABWDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
- GFXDRV_ASSERT_READY;
- // Instead of implementing the original cursor rendering code, we rely on the 8 bit cursor that
- // has already been generated by the engine. We simply convert the colors as needed and scale the cursor...
- assert(keycolor == 1);
- keycolor = 0x0f;
- w <<= 1;
- const byte *s = reinterpret_cast<const byte*>(cursor);
- byte *d0 = _compositeBuffer;
- byte *d1 = _compositeBuffer + w;
-
- for (uint i = 0; i < h; ++i) {
- for (uint ii = 0; ii < w; ++ii) {
- *d0++ = *d1++ = *s ? (*s ^ 0x0e) : 0;
- if (ii & 1)
- ++s;
- }
- d0 += w;
- d1 += w;
- }
-
- CursorMan.replaceCursor(_compositeBuffer, w, h << 1, hotspotX << 1, hotspotY << 1, keycolor);
-}
-
-Common::Point SCI0_CGABWDriver::getMousePos() const {
- Common::Point res = GfxDriver::getMousePos();
- res.x >>= 1;
- res.y >>= 1;
- return res;
-}
-
-void SCI0_CGABWDriver::setMousePos(const Common::Point &pos) const {
- g_system->warpMouse(pos.x << 1, pos.y << 1);
-}
-
-void SCI0_CGABWDriver::setShakePos(int shakeXOffset, int shakeYOffset) const {
- g_system->setShakePos(shakeXOffset << 1, shakeYOffset << 1);
-}
-
-void SCI0_CGABWDriver::clearRect(const Common::Rect &r) const {
- Common::Rect r2(r.left << 1, r.top << 1, r.right << 1, r.bottom << 1);
- GfxDriver::clearRect(r2);
-}
-
-Common::Point SCI0_CGABWDriver::getRealCoords(Common::Point &pos) const {
- return Common::Point(pos.x << 1, pos.y << 1);
-}
-
-template <typename T> void cgabwRenderLine_v1(byte *&dst, const byte *src, int w, int tx, int ty, const byte *patterns, const byte *pal) {
- const T *p = reinterpret_cast<const T*>(pal);
- const uint16 *patterns16 = reinterpret_cast<const uint16*>(patterns);
- T *d1 = reinterpret_cast<T*>(dst);
- T *d2 = d1 + (w << 1);
- w >>= 1;
-
- for (int i = 0; i < w; ++i) {
- uint16 pt = patterns16[((src[0] & 0x0f) << 4) | (src[1] & 0x0f)];
- src += 2;
- byte sh = (ty & 3) << 1;
- byte lo = ((pt & 0xff) >> sh) | ((pt & 0xff) << (8 - sh));
- byte hi = (pt >> (8 + sh)) | ((pt >> 8) << (8 - sh));
- if (sizeof(T) == 1) {
- *d1++ = *d2++ = ((lo >> (6 - (tx << 1))) >> 1) & 1;
- *d1++ = *d2++ = (lo >> (6 - (tx << 1))) & 1;
- *d1++ = *d2++ = ((hi >> (4 - (tx << 1))) >> 1) & 1;
- *d1++ = *d2++ = (hi >> (4 - (tx << 1))) & 1;
- } else {
- *d1++ = *d2++ = p[((lo >> (6 - (tx << 1))) >> 1) & 1];
- *d1++ = *d2++ = p[(lo >> (6 - (tx << 1))) & 1];
- *d1++ = *d2++ = p[((hi >> (4 - (tx << 1))) >> 1) & 1];
- *d1++ = *d2++ = p[(hi >> (4 - (tx << 1))) & 1];
- }
- tx ^= 2;
- }
-
- dst = reinterpret_cast<byte*>(d2);
-}
-
-template <typename T> void cgabwRenderLine_v2(byte *&dst, const byte *src, int w, int tx, int ty, const byte *patterns, const byte *pal) {
- const T *p = reinterpret_cast<const T*>(pal);
- T *d1 = reinterpret_cast<T*>(dst);
- T *d2 = d1 + (w << 1);
-
- for (int i = 0; i < w; ++i) {
- byte pt = patterns[((*src++ & 0x0f) << 3) + ty] >> (6 - (tx << 1));
- if (sizeof(T) == 1) {
- *d1++ = *d2++ = (pt >> 1) & 1;
- *d1++ = *d2++ = pt & 1;
- } else {
- *d1++ = *d2++ = p[(pt >> 1) & 1];
- *d1++ = *d2++ = p[pt & 1];
- }
- tx = (tx + 1) & 3;
- }
-
- dst = reinterpret_cast<byte*>(d2);
-}
-
-void SCI0_CGABWDriver::setupRenderProc() {
- static const LineProc lineProcs[] = {
- &cgabwRenderLine_v1<byte>,
- &cgabwRenderLine_v1<uint16>,
- &cgabwRenderLine_v1<uint32>,
- &cgabwRenderLine_v2<byte>,
- &cgabwRenderLine_v2<uint16>,
- &cgabwRenderLine_v2<uint32>
- };
-
- int t = _pixelSize >> 1;
- if (!_earlyVersion)
- t += 3;
-
- assert(t < ARRAYSIZE(lineProcs));
- _renderLine = lineProcs[t];
-}
-
-const char *SCI0_CGABWDriver::_driverFiles[2] = { "CGA320BW.DRV", "CGA320M.DRV" };
-
-SCI0_HerculesDriver::SCI0_HerculesDriver(uint32 monochromeColor, bool rgbRendering, bool cropImage) : SCI0_DOSPreVGADriver(2, cropImage ? 640 : 720, cropImage ? 300 : 350, rgbRendering),
- _centerX(cropImage ? 0 : 40), _centerY(cropImage ? 0 : 25), _monochromePatterns(nullptr), _renderLine(nullptr) {
- _monochromePalette[0] = _monochromePalette[1] = _monochromePalette[2] = 0;
- _monochromePalette[3] = (monochromeColor >> 16) & 0xff;
- _monochromePalette[4] = (monochromeColor >> 8) & 0xff;
- _monochromePalette[5] = monochromeColor & 0xff;
- assignPalette(_monochromePalette);
- bool unused = false;
-
- if (!(_monochromePatterns = monochrInit(_driverFile, unused)))
- GFXDRV_ERR_OPEN(_driverFile);
-}
-
-SCI0_HerculesDriver::~SCI0_HerculesDriver() {
- delete[] _monochromePatterns;
-}
-
-void SCI0_HerculesDriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod*, const byte*) {
- GFXDRV_ASSERT_READY;
-
- byte *dst = _compositeBuffer;
- byte sw = destY & 1;
- src += (srcY * pitch + srcX);
- destY = (destY & ~1) * 3 / 2 + (destY & 1);
- int ty = destY & 7;
- int rh = 0;
-
- for (int i = 0; i < h; ++i) {
- const byte *src2 = src;
- _renderLine(dst, src2, w, srcX & 3, ty, _monochromePatterns, _internalPalette);
- ty = (ty + 1) & 7;
- ++rh;
-
- if (sw & 1)
- sw ^= 2;
-
- if (sw != 3) {
- src += pitch;
- sw ^= 1;
- } else {
- --i;
- }
- }
-
- g_system->copyRectToScreen(_compositeBuffer, (w << 1) * _pixelSize, (destX << 1) + _centerX, destY + _centerY, w << 1, rh);
-}
-
-void SCI0_HerculesDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
- GFXDRV_ASSERT_READY;
- // Instead of implementing the original cursor rendering code, we rely on the 8 bit cursor that
- // has already been generated by the engine. We simply convert the colors as needed and scale the cursor...
- assert(keycolor == 1);
- keycolor = 0x0f;
- int alt = 0;
- const byte *s = reinterpret_cast<const byte *>(cursor);
- byte *d = _compositeBuffer;
-
- for (uint i = 0; i < h; ++i) {
- for (uint ii = 0; ii < (w << 1); ++ii) {
- *d++ = *s ? (*s ^ 0x0e) : 0;
- if (ii & 1)
- ++s;
- }
- if (i & 1) {
- alt ^= 1;
- if (alt) {
- s -= w;
- --i;
- }
- }
- }
-
- CursorMan.replaceCursor(_compositeBuffer, w << 1, (h & ~1) * 3 / 2 + (h & 1), hotspotX << 1, (hotspotY & ~1) * 3 / 2 + (hotspotY & 1), keycolor);
-}
-
-Common::Point SCI0_HerculesDriver::getMousePos() const {
- Common::Point res = GfxDriver::getMousePos();
- res.x = CLIP<int>(res.x - _centerX, 0, 639) >> 1;
- res.y = (CLIP<int>(res.y - _centerY, 0, 299) * 2 + 1) / 3;
- return res;
-}
-
-void SCI0_HerculesDriver::setMousePos(const Common::Point &pos) const {
- g_system->warpMouse((pos.x << 1) + _centerX, (pos.y & ~1) * 3 / 2 + (pos.y & 1) + _centerY);
-}
-
-void SCI0_HerculesDriver::setShakePos(int shakeXOffset, int shakeYOffset) const {
- g_system->setShakePos(shakeXOffset << 1, (shakeYOffset & ~1) * 3 / 2 + (shakeYOffset & 1));
-}
-
-void SCI0_HerculesDriver::clearRect(const Common::Rect &r) const {
- Common::Rect r2((r.left << 1) + _centerX, (r.top & ~1) * 3 / 2 + (r.top & 1) + _centerY, (r.right << 1) + 40, (r.bottom & ~1) * 3 / 2 + (r.bottom & 1) + _centerY);
- GfxDriver::clearRect(r2);
-}
-
-Common::Point SCI0_HerculesDriver::getRealCoords(Common::Point &pos) const {
- return Common::Point((pos.x << 1) + _centerX, (pos.y & ~1) * 3 / 2 + (pos.y & 1) + _centerY);
-}
-
-template <typename T> void herculesRenderLine(byte *&dst, const byte *src, int w, int tx, int ty, const byte *patterns, const byte *pal) {
- T *d = reinterpret_cast<T*>(dst);
- const T *p = reinterpret_cast<const T*>(pal);
-
- for (int i = 0; i < w; ++i) {
- byte pt = patterns[((*src++ & 0x0f) << 3) + ty] >> (6 - (tx << 1));
- if (sizeof(T) == 1) {
- *d++ = (pt >> 1) & 1;
- *d++ = pt & 1;
- } else {
- *d++ = p[(pt >> 1) & 1];
- *d++ = p[pt & 1];
- }
- tx = (tx + 1) & 3;
- }
-
- dst = reinterpret_cast<byte*>(d);
-}
-
-void SCI0_HerculesDriver::setupRenderProc() {
- static const LineProc lineProcs[] = {
- &herculesRenderLine<byte>,
- &herculesRenderLine<uint16>,
- &herculesRenderLine<uint32>
- };
-
- assert((_pixelSize >> 1) < ARRAYSIZE(lineProcs));
- _renderLine = lineProcs[_pixelSize >> 1];
-}
-
-const char *SCI0_HerculesDriver::_driverFile = "HERCMONO.DRV";
-
-
-SCI1_VGAGreyScaleDriver::SCI1_VGAGreyScaleDriver(bool rgbRendering) : GfxDefaultDriver(320, 200, false, rgbRendering), _greyScalePalette(nullptr) {
- _greyScalePalette = new byte[_numColors * 3]();
-}
-
-SCI1_VGAGreyScaleDriver::~SCI1_VGAGreyScaleDriver() {
- delete[] _greyScalePalette;
-}
-
-void SCI1_VGAGreyScaleDriver::setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod *palMods, const byte *palModMapping) {
- GFXDRV_ASSERT_READY;
- byte *d = _greyScalePalette;
- for (uint i = 0; i < num; ++i) {
- // In the driver files I inspected there were never any other color distributions than this.
- // So I guess it is safe to hardcode that instead of loading it from the driver file.
- d[0] = d[1] = d[2] = (colors[0] * 77 + colors[1] * 150 + colors[2] * 28) >> 8;
- colors += 3;
- d += 3;
- }
-
- GfxDefaultDriver::setPalette(_greyScalePalette, start, num, update, palMods, palModMapping);
-}
-
-const char *SCI1_VGAGreyScaleDriver::_driverFile = "VGA320BW.DRV";
-
-SCI1_EGADriver::SCI1_EGADriver(bool rgbRendering) : GfxDriver(320, 200, 256), _requestRGBMode(rgbRendering), _egaColorPatterns(nullptr), _egaMatchTable(nullptr),
- _currentBitmap(nullptr), _compositeBuffer(nullptr), _currentPalette(nullptr), _internalPalette(nullptr), _colAdjust(0), _renderLine(nullptr), _vScaleMult(2), _vScaleDiv(1) {
- static const byte egaColors[48] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0x00, 0xAA, 0xAA,
- 0xAA, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0xAA, 0x55, 0x00, 0xAA, 0xAA, 0xAA,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0x55, 0x55, 0xFF, 0xFF,
- 0xFF, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0xFF, 0xFF, 0x55, 0xFF, 0xFF, 0xFF
- };
- _convPalette = egaColors;
-}
-
-SCI1_EGADriver::~SCI1_EGADriver() {
- delete[] _egaMatchTable;
- delete[] _egaColorPatterns;
- delete[] _compositeBuffer;
- delete[] _currentBitmap;
- delete[] _currentPalette;
- delete[] _internalPalette;
-}
-
-template <typename T> void ega640RenderLine(byte *&dst, const byte *src, int w, const byte *patterns, const byte *pal, bool) {
- const T *p = reinterpret_cast<const T*>(pal);
- T *d1 = reinterpret_cast<T*>(dst);
- T *d2 = d1 + (w << 1);
-
- for (int i = 0; i < w; ++i) {
- byte pt = patterns[*src++];
- if (sizeof(T) == 1) {
- *d1++ = *d2++ = pt >> 4;
- *d1++ = *d2++ = pt & 0x0f;
- } else {
- *d1++ = *d2++ = p[pt >> 4];
- *d1++ = *d2++ = p[pt & 0x0f];
- }
- }
- dst = reinterpret_cast<byte*>(d2);
-}
-
-void SCI1_EGADriver::initScreen(const Graphics::PixelFormat*) {
- if (!_ready)
- loadData();
-
- Graphics::PixelFormat format(Graphics::PixelFormat::createFormatCLUT8());
- initGraphics(_screenW << 1, _screenH * _vScaleMult / _vScaleDiv, _requestRGBMode ? nullptr : &format);
- format = g_system->getScreenFormat();
- _pixelSize = format.bytesPerPixel;
-
- if (_requestRGBMode && _pixelSize == 1)
- warning("SCI1_EGADriver::initScreen(): RGB rendering not available in this ScummVM build");
-
- delete[] _egaColorPatterns;
- delete[] _compositeBuffer;
- delete[] _currentBitmap;
- delete[] _currentPalette;
- delete[] _internalPalette;
- _internalPalette = nullptr;
- _egaColorPatterns = _compositeBuffer = _currentBitmap = _currentPalette = nullptr;
-
- if (_pixelSize == 1) {
- g_system->getPaletteManager()->setPalette(_convPalette, 0, 16);
- } else {
- byte *rgbpal = new byte[_numColors * _pixelSize]();
- assert(rgbpal);
-
- if (_pixelSize == 2)
- updateRGBPalette<uint16>(rgbpal, _convPalette, 0, 16, format);
- else if (_pixelSize == 4)
- updateRGBPalette<uint32>(rgbpal, _convPalette, 0, 16, format);
- else
- error("SCI1_EGADriver::initScreen(): Unsupported screen format");
- _internalPalette = rgbpal;
- CursorMan.replaceCursorPalette(_convPalette, 0, 16);
- }
-
- _compositeBuffer = new byte[(_screenW << 1) * (_screenH * _vScaleMult / _vScaleDiv) * _pixelSize]();
- assert(_compositeBuffer);
- _currentBitmap = new byte[_screenW * _screenH]();
- assert(_currentBitmap);
- _currentPalette = new byte[256 * 3]();
- assert(_currentPalette);
- _egaColorPatterns = new byte[256]();
- assert(_egaColorPatterns);
-
- static const LineProc lineProcs[] = {
- &ega640RenderLine<byte>,
- &ega640RenderLine<uint16>,
- &ega640RenderLine<uint32>
- };
-
- assert((_pixelSize >> 1) < ARRAYSIZE(lineProcs));
- _renderLine = lineProcs[_pixelSize >> 1];
-
- _ready = true;
-}
-
-void SCI1_EGADriver::setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod*, const byte*) {
- GFXDRV_ASSERT_READY;
- memcpy(_currentPalette + start * 3, colors, num * 3);
- byte *d = &_egaColorPatterns[start];
- for (uint i = 0; i < num; ++i) {
- *d++ = _egaMatchTable[((MIN<byte>((colors[0] >> 2) + _colAdjust, 63) & 0x38) << 3) | (MIN<byte>((colors[1] >> 2) + _colAdjust, 63) & 0x38) | (MIN<byte>((colors[2] >> 2) + _colAdjust, 63) >> 3)];
- colors += 3;
- }
- if (update)
- copyRectToScreen(_currentBitmap, 0, 0, _screenW, 0, 0, _screenW, _screenH, nullptr, nullptr);
-}
-
-void SCI1_EGADriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod*, const byte*) {
- GFXDRV_ASSERT_READY;
- assert (h >= 0 && w >= 0);
-
- src += (srcY * pitch + srcX);
-
- if (src != _currentBitmap)
- updateBitmapBuffer(_currentBitmap, _screenW, src, pitch, destX, destY, w, h);
-
- uint16 realWidth, realHeight;
- renderBitmap(_compositeBuffer, src, pitch, destY, w, h, _egaColorPatterns, _internalPalette, realWidth, realHeight);
-
- Common::Point pos(destX, destY);
- pos = getRealCoords(pos);
-
- g_system->copyRectToScreen(_compositeBuffer, realWidth * _pixelSize, pos.x, pos.y, realWidth, realHeight);
-}
-
-void SCI1_EGADriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
- GFXDRV_ASSERT_READY;
- const byte *s = reinterpret_cast<const byte*>(cursor);
- int dstPitch = (w << 1);
- byte *d1 = _compositeBuffer;
- byte *d2 = _compositeBuffer + dstPitch;
- uint32 newKeyColor = 0xFF;
-
- for (uint i = 0; i < h; ++i) {
- for (uint ii = 0; ii < w; ++ii) {
- byte col = *s++;
- if (col == keycolor) {
- *d1++ = *d2++ = newKeyColor;
- *d1++ = *d2++ = newKeyColor;
- } else {
- byte pt = _egaColorPatterns[col];
- *d1++ = *d2++ = pt >> 4;
- *d1++ = *d2++ = pt & 0x0f;
- }
- }
- d1 += dstPitch;
- d2 += dstPitch;
- }
-
- CursorMan.replaceCursor(_compositeBuffer, w << 1, h << 1, hotspotX << 1, hotspotY << 1, newKeyColor);
-}
-
-void SCI1_EGADriver::copyCurrentBitmap(byte *dest, uint32 size) const {
- GFXDRV_ASSERT_READY;
- assert(dest);
- assert(size <= (uint32)(_screenW * _screenH));
- memcpy(dest, _currentBitmap, size);
-}
-
-void SCI1_EGADriver::copyCurrentPalette(byte *dest, int start, int num) const {
- GFXDRV_ASSERT_READY;
- assert(dest);
- assert(start + num <= 256);
- memcpy(dest + start * 3, _currentPalette + start * 3, num * 3);
-}
-
-void SCI1_EGADriver::drawTextFontGlyph(const byte*, int, int, int, int, int, int, const PaletteMod*, const byte*) {
- // This is only needed for scaling drivers with unscaled hires fonts.
- error("SCI1_EGADriver::drawTextFontGlyph(): Not implemented");
-}
-
-Common::Point SCI1_EGADriver::getMousePos() const {
- Common::Point res = GfxDriver::getMousePos();
- res.x >>= 1;
- res.y = res.y * _vScaleDiv / _vScaleMult;
- return res;
-}
-
-void SCI1_EGADriver::setMousePos(const Common::Point &pos) const {
- g_system->warpMouse(pos.x << 1, pos.y * _vScaleMult / _vScaleDiv);
-}
-
-void SCI1_EGADriver::setShakePos(int shakeXOffset, int shakeYOffset) const {
- g_system->setShakePos(shakeXOffset << 1, shakeYOffset * _vScaleMult / _vScaleDiv);
-}
-
-void SCI1_EGADriver::clearRect(const Common::Rect &r) const {
- Common::Rect r2(r.left << 1, r.top * _vScaleMult / _vScaleDiv, r.right << 1, r.bottom * _vScaleMult / _vScaleDiv);
- GfxDriver::clearRect(r2);
-}
-
-Common::Point SCI1_EGADriver::getRealCoords(Common::Point &pos) const {
- return Common::Point(pos.x << 1, pos.y * _vScaleMult / _vScaleDiv);
-}
-
-void SCI1_EGADriver::loadData() {
- Common::File drv;
- if (!drv.open(_driverFile))
- GFXDRV_ERR_OPEN(_driverFile);
-
- uint16 eprcOffs = 0;
-
- uint32 cmd = drv.readUint32LE();
- if ((cmd & 0xFF) == 0xE9)
- eprcOffs = ((cmd >> 8) & 0xFFFF) + 3;
-
- if (!eprcOffs || drv.readUint32LE() != 0x87654321 || !drv.skip(1) || !drv.seek(drv.readByte(), SEEK_CUR) || !drv.seek(drv.readByte(), SEEK_CUR) || drv.readUint32LE() != 0xFEDCBA98 || !drv.skip(4))
- GFXDRV_ERR_VERSION(_driverFile);
-
- uint32 pos = (drv.pos() + 1) & ~1;
-
- drv.seek(pos);
- drv.seek(drv.readUint16LE());
- uint32 colResponse = drv.readUint32LE();
- _numColors = (colResponse >> 8) & 0xffff;
- if (_numColors < 16 || _numColors > 256 || (colResponse & 0xff0000ff) != 0xC30000B8)
- error("SCI1_EGADriver: Failed to retrieve color info from '%s'", _driverFile);
-
- drv.seek(pos + 20);
- drv.seek(drv.readUint16LE());
- byte *buff = new byte[128];
- drv.read(buff, 128);
-
- uint16 tableOffs = 0;
- for (int i = 0; i < 120 && !tableOffs; ++i) {
- uint32 c = READ_BE_UINT32(buff + i);
- if (c == 0x8BD82E8A) {
- if (buff[i + 4] == 0x87)
- tableOffs = READ_LE_UINT16(buff + i + 5);
- } else if (c == 0xD0E8D0E8) {
- for (int ii = 4; ii < 14; ++ii) {
- if (READ_BE_UINT16(buff + i + ii) == 0x83C0) {
- c = READ_BE_UINT32(buff + i + ii + 2);
- if ((c & 0xFFFFFF) == 0x83F83F)
- _colAdjust = c >> 24;
- }
- }
- }
- }
- delete[] buff;
-
- if (!tableOffs)
- error("SCI1_EGADriver: Failed to load color data from '%s'", _driverFile);
-
- drv.seek(tableOffs);
- byte *table = new byte[512]();
- drv.read(table, 512);
- _egaMatchTable = table;
-
- if (drv.readUint16LE() != 152 || drv.readUint16LE() != 160)
- GFXDRV_ERR_VERSION(_driverFile);
-
- drv.close();
-}
-
-void SCI1_EGADriver::renderBitmap(byte *dst, const byte *src, int pitch, int, int w, int h, const byte *patterns, const byte *palette, uint16 &realWidth, uint16 &realHeight) {
- for (int i = 0; i < h; ++i) {
- _renderLine(dst, src, w, patterns, palette, 0);
- src += pitch;
- }
- realWidth = w << 1;
- realHeight = h << 1;
-}
-
-const char *SCI1_EGADriver::_driverFile = "EGA640.DRV";
-
-template <typename T> void scale2x(byte *dst, const byte *src, int pitch, int w, int h) {
- const T *s = reinterpret_cast<const T*>(src);
- int dstPitch = pitch << 1;
- T *d1 = reinterpret_cast<T*>(dst);
- T *d2 = d1 + dstPitch;
- pitch -= w;
- dstPitch += (pitch << 1);
-
- while (h--) {
- for (int i = 0; i < w; ++i) {
- d1[0] = d1[1] = d2[0] = d2[1] = *s++;
- d1 += 2;
- d2 += 2;
- }
- s += pitch;
- d1 += dstPitch;
- d2 += dstPitch;
- }
-}
-
-UpscaledGfxDriver::UpscaledGfxDriver(int16 textAlignX, bool scaleCursor, bool rgbRendering) :
- UpscaledGfxDriver(640, 400, textAlignX, scaleCursor, rgbRendering) {
-}
-
-UpscaledGfxDriver::UpscaledGfxDriver(uint16 scaledW, uint16 scaledH, int16 textAlignX, bool scaleCursor, bool rgbRendering) :
- GfxDefaultDriver(scaledW, scaledH, false, rgbRendering), _textAlignX(textAlignX), _scaleCursor(scaleCursor), _needCursorBuffer(false),
- _scaledBitmap(nullptr), _renderScaled(nullptr), _renderGlyph(nullptr), _cursorWidth(0), _cursorHeight(0), _hScaleMult(2), _vScaleMult(2), _vScaleDiv(1) {
- _virtualW = 320;
- _virtualH = 200;
-}
-
-UpscaledGfxDriver::~UpscaledGfxDriver() {
- delete[] _scaledBitmap;
-}
-
-void renderGlyph(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h, int transpCol) {
- dstPitch -= w;
- srcPitch -= w;
-
- while (h--) {
- for (int i = 0; i < w; ++i) {
- byte in = *src++;
- if (in != transpCol)
- *dst = in;
- ++dst;
- }
- src += srcPitch;
- dst += dstPitch;
- }
-}
-
-void UpscaledGfxDriver::initScreen(const Graphics::PixelFormat *format) {
- GfxDefaultDriver::initScreen(format);
- _scaledBitmap = new byte[_screenW * _screenH * _srcPixelSize]();
-
- static const ScaledRenderProc scaledRenderProcs[] = {
- &scale2x<byte>,
- &scale2x<uint16>,
- &scale2x<uint32>
- };
- assert((_srcPixelSize >> 1) < ARRAYSIZE(scaledRenderProcs));
- _renderScaled = scaledRenderProcs[_srcPixelSize >> 1];
- _renderGlyph = &renderGlyph;
-}
-
-void UpscaledGfxDriver::setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod *palMods, const byte *palModMapping) {
- GFXDRV_ASSERT_READY;
- if (_pixelSize == 1) {
- GfxDefaultDriver::setPalette(colors, start, num, update, palMods, palModMapping);
- return;
- }
- updatePalette(colors, start, num);
- if (update)
- updateScreen(0, 0, _screenW, _screenH, palMods, palModMapping);
- if (_cursorUsesScreenPalette)
- CursorMan.replaceCursorPalette(_currentPalette, 0, 256);
-}
-
-void UpscaledGfxDriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) {
- GFXDRV_ASSERT_READY;
- assert (h >= 0 && w >= 0);
-
- src += (srcY * pitch + srcX * _srcPixelSize);
- if (src != _currentBitmap)
- updateBitmapBuffer(_currentBitmap, _virtualW * _srcPixelSize, src, pitch, destX * _srcPixelSize, destY, w * _srcPixelSize, h);
-
- int realWidth = 0;
- int realHeight = 0;
-
- // We need to scale and color convert the bitmap in separate functions, because we want
- // to keep the scaled non-color-modified bitmap for palette updates in rgb rendering mode.
- renderBitmap(src, pitch, destX, destY, w, h, realWidth, realHeight);
-
- Common::Point p(destX, destY);
- p = getRealCoords(p);
-
- updateScreen(p.x, p.y, realWidth, realHeight, palMods, palModMapping);
-}
-
-void UpscaledGfxDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
- GFXDRV_ASSERT_READY;
- if (_scaleCursor) {
- adjustCursorBuffer(w << 1, h << 1);
- scale2x<byte>(_compositeBuffer, reinterpret_cast<const byte*>(cursor), w, w, h);
- CursorMan.replaceCursor(_compositeBuffer, w << 1, h << 1, hotspotX << 1, hotspotY << 1, keycolor);
- } else {
- CursorMan.replaceCursor(cursor, w, h, hotspotX, hotspotY, keycolor);
- }
-}
-
-Common::Point UpscaledGfxDriver::getMousePos() const {
- Common::Point res = GfxDriver::getMousePos();
- res.x /= _hScaleMult;
- res.y = res.y * _vScaleDiv / _vScaleMult;
- return res;
-}
-
-void UpscaledGfxDriver::setMousePos(const Common::Point &pos) const {
- g_system->warpMouse(pos.x * _hScaleMult, pos.y * _vScaleMult / _vScaleDiv);
-}
-
-void UpscaledGfxDriver::setShakePos(int shakeXOffset, int shakeYOffset) const {
- g_system->setShakePos(shakeXOffset * _hScaleMult, shakeYOffset * _vScaleMult / _vScaleDiv);
-}
-
-void UpscaledGfxDriver::clearRect(const Common::Rect &r) const {
- Common::Rect r2(r.left * _hScaleMult, r.top * _vScaleMult / _vScaleDiv, r.right * _hScaleMult, r.bottom * _vScaleMult / _vScaleDiv);
- GfxDriver::clearRect(r2);
-}
-
-Common::Point UpscaledGfxDriver::getRealCoords(Common::Point &pos) const {
- return Common::Point(pos.x * _hScaleMult, pos.y * _vScaleMult / _vScaleDiv);
-}
-
-void UpscaledGfxDriver::drawTextFontGlyph(const byte *src, int pitch, int hiresDestX, int hiresDestY, int hiresW, int hiresH, int transpColor, const PaletteMod *palMods, const byte *palModMapping) {
- GFXDRV_ASSERT_READY;
- hiresDestX &= ~(_textAlignX - 1);
- byte *scb = _scaledBitmap + hiresDestY * _screenW * _srcPixelSize + hiresDestX * _srcPixelSize;
- _renderGlyph(scb, _screenW, src, pitch, hiresW, hiresH, transpColor);
- updateScreen(hiresDestX, hiresDestY, hiresW, hiresH, palMods, palModMapping);
-}
-
-void UpscaledGfxDriver::updateScreen(int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) {
- byte *buff = _compositeBuffer;
- int pitch = w * _pixelSize;
- byte *scb = _scaledBitmap + destY * _screenW * _srcPixelSize + destX * _srcPixelSize;
- if (palMods && palModMapping) {
- _colorConvMod(buff, scb, _screenW, w, h, _currentPalette, _internalPalette, _format, palMods, palModMapping);
- } else if (_pixelSize != _srcPixelSize) {
- _colorConv(buff, scb, _screenW, w, h, _internalPalette);
- } else {
- buff = scb;
- pitch = _screenW *_pixelSize;
- }
-
- g_system->copyRectToScreen(buff, pitch, destX, destY, w, h);
-}
-
-void UpscaledGfxDriver::adjustCursorBuffer(uint16 newWidth, uint16 newHeight) {
- // For configs which need/have the composite buffer for other purposes, we can skip this.
- if (!_compositeBuffer)
- _needCursorBuffer = true;
- else if (!_needCursorBuffer)
- return;
-
- if (_cursorWidth * _cursorHeight < newWidth * newHeight) {
- delete[] _compositeBuffer;
- _compositeBuffer = new byte[newWidth * newHeight * _srcPixelSize]();
- _cursorWidth = newWidth;
- _cursorHeight = newHeight;
- }
-}
-
-void UpscaledGfxDriver::renderBitmap(const byte *src, int pitch, int dx, int dy, int w, int h, int &realWidth, int &realHeight) {
- byte *scb = _scaledBitmap + (dy << 1) * _screenW * _srcPixelSize + (dx << 1) * _srcPixelSize;
- _renderScaled(scb, src, pitch, w, h);
- realWidth = w << 1;
- realHeight = h << 1;
-}
-
-WindowsGfx256ColorsDriver::WindowsGfx256ColorsDriver(bool coloredDosStyleCursors, bool smallWindow,bool rgbRendering) :
- UpscaledGfxDriver(smallWindow ? 320 : 640, smallWindow ? 240 : 440, 1, coloredDosStyleCursors && !smallWindow, rgbRendering), _dosStyleCursors(coloredDosStyleCursors), _smallWindow(smallWindow),
- _renderLine(nullptr), _renderLine2(nullptr), _flags(0), _colorMap(nullptr), _vScaleMult2(smallWindow ? 1 : 2) {
- _virtualW = 320;
- _virtualH = 200;
- if (smallWindow)
- _hScaleMult = 1;
- _vScaleMult = _smallWindow ? 6 : 11;
- _vScaleDiv = 5;
-}
-
-void largeWindowRenderLine(byte *&dst, const byte *src, int pitch, int w, int ty) {
- int dstPitch = pitch;
- int dstPitch2 = pitch - (w << 1);
- byte *d1 = dst;
- byte *d2 = d1 + dstPitch;
-
- if (ty == 5) {
- byte *d3 = d2 + dstPitch;
- for (int i = 0; i < w; ++i) {
- d1[0] = d1[1] = d2[0] = d2[1] = d3[0] = d3[1] = *src++;
- d1 += 2;
- d2 += 2;
- d3 += 2;
- }
- dst = d3 + dstPitch2;
- } else {
- for (int i = 0; i < w; ++i) {
- d1[0] = d1[1] = d2[0] = d2[1] = *src++;
- d1 += 2;
- d2 += 2;
- }
- dst = d2 + dstPitch2;
- }
-}
-
-void largeWindowRenderLineMovie(byte *&dst, const byte *src, int pitch, int w, const byte*) {
- int dstPitch = pitch;
- int dstPitch2 = pitch - (w << 1);
- byte *d1 = dst;
- byte *d2 = d1 + dstPitch;
-
- for (int i = 0; i < w; ++i) {
- d1[0] = d1[1] = d2[0] = d2[1] = *src++;
- d1 += 2;
- d2 += 2;
- }
- dst = d2 + dstPitch2;
-}
-
-void smallWindowRenderLine(byte *&dst, const byte *src, int pitch, int w, int ty) {
- int dstPitch = pitch;
- int dstPitch2 = pitch - w;
- byte *d1 = dst;
-
- if (ty == 5) {
- byte *d2 = d1 + dstPitch;
- for (int i = 0; i < w; ++i)
- *d1++ = *d2++ = *src++;
- dst = d2 + dstPitch2;
- } else {
- for (int i = 0; i < w; ++i)
- *d1++ = *src++;
- dst = d1 + dstPitch2;
- }
-}
-
-void smallWindowRenderLineMovie(byte *&dst, const byte *src, int pitch, int w, const byte*) {
- int dstPitch = pitch - w;
- byte *d1 = dst;
-
- for (int i = 0; i < w; ++i)
- *d1++ = *src++;
- dst = d1 + dstPitch;
-}
-
-void hiresRenderLine(byte *&dst, const byte *src, int pitch, int w, const byte *colorMap) {
- if (!colorMap) {
- memcpy(dst, src, w);
- } else {
- byte *d = dst;
- for (int i = 0; i < w; ++i)
- *d++ = colorMap[*src++];
- }
- dst += pitch;
-}
-
-void renderLineDummy(byte *&, const byte* , int, int, const byte*) {
-}
-
-void WindowsGfx256ColorsDriver::initScreen(const Graphics::PixelFormat *format) {
- UpscaledGfxDriver::initScreen(format);
- _renderLine = _smallWindow ? &smallWindowRenderLine : &largeWindowRenderLine;
- _renderLine2 = _smallWindow ? &renderLineDummy : &hiresRenderLine;
-}
-
-void WindowsGfx256ColorsDriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) {
- GFXDRV_ASSERT_READY;
- assert (h >= 0 && w >= 0);
-
- if (!(_flags & (kHiResMode | kMovieMode))) {
- UpscaledGfxDriver::copyRectToScreen(src, srcX, srcY, pitch, destX, destY, w, h, palMods, palModMapping);
- return;
- }
-
- if (_flags & kMovieMode) {
- destX = (_screenW >> 1) - (w & ~1) * _hScaleMult / 2;
- destY = (_screenH >> 1) - (h & ~1) * _vScaleMult2 / 2;
- }
-
- src += (srcY * pitch + srcX * _srcPixelSize);
- byte *dst = _scaledBitmap + destY * _screenW * _srcPixelSize + destX * _srcPixelSize;
-
- for (int i = 0; i < h; ++i) {
- _renderLine2(dst, src, _screenW, w, _colorMap);
- src += pitch;
- }
-
- if (_flags & kMovieMode) {
- w *= _hScaleMult;
- h *= _vScaleMult2;
- }
-
- updateScreen(destX, destY, w, h, palMods, palModMapping);
-}
-
-byte findColorInPalette(uint32 rgbTriplet, const byte *palette, int numColors) {
- byte color[3];
- for (int i = 2; i >= 0; --i) {
- color[i] = rgbTriplet & 0xFF;
- rgbTriplet >>= 8;
- }
- int min = 65025;
- byte match = 0;
- for (int i = 0; i < numColors && min; ++i) {
- const byte *rgb = &palette[i * 3];
- int t = (color[0] - rgb[0]) * (color[0] - rgb[0]) + (color[1] - rgb[1]) * (color[1] - rgb[1]) + (color[2] - rgb[2]) * (color[2] - rgb[2]);
- if (t < min) {
- min = t;
- match = i;
- }
- }
- return match;
-}
-
-void renderWinMonochromeCursor(byte *dst, const void *src, const byte *palette, uint &w, uint &h, int &hotX, int &hotY, byte blackColor, byte whiteColor, uint32 &keycolor, bool noScale) {
- const byte *s = reinterpret_cast<const byte*>(src);
- uint16 min = 65025;
- uint16 max = 0;
-
- byte newKeyColor = 0;
- while (newKeyColor == blackColor || newKeyColor == whiteColor)
- ++newKeyColor;
-
- for (uint i = 0; i < w * h; ++i) {
- byte col = *s++;
- if (col == keycolor)
- continue;
- const byte *rgb = &palette[col * 3];
- uint16 t = rgb[0] * 28 + rgb[1] * 150 + rgb[2] * 28;
- if (t > max)
- max = t;
- if (t < min)
- min = t;
- }
-
-#if 0
- // The original interpreter will accidentally let the value overflow like this,
- // making most cursors completely white. I have fixed it.
- uint16 med = (uint16)(min + max) >> 1;
-#else
- uint16 med = (min + max) >> 1;
-#endif
- uint16 lim1 = max - (max - min) / 3;
- uint16 lim2 = min + max - lim1;
- s = reinterpret_cast<const byte*>(src);
-
- if (w < 17 && h < 17 && !noScale) {
- // Small cursors (like the insignia ring in KQ6) get scaled and dithered.
- byte *dst2 = dst + (w << 1);
- for (uint i = 0; i < h; ++i) {
- for (uint ii = 0; ii < w; ++ii) {
- byte col = *s++;
- if (col == keycolor) {
- *dst++ = *dst2++ = newKeyColor;
- *dst++ = *dst2++ = newKeyColor;
- continue;
- }
- const byte *rgb = &palette[col * 3];
- uint16 t = rgb[0] * 28 + rgb[1] * 150 + rgb[2] * 28;
-
- dst[0] = dst2[1] = t > lim2 ? whiteColor : blackColor;
- dst2[0] = dst[1] = t > lim1 ? whiteColor : blackColor;
- dst += 2;
- dst2 += 2;
- };
- dst += (w << 1);
- dst2 += (w << 1);
- }
- w <<= 1;
- h <<= 1;
- hotX <<= 1;
- hotY <<= 1;
- } else {
- for (uint i = 0; i < w * h; ++i) {
- byte col = *s++;
- if (col == keycolor) {
- *dst++ = newKeyColor;
- continue;
- }
- const byte *rgb = &palette[col * 3];
- uint16 t = rgb[0] * 28 + rgb[1] * 150 + rgb[2] * 28;
- *dst++ = t > med ? whiteColor : blackColor;
- }
- }
- keycolor = newKeyColor;
-}
-
-void WindowsGfx256ColorsDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
- GFXDRV_ASSERT_READY;
- if (_dosStyleCursors) {
- // The original windows interpreter always renders the cursor as b/w, regardless of which cursor views (the DOS
- // cursors or the new Windows ones) the user selects. This is also regardless of color mode (16 or 256 colors).
- // It is a technical limitation on Windows 95 with VGA hardware that mouse cursors have to be b/w.
- // Instead, we use the colored DOS style cursors as a default, since there was consensus to do that.
- UpscaledGfxDriver::replaceCursor(cursor, w, h, hotspotX, hotspotY, keycolor);
- return;
- }
- adjustCursorBuffer(w << 1, h << 1);
-
- if (_pixelSize == 1)
- copyCurrentPalette(_currentPalette, 0, _numColors);
-
- byte col1 = findColorInPalette(0x00000000, _currentPalette, _numColors);
- byte col2 = findColorInPalette(0x00FFFFFF, _currentPalette, _numColors);
- renderWinMonochromeCursor(_compositeBuffer, cursor, _currentPalette, w, h, hotspotX, hotspotY, col1, col2, keycolor, _smallWindow);
- CursorMan.replaceCursor(_compositeBuffer, w, h, hotspotX, hotspotY, keycolor);
-}
-
-Common::Point WindowsGfx256ColorsDriver::getRealCoords(Common::Point &pos) const {
- return Common::Point(pos.x * _hScaleMult, pos.y * _vScaleMult2 + (pos.y + 4) / 5);
-}
-
-void WindowsGfx256ColorsDriver::setFlags(uint32 flags) {
- flags ^= (_flags & flags);
- if (!flags)
- return;
-
- if (flags & kMovieMode)
- _renderLine2 = _smallWindow ? &smallWindowRenderLineMovie : &largeWindowRenderLineMovie;
-
- _flags |= flags;
-}
-
-void WindowsGfx256ColorsDriver::clearFlags(uint32 flags) {
- flags &= _flags;
- if (!flags)
- return;
-
- if (flags & kMovieMode)
- _renderLine2 = _smallWindow ? &renderLineDummy : &hiresRenderLine;
-
- _flags &= ~flags;
-}
-
-void WindowsGfx256ColorsDriver::renderBitmap(const byte *src, int pitch, int dx, int dy, int w, int h, int &realWidth, int &realHeight) {
- assert(_renderLine);
-
- byte *dst = _scaledBitmap + (dy * _vScaleMult2 + (dy + 4) / 5) * _screenW * _srcPixelSize + dx *_hScaleMult * _srcPixelSize;
- const byte *dstart = dst;
- dy = (dy + 4) % 5;
-
- while (h--) {
- _renderLine(dst, src, _screenW, w, ++dy);
- dy %= 5;
- src += pitch;
- }
-
- realWidth = w * _hScaleMult;
- realHeight = (dst - dstart) / _screenW;
-}
-
-WindowsGfx16ColorsDriver::WindowsGfx16ColorsDriver(bool enhancedDithering, bool rgbRendering) : SCI1_EGADriver(rgbRendering), _enhancedDithering(enhancedDithering), _renderLine2(nullptr) {
- static const byte win16Colors[48] = {
- 0x00, 0x00, 0x00, 0xA8, 0x00, 0x57, 0x00, 0xA8, 0x57, 0xA8, 0xA8, 0x57,
- 0x00, 0x00, 0xA8, 0xA8, 0x57, 0xA8, 0x57, 0xA8, 0xA8, 0x87, 0x88, 0x8F,
- 0xC0, 0xC7, 0xC8, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
- 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
- };
-
- _convPalette = win16Colors;
- _vScaleMult = 11;
- _vScaleDiv = 5;
-}
-
-template <typename T, bool extScale> void win16ColRenderLine(byte *&dst, const byte *src, int w, const byte *patterns, const byte *pal, bool swap) {
- const T *p = reinterpret_cast<const T*>(pal);
- T *d1 = reinterpret_cast<T*>(dst);
- T *d2 = d1 + (w << 1);
- T *d3 = d2 + (w << 1);
- T *&d3r = swap ? d2 : d1;
-
- if (swap)
- SWAP(d1, d2);
-
- for (int i = 0; i < w; ++i) {
- byte pt = patterns[*src++];
- if (sizeof(T) == 1) {
- *d1++ = d2[1] = pt & 0x0F;
- *d1++ = *d2++ = pt >> 4;
- } else {
- *d1++ = d2[1] = p[pt & 0x0F];
- *d1++ = *d2++ = p[pt >> 4];
- }
- d2++;
-
- if (extScale) {
- *d3++ = *(d3r - 2);
- *d3++ = *(d3r - 1);
- }
- }
-
- dst = reinterpret_cast<byte*>(extScale ? d3 : (swap ? d1 : d2));
-}
-
-void WindowsGfx16ColorsDriver::initScreen(const Graphics::PixelFormat *format) {
- SCI1_EGADriver::initScreen(format);
-
- static const LineProc lineProcs[] = {
- &win16ColRenderLine<byte, false>,
- &win16ColRenderLine<byte, true>,
- &win16ColRenderLine<uint16, false>,
- &win16ColRenderLine<uint16, true>,
- &win16ColRenderLine<uint32, false>,
- &win16ColRenderLine<uint32, true>
- };
-
- assert((_pixelSize | 1) < ARRAYSIZE(lineProcs));
- _renderLine = lineProcs[_pixelSize & ~1];
- _renderLine2 = lineProcs[_pixelSize | 1];
-}
-
-void WindowsGfx16ColorsDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
- GFXDRV_ASSERT_READY;
- // The original windows interpreter always renders the cursor as b/w, regardless of which cursor views (the DOS
- // cursors or the new Windows ones) the user selects. This is also regardless of color mode (16 or 256 colors).
- byte col1 = findColorInPalette(0x00000000, _convPalette, _numColors);
- byte col2 = findColorInPalette(0x00FFFFFF, _convPalette, _numColors);
- renderWinMonochromeCursor(_compositeBuffer, cursor, _currentPalette, w, h, hotspotX, hotspotY, col1, col2, keycolor, false);
- CursorMan.replaceCursor(_compositeBuffer, w, h, hotspotX, hotspotY, keycolor);
-}
-
-Common::Point WindowsGfx16ColorsDriver::getRealCoords(Common::Point &pos) const {
- return Common::Point(pos.x << 1, (pos.y << 1) + (pos.y + 4) / 5);
-}
-
-void WindowsGfx16ColorsDriver::loadData() {
- Common::File file;
- if (!file.open(_driverFile))
- GFXDRV_ERR_OPEN(_driverFile);
-
- int64 sz = file.size();
- byte *buf = new byte[sz];
- file.read(buf, sz);
- file.close();
-
- // We can keep the search for the table simple, since there are only two supported executables (KQ6
- // Windows and SQ4 Windows) and both contain the following value only within the pattern table...
- uint32 srch = FROM_LE_32(0xCC4C4404);
-
- const byte *tblOffs = nullptr;
- for (const byte *pos = buf; pos < buf + sz - 67 && tblOffs == nullptr; ++pos) {
- // We check three times, just to be sure. Checking once would actually suffice.
- if (READ_UINT32(pos) != srch || READ_UINT32(pos + 8) != srch || READ_UINT32(pos + 64) != srch)
- continue;
- tblOffs = pos - 4;
- }
-
- if (tblOffs == nullptr)
- error("%s(): Failed to load 16 colors match table", __FUNCTION__);
-
- byte *tbl = new byte[512];
- memcpy(tbl, tblOffs, 512);
- _egaMatchTable = tbl;
-
- delete[] buf;
-
- _colAdjust = (_egaMatchTable[482] == 0x79) ? 4 : 0;
- _numColors = 16;
-}
-
-void WindowsGfx16ColorsDriver::renderBitmap(byte *dst, const byte *src, int pitch, int y, int w, int h, const byte *patterns, const byte *palette, uint16 &realWidth, uint16 &realHeight) {
- const byte *dst0 = dst;
- byte mod = (y + 4) % 5;
- byte swap = _enhancedDithering ? ((y + 4) / 5) & 1 : 0;
- for (int i = 0; i < h; ++i) {
- if (++mod == 5) {
- _renderLine2(dst, src, w, patterns, palette, swap);
- if (_enhancedDithering)
- swap ^= 1;
- mod = 0;
- } else {
- _renderLine(dst, src, w, patterns, palette, swap);
- }
- src += pitch;
- }
- realWidth = w << 1;
- realHeight = (dst - dst0) / (realWidth * _pixelSize);
-}
-
-const char *WindowsGfx16ColorsDriver::_driverFile = "SCIWV.EXE";
-
-PC98Gfx16ColorsDriver::PC98Gfx16ColorsDriver(int textAlignX, bool cursorScaleWidth, bool cursorScaleHeight, SjisFontStyle sjisFontStyle, bool rgbRendering, bool needsUnditheringPalette) :
- UpscaledGfxDriver(textAlignX, cursorScaleWidth && cursorScaleHeight, rgbRendering), _textModePalette(nullptr), _fontStyle(sjisFontStyle),
- _cursorScaleHeightOnly(!cursorScaleWidth && cursorScaleHeight), _convPalette(nullptr) {
- // Palette taken from driver file (identical for all versions of the
- // driver I have seen so far, also same for SCI0 and SCI1)
- static const byte pc98colorsV16[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x07, 0x07,
- 0x07, 0x00, 0x00, 0x07, 0x00, 0x07, 0x05, 0x07, 0x00, 0x09, 0x09, 0x09,
- 0x06, 0x06, 0x06, 0x00, 0x00, 0x0f, 0x07, 0x0f, 0x06, 0x00, 0x0f, 0x0f,
- 0x0f, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f
- };
-
- byte *col = new byte[768]();
- const byte *s = pc98colorsV16;
-
- for (uint i = 0; i < sizeof(pc98colorsV16) / 3; ++i) {
- int a = ((i & 6) == 4 || (i & 6) == 2 ? i ^ 6 : i) * 3;
- col[a + 0] = (s[1] * 0x11);
- col[a + 1] = (s[0] * 0x11);
- col[a + 2] = (s[2] * 0x11);
- s += 3;
- }
-
- if (_fontStyle == kFontStyleTextMode) {
- byte *d = &col[48];
- for (uint8 i = 0; i < 8; ++i) {
- *d++ = (i & 4) ? 0xff : 0;
- *d++ = (i & 2) ? 0xff : 0;
- *d++ = (i & 1) ? 0xff : 0;
- }
- }
-
- if (needsUnditheringPalette) {
- // We store the text mode color separately, since we need the slots for the undithering.
- if (_fontStyle == kFontStyleTextMode) {
- byte *tpal = new byte[24]();
- memcpy(tpal, &col[48], 24);
- _textModePalette = tpal;
- }
- // For the undithered mode, we generate the missing colors using the same formula as for EGA.
- byte *d = &col[48];
- for (int i = 16; i < 256; i++) {
- const byte *s1 = &col[(i & 0x0f) * 3];
- const byte *s2 = &col[(i >> 4) * 3];
- for (int ii = 0; ii < 3; ++ii)
- *d++ = (byte)(0.5 + (pow(0.5 * ((pow(*s1++ / 255.0, 2.2 / 1.0) * 255.0) + (pow(*s2++ / 255.0, 2.2 / 1.0) * 255.0)) / 255.0, 1.0 / 2.2) * 255.0));
- }
- }
-
- _convPalette = col;
-}
-
-PC98Gfx16ColorsDriver::~PC98Gfx16ColorsDriver() {
- delete[] _convPalette;
- delete[] _textModePalette;
-}
-
-void renderPC98GlyphFat(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h, int transpCol) {
- dstPitch -= w;
- srcPitch -= w;
-
- while (h--) {
- for (int i = 0; i < w - 1; ++i) {
- uint8 a = *src++;
- uint8 b = *src;
- if (a != transpCol)
- *dst = a;
- else if (b != transpCol)
- *dst = b;
- ++dst;
- }
- byte l = *src++;
- if (l != transpCol)
- *dst = l;
- ++dst;
- src += srcPitch;
- dst += dstPitch;
- }
-}
-
-void renderPC98GlyphSpecial(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h, int transpCol) {
- assert(h == 16); // This is really not suitable for anything but the special SCI1 PC98 glyph drawing
- dstPitch -= w;
- srcPitch -= w;
-
- while (h--) {
- if (h > 10 || h < 5) {
- for (int i = 0; i < w - 1; ++i) {
- uint8 a = *src++;
- uint8 b = *src;
- if (a != transpCol)
- *dst = a;
- else if (b != transpCol)
- *dst = b;
- ++dst;
- }
- byte l = *src++;
- if (l != transpCol)
- *dst = l;
- ++dst;
- } else {
- for (int i = 0; i < w; ++i) {
- byte in = *src++;
- if (in != transpCol)
- *dst = in;
- ++dst;
- }
- }
- src += srcPitch;
- dst += dstPitch;
- }
-}
-
-void PC98Gfx16ColorsDriver::initScreen(const Graphics::PixelFormat *format) {
- UpscaledGfxDriver::initScreen(format);
-
- assert(_convPalette);
- GfxDefaultDriver::setPalette(_convPalette, 0, 256, true, nullptr, nullptr);
-
- if (_fontStyle == kFontStyleTextMode)
- _renderGlyph = &renderPC98GlyphFat;
-
- if (_fontStyle != kFontStyleSpecialSCI1)
- return;
-
- _renderGlyph = &renderPC98GlyphSpecial;
-}
-
-void PC98Gfx16ColorsDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
- GFXDRV_ASSERT_READY;
- if (!_cursorScaleHeightOnly) {
- UpscaledGfxDriver::replaceCursor(cursor, w, h, hotspotX, hotspotY, keycolor);
- return;
- }
-
- // Special case for PQ2 which scales the cursor height (but not the width)
- adjustCursorBuffer(w, h << 1);
- const byte *s = reinterpret_cast<const byte*>(cursor);
- byte *d = _compositeBuffer;
-
- for (uint i = 0; i < h; ++i) {
- memcpy(d, s, w);
- d += w;
- memcpy(d, s, w);
- d += w;
- s += w;
- }
-
- CursorMan.replaceCursor(_compositeBuffer, w, h << 1, hotspotX, hotspotY << 1, keycolor);
-}
-
-byte PC98Gfx16ColorsDriver::remapTextColor(byte color) const {
- // Always black for QFG and SCI1. For QFG, this is on purpose. The code just copies the inverted glyph data
- // into all 4 vmem planes. For SCI1 the driver opcode actually has a pen color argument, but it isn't put
- // to any use. Not sure if it is intended.
- if (_fontStyle != kFontStyleTextMode)
- return 0;
-
- color &= 7;
- // This seems to be a bug in the original PQ2 interpreter, which I replicate, so that we get the same colors.
- // What they were trying to do is just getting the rgb bits in the right order (switch red and green). But
- // instead, before checking and setting the bits, they also copy the full color byte to the target color. So,
- // the extra bits come just on top. The result: All green and red colors are turned into yellow, all magenta
- // and cyan colors are turned into white.
- if (color & 2)
- color |= 4;
- if (color & 4)
- color |= 2;
- // This is the blue color that PQ2 uses basically for all Japanese text...
- if (color == 0)
- color = 1;
-
- byte textCol = color;
- color += 0x10;
-
- if (_textModePalette) {
- // If we have used up the whole space of the CLUT8 for the undithering, we try
- // to relocate the color which will work for all text mode colors with the default
- // palette that is used by the PC-98 ports...
- for (int i = 0; i < 256; ++i) {
- if (_convPalette[i * 3] != _textModePalette[textCol * 3] || _convPalette[i * 3 + 1] != _textModePalette[textCol * 3 + 1] || _convPalette[i * 3 + 2] != _textModePalette[textCol * 3 + 2])
- continue;
- color = i;
- break;
- }
- if (color >= 16)
- color = 0;
- }
- return color;
-}
-
-SCI0_PC98Gfx8ColorsDriver::SCI0_PC98Gfx8ColorsDriver(bool cursorScaleHeight, bool useTextModeForSJISChars, bool rgbRendering) :
- UpscaledGfxDriver(8, false, rgbRendering), _cursorScaleHeightOnly(cursorScaleHeight), _useTextMode(useTextModeForSJISChars), _convPalette(nullptr) {
- byte *col = new byte[8 * 3]();
- _convPalette = col;
-
- for (uint8 i = 0; i < 8; ++i) {
- *col++ = (i & 4) ? 0xff : 0;
- *col++ = (i & 2) ? 0xff : 0;
- *col++ = (i & 1) ? 0xff : 0;
- }
-}
-
-SCI0_PC98Gfx8ColorsDriver::~SCI0_PC98Gfx8ColorsDriver() {
- delete[] _convPalette;
-}
-
-void pc98SimpleDither(byte *dst, const byte *src, int pitch, int w, int h) {
- int dstPitch = pitch << 1;
- byte *d1 = dst;
- byte *d2 = d1 + dstPitch;
- pitch -= w;
- dstPitch += (pitch << 1);
-
- while (h--) {
- for (int i = 0; i < w; ++i) {
- uint8 v = *src++;
- d1[0] = d2[0] = (v & 7);
- d1[1] = d2[1] = (v & 8) ? (v & 7) : 0;
- d1 += 2;
- d2 += 2;
- }
- src += pitch;
- d1 += dstPitch;
- d2 += dstPitch;
- }
-}
-
-void SCI0_PC98Gfx8ColorsDriver::initScreen(const Graphics::PixelFormat *format) {
- UpscaledGfxDriver::initScreen(format);
- _renderScaled = &pc98SimpleDither;
- if (_useTextMode)
- _renderGlyph = &renderPC98GlyphFat;
- assert(_convPalette);
- GfxDefaultDriver::setPalette(_convPalette, 0, 8, true, nullptr, nullptr);
-}
-
-void SCI0_PC98Gfx8ColorsDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
- GFXDRV_ASSERT_READY;
- adjustCursorBuffer(w, _cursorScaleHeightOnly ? h << 1 : h);
- const byte *s = reinterpret_cast<const byte*>(cursor);
- byte *d = _compositeBuffer;
- uint32 newKeyColor = 0xFF;
-
- for (uint i = 0; i < h; ++i) {
- for (uint ii = 0; ii < w; ++ii) {
- byte col = *s++;
- *d++ = (col == keycolor) ? newKeyColor : (col & 7);
- }
- }
-
- // Special case for PQ2 which 2x scales the cursor height
- if (_cursorScaleHeightOnly) {
- s = _compositeBuffer + h * w - w;
- d = _compositeBuffer + h * w * 2 - w;
-
- for (uint i = 0; i < h; ++i) {
- memcpy(d, s, w);
- d -= w;
- memcpy(d, s, w);
- d -= w;
- s -= w;
- }
- h <<= 1;
- hotspotX <<= 1;
- }
-
- CursorMan.replaceCursor(_compositeBuffer, w, h, hotspotX, hotspotY, newKeyColor);
-}
-
-byte SCI0_PC98Gfx8ColorsDriver::remapTextColor(byte color) const {
- // Always black. For QFG, this is on purpose. The code just copies the inverted glyph data into all 4 vmem planes.
- if (!_useTextMode)
- return 0;
-
- color &= 7;
- // This seems to be a bug in the original PQ2 interpreter, which I replicate, so that we get the same colors.
- // What they were trying to do is just getting the rgb bits in the right order (switch red and green). But
- // instead, before checking and setting the bits, they also copy the full color byte to the target color. So,
- // the extra bits come just on top. The result: All green and red colors are turned into yellow, all magenta
- // and cyan colors are turned into white.
- if (color & 2)
- color |= 4;
- if (color & 4)
- color |= 2;
- // This is the blue color that PQ2 uses basically for all Japanese text...
- if (color == 0)
- color = 1;
-
- return color;
-}
-
-const char *SCI0_PC98Gfx8ColorsDriver::_driverFiles[2] = { "9801V8M.DRV", "9801VID.DRV" };
-
-SCI1_PC98Gfx8ColorsDriver::SCI1_PC98Gfx8ColorsDriver(bool rgbRendering) : UpscaledGfxDriver(1, true, rgbRendering), _ditheringTable(nullptr), _convPalette(nullptr) {
- Common::File drv;
- if (!drv.open(_driverFile))
- GFXDRV_ERR_OPEN(_driverFile);
-
- uint16 eprcOffs = 0;
-
- uint32 cmd = drv.readUint32LE();
- if ((cmd & 0xFF) == 0xE9)
- eprcOffs = ((cmd >> 8) & 0xFFFF) + 3;
-
- if (!eprcOffs || drv.readUint32LE() != 0x87654321 || !drv.skip(1) || !drv.seek(drv.readByte(), SEEK_CUR) || !drv.seek(drv.readByte(), SEEK_CUR))
- GFXDRV_ERR_VERSION(_driverFile);
-
- uint32 pos = (drv.pos() + 1) & ~1;
-
- drv.seek(pos + 2);
- drv.seek(drv.readUint16LE());
- byte *buff = new byte[190];
- drv.read(buff, 190);
-
- uint16 tableOffs = 0;
- int step = 0;
- for (int i = 0; i < 182 && !tableOffs; ++i) {
- uint32 c = READ_BE_UINT32(buff + i);
- if (step == 0 && ((c & 0xFFF0FFF0) != 0xD1E0D1E0 || (READ_BE_UINT32(buff + i + 4) ^ c)))
- continue;
-
- if (step == 0) {
- step = 1;
- i += 7;
- continue;
- }
-
- if (c >> 20 != 0x81C || ((READ_BE_UINT32(buff + i + 4) >> 20) ^ (c >> 20)))
- continue;
-
- if ((c & 0xFFFF) == READ_BE_UINT16(buff + i + 6))
- tableOffs = FROM_BE_16(c);
- }
- delete[] buff;
-
- if (!tableOffs)
- error("SCI1_PC98Gfx8ColorsDriver: Failed to load dithering data from '%s'", _driverFile);
-
- drv.seek(tableOffs);
- byte *dmx = new byte[96]();
- drv.read(dmx, 96);
-
- if (drv.readUint16LE() != 0xA800 || drv.readUint16LE() != 0xB000)
- GFXDRV_ERR_VERSION(_driverFile);
-
- drv.close();
-
- byte *dt = new byte[1536]();
- _ditheringTable = dt;
-
- for (uint16 i = 0; i < 256; ++i) {
- for (int ii = 0; ii < 6; ++ii)
- *dt++ = (dmx[(i >> 4) * 6 + ii] & 0xCC) | (dmx[(i & 0x0f) * 6 + ii] & 0x33);
- }
-
- delete[] dmx;
-
- _textAlignX = 1;
-
- byte *col = new byte[8 * 3]();
- _convPalette = col;
-
- for (uint8 i = 0; i < 8; ++i) {
- *col++ = (i & 2) ? 0xff : 0;
- *col++ = (i & 1) ? 0xff : 0;
- *col++ = (i & 4) ? 0xff : 0;
- }
-}
-
-SCI1_PC98Gfx8ColorsDriver::~SCI1_PC98Gfx8ColorsDriver() {
- delete[] _ditheringTable;
- delete[] _convPalette;
-}
-
-void renderPlanarMatrix(byte *dst, const byte *src, int pitch, int w, int h, const byte *tbl) {
- int dstPitch = pitch << 1;
- byte *d1 = dst;
- byte *d2 = d1 + dstPitch;
- pitch -= w;
- dstPitch += (pitch << 1);
-
- while (h--) {
- byte sh = 0;
- for (int i = 0; i < (w >> 1); ++i) {
- const byte *c = &tbl[(src[0] << 4 | src[1]) * 6];
- for (int ii = sh; ii < sh + 4; ++ii) {
- *d1++ = (((c[0] >> (7 - ii)) & 1) << 2) | (((c[1] >> (7 - ii)) & 1) << 1) | ((c[2] >> (7 - ii)) & 1);
- *d2++ = (((c[3] >> (7 - ii)) & 1) << 2) | (((c[4] >> (7 - ii)) & 1) << 1) | ((c[5] >> (7 - ii)) & 1);
- }
- src += 2;
- sh ^= 4;
- }
-
- src += pitch;
- d1 += dstPitch;
- d2 += dstPitch;
- }
-}
-
-void SCI1_PC98Gfx8ColorsDriver::initScreen(const Graphics::PixelFormat *format) {
- UpscaledGfxDriver::initScreen(format);
-
- _renderGlyph = &renderPC98GlyphFat;
-
- assert(_convPalette);
- GfxDefaultDriver::setPalette(_convPalette, 0, 8, true, nullptr, nullptr);
-}
-
-void SCI1_PC98Gfx8ColorsDriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) {
- GFXDRV_ASSERT_READY;
- assert (h >= 0 && w >= 0);
-
- byte diff = srcX & 7;
- srcX &= ~7;
- destX &= ~7;
- w = (w + diff + 7) & ~7;
-
- src += (srcY * pitch + srcX * _srcPixelSize);
- if (src != _currentBitmap)
- updateBitmapBuffer(_currentBitmap, _virtualW * _srcPixelSize, src, pitch, destX * _srcPixelSize, destY, w * _srcPixelSize, h);
-
- byte *scb = _scaledBitmap + (destY << 1) * _screenW * _srcPixelSize + (destX << 1) * _srcPixelSize;
- renderPlanarMatrix(scb, src, pitch, w, h, _ditheringTable);
-
- updateScreen(destX << 1, destY << 1, w << 1, h << 1, palMods, palModMapping);
-}
-
-void SCI1_PC98Gfx8ColorsDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
- GFXDRV_ASSERT_READY;
- adjustCursorBuffer(w << 1, h << 1);
- const byte *s = reinterpret_cast<const byte*>(cursor);
- byte *d1 = _compositeBuffer;
- uint32 newKeyColor = 0xFF;
-
- int dstPitch = (w << 1);
- byte *d2 = _compositeBuffer + dstPitch;
-
- for (uint i = 0; i < h; ++i) {
- for (uint ii = 0; ii < w; ++ii) {
- byte col = *s++;
- if (col == keycolor) {
- *d1++ = *d2++ = newKeyColor;
- *d1++ = *d2++ = newKeyColor;
- } else {
- *d1++ = *d2++ = (col & 7);
- *d1++ = *d2++ = (col & 8) ? (col & 7) : 0;
- }
- }
- d1 += dstPitch;
- d2 += dstPitch;
- }
-
- CursorMan.replaceCursor(_compositeBuffer, w << 1, h << 1, hotspotX << 1, hotspotY << 1, newKeyColor);
-}
-
-byte SCI1_PC98Gfx8ColorsDriver::remapTextColor(byte) const {
- // Always black. The driver opcode actually has a pen color argument, but it isn't put to any use. Not sure if it is intended.
- return 0;
-}
-const char *SCI1_PC98Gfx8ColorsDriver::_driverFile = "9801V8.DRV";
-
-#undef GFXDRV_ASSERT_READY
-#undef GFXDRV_ERR_OPEN
-#undef GFXDRV_ERR_VERSION
-
-} // End of namespace Sci
diff --git a/engines/sci/graphics/gfxdrivers.h b/engines/sci/graphics/gfxdrivers.h
deleted file mode 100644
index e4a54095c0d..00000000000
--- a/engines/sci/graphics/gfxdrivers.h
+++ /dev/null
@@ -1,385 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef SCI_GRAPHICS_GFXDRIVERS_H
-#define SCI_GRAPHICS_GFXDRIVERS_H
-
-#include "common/platform.h"
-#include "common/rect.h"
-#include "graphics/pixelformat.h"
-
-namespace Graphics {
- class Cursor;
-}
-
-namespace Sci {
-
-struct PaletteMod;
-
-class GfxDriver {
-public:
- enum DrawFlags : uint32 {
- kHiResMode = 1 << 0,
- kMovieMode = 1 << 1
- };
-
- GfxDriver(uint16 screenWidth, uint16 screenHeight, int numColors) : _screenW(screenWidth), _screenH(screenHeight), _numColors(numColors), _ready(false), _pixelSize(1) {}
- virtual ~GfxDriver() {}
- virtual void initScreen(const Graphics::PixelFormat *srcRGBFormat = nullptr) = 0; // srcRGBFormat: expect incoming data to have the specified rgb pixel format (used for Mac hicolor videos)
- virtual void setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod *palMods, const byte *palModMapping) = 0;
- virtual void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) = 0;
- virtual void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) = 0;
- virtual void replaceMacCursor(const Graphics::Cursor *cursor) = 0;
- virtual Common::Point getMousePos() const;
- virtual void setMousePos(const Common::Point &pos) const;
- virtual void setShakePos(int shakeXOffset, int shakeYOffset) const;
- virtual void clearRect(const Common::Rect &r) const;
- virtual void copyCurrentBitmap(byte *dest, uint32 size) const = 0;
- virtual void copyCurrentPalette(byte *dest, int start, int num) const;
- virtual void drawTextFontGlyph(const byte *src, int pitch, int hiresDestX, int hiresDestY, int hiresW, int hiresH, int transpColor, const PaletteMod *palMods, const byte *palModMapping) = 0;
- virtual byte remapTextColor(byte color) const { return color; }
- virtual void setColorMap(const byte *colorMap) {}
- virtual Common::Point getRealCoords(Common::Point &pos) const { return pos; }
- virtual void setFlags(uint32 flags) {}
- virtual void clearFlags(uint32 flags) {}
- virtual bool supportsPalIntensity() const = 0;
- virtual bool supportsHiResGraphics() const = 0;
- virtual bool driverBasedTextRendering() const = 0;
- uint16 numColors() const { return _numColors; }
- byte pixelSize() const { return _pixelSize; }
-
-protected:
- bool _ready;
- static bool checkDriver(const char *const *driverNames, int listSize);
- const uint16 _screenW;
- const uint16 _screenH;
- uint16 _numColors;
- byte _pixelSize;
-};
-
-class GfxDefaultDriver : public GfxDriver {
-public:
- GfxDefaultDriver(uint16 screenWidth, uint16 screenHeight, bool isSCI0, bool rgbRendering);
- ~GfxDefaultDriver() override;
- void initScreen(const Graphics::PixelFormat *srcRGBFormat) override; // srcRGBFormat: expect incoming data to have the specified rgb pixel format (used for Mac hicolor videos)
- void setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod *palMods, const byte *palModMapping) override;
- void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) override;
- void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
- void replaceMacCursor(const Graphics::Cursor*) override;
- void copyCurrentBitmap(byte *dest, uint32 size) const override;
- void copyCurrentPalette(byte *dest, int start, int num) const override;
- void drawTextFontGlyph(const byte*, int, int, int, int, int, int, const PaletteMod*, const byte*) override; // Only for HiRes fonts. Not implemented here.
- bool supportsPalIntensity() const override { return true; }
- bool supportsHiResGraphics() const override { return false; }
- bool driverBasedTextRendering() const override { return false; }
-protected:
- void updatePalette(const byte *colors, uint start, uint num);
- byte *_compositeBuffer;
- byte *_currentBitmap;
- byte *_currentPalette;
- byte *_internalPalette;
- uint16 _virtualW;
- uint16 _virtualH;
- Graphics::PixelFormat _format;
- byte _srcPixelSize;
- bool _cursorUsesScreenPalette;
- const bool _alwaysCreateBmpBuffer;
- const bool _requestRGBMode;
- typedef void (*ColorConvProc)(byte*, const byte*, int, int, int, const byte*);
- ColorConvProc _colorConv;
- typedef void (*ColorConvModProc)(byte*, const byte*, int, int, int, const byte*, const byte*, Graphics::PixelFormat&, const PaletteMod*, const byte*);
- ColorConvModProc _colorConvMod;
-private:
- void generateOutput(byte *dst, const byte *src, int pitch, int w, int h, const PaletteMod *palMods, const byte *palModMapping);
-};
-
-class SCI0_DOSPreVGADriver : public GfxDriver {
-public:
- SCI0_DOSPreVGADriver(int numColors, int screenW, int screenH, bool rgbRendering);
- ~SCI0_DOSPreVGADriver() override;
- void initScreen(const Graphics::PixelFormat*) override;
- void setPalette(const byte*, uint, uint, bool, const PaletteMod*, const byte*) override {}
- void replaceMacCursor(const Graphics::Cursor*) override;
- void copyCurrentBitmap(byte*, uint32) const override;
- void drawTextFontGlyph(const byte*, int, int, int, int, int, int, const PaletteMod*, const byte*) override; // Only for HiRes fonts. Not implemented here.
- void copyCurrentPalette(byte *dest, int start, int num) const override;
- bool supportsPalIntensity() const override { return false; }
- bool supportsHiResGraphics() const override { return false; }
- bool driverBasedTextRendering() const override { return false; }
-protected:
- void assignPalette(const byte *colors);
- byte *_compositeBuffer;
- const byte *_internalPalette;
-private:
- virtual void setupRenderProc() = 0;
- const bool _requestRGBMode;
- const byte *_colors;
-};
-
-class SCI0_CGADriver final : public SCI0_DOSPreVGADriver {
-public:
- SCI0_CGADriver(bool emulateCGAModeOnEGACard, bool rgbRendering);
- ~SCI0_CGADriver() override;
- void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod*, const byte*) override;
- void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
- static bool validateMode(Common::Platform p) { return (p == Common::kPlatformDOS) && checkDriver(&_driverFile, 1); }
-private:
- void setupRenderProc() override;
- uint16 *_cgaPatterns;
- byte _palette[12];
- const bool _disableMode5;
- typedef void (*LineProc)(byte*&, const byte*, int, int, int, const uint16*, const byte*);
- LineProc _renderLine;
- static const char *_driverFile;
-};
-
-class SCI0_CGABWDriver final : public SCI0_DOSPreVGADriver {
-public:
- SCI0_CGABWDriver(uint32 monochromeColor, bool rgbRendering);
- ~SCI0_CGABWDriver() override;
- void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod*, const byte*) override;
- void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
- Common::Point getMousePos() const override;
- void setMousePos(const Common::Point &pos) const override;
- void setShakePos(int shakeXOffset, int shakeYOffset) const override;
- void clearRect(const Common::Rect &r) const override;
- Common::Point getRealCoords(Common::Point &pos) const override;
- static bool validateMode(Common::Platform p) { return (p == Common::kPlatformDOS) && checkDriver(_driverFiles, 2); }
-private:
- void setupRenderProc() override;
- byte _monochromePalette[6];
- const byte *_monochromePatterns;
- bool _earlyVersion;
- typedef void (*LineProc)(byte*&, const byte*, int, int, int, const byte*, const byte*);
- LineProc _renderLine;
- static const char *_driverFiles[2];
-};
-
-class SCI0_HerculesDriver final : public SCI0_DOSPreVGADriver {
-public:
- SCI0_HerculesDriver(uint32 monochromeColor, bool rgbRendering, bool cropImage);
- ~SCI0_HerculesDriver() override;
- void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod*, const byte*) override;
- void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
- Common::Point getMousePos() const override;
- void setMousePos(const Common::Point &pos) const override;
- void setShakePos(int shakeXOffset, int shakeYOffset) const override;
- void clearRect(const Common::Rect &r) const override;
- Common::Point getRealCoords(Common::Point &pos) const override;
- static bool validateMode(Common::Platform p) { return (p == Common::kPlatformDOS) && checkDriver(&_driverFile, 1); }
-private:
- void setupRenderProc() override;
- const uint16 _centerX;
- const uint16 _centerY;
- byte _monochromePalette[6];
- const byte *_monochromePatterns;
- typedef void (*LineProc)(byte*&, const byte*, int, int, int, const byte*, const byte*);
- LineProc _renderLine;
- static const char *_driverFile;
-};
-
-class SCI1_VGAGreyScaleDriver final : public GfxDefaultDriver {
-public:
- SCI1_VGAGreyScaleDriver(bool rgbRendering);
- ~SCI1_VGAGreyScaleDriver() override;
- void setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod *palMods, const byte *palModMapping) override;
- static bool validateMode(Common::Platform p) { return (p == Common::kPlatformDOS || p == Common::kPlatformWindows) && checkDriver(&_driverFile, 1); }
-private:
- byte *_greyScalePalette;
- static const char *_driverFile;
-};
-
-class SCI1_EGADriver : public GfxDriver {
-public:
- SCI1_EGADriver(bool rgbRendering);
- ~SCI1_EGADriver() override;
- void initScreen(const Graphics::PixelFormat*) override;
- void setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod*, const byte*) override;
- void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod*, const byte*) override;
- void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
- void replaceMacCursor(const Graphics::Cursor *cursor) override {}
- void copyCurrentBitmap(byte *dest, uint32 size) const override;
- void copyCurrentPalette(byte *dest, int start, int num) const override;
- void drawTextFontGlyph(const byte*, int, int, int, int, int, int, const PaletteMod*, const byte*) override; // Only for HiRes fonts. Not implemented here.
- Common::Point getMousePos() const override;
- void setMousePos(const Common::Point &pos) const override;
- void setShakePos(int shakeXOffset, int shakeYOffset) const override;
- void clearRect(const Common::Rect &r) const override;
- Common::Point getRealCoords(Common::Point &pos) const override;
- bool supportsPalIntensity() const override { return false; }
- bool supportsHiResGraphics() const override { return false; }
- bool driverBasedTextRendering() const override { return false; }
- static bool validateMode(Common::Platform p) { return (p == Common::kPlatformDOS || p == Common::kPlatformWindows) && checkDriver(&_driverFile, 1); }
-protected:
- typedef void (*LineProc)(byte*&, const byte*, int, const byte*, const byte*, bool);
- LineProc _renderLine;
- const byte *_convPalette;
- uint16 _vScaleMult, _vScaleDiv;
- const byte *_egaMatchTable;
- byte *_egaColorPatterns;
- uint8 _colAdjust;
- byte *_compositeBuffer;
- byte *_currentPalette;
-private:
- virtual void loadData();
- virtual void renderBitmap(byte *dst, const byte *src, int pitch, int y, int w, int h, const byte *patterns, const byte *palette, uint16 &realWidth, uint16 &realHeight);
- byte *_currentBitmap;
- const byte *_internalPalette;
- const bool _requestRGBMode;
- static const char *_driverFile;
-};
-
-class UpscaledGfxDriver : public GfxDefaultDriver {
-public:
- UpscaledGfxDriver(int16 textAlignX, bool scaleCursor, bool rgbRendering);
- ~UpscaledGfxDriver() override;
- void initScreen(const Graphics::PixelFormat *format) override;
- void setPalette(const byte *colors, uint start, uint num, bool update, const PaletteMod *palMods, const byte *palModMapping) override;
- void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) override;
- void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
- Common::Point getMousePos() const override;
- void setMousePos(const Common::Point &pos) const override;
- void setShakePos(int shakeXOffset, int shakeYOffset) const override;
- void clearRect(const Common::Rect &r) const override;
- Common::Point getRealCoords(Common::Point &pos) const override;
- void drawTextFontGlyph(const byte *src, int pitch, int hiresDestX, int hiresDestY, int hiresW, int hiresH, int transpColor, const PaletteMod *palMods, const byte *palModMapping) override; // For HiRes fonts. PC-98 versions bypass the video driver for this and render directly on top of the vram.
- bool driverBasedTextRendering() const override { return true; }
-protected:
- UpscaledGfxDriver(uint16 scaledW, uint16 scaledH, int16 textAlignX, bool scaleCursor, bool rgbRendering);
- void updateScreen(int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping);
- void adjustCursorBuffer(uint16 newWidth, uint16 newHeight);
- typedef void (*GlyphRenderProc)(byte*, int, const byte*, int, int, int, int);
- GlyphRenderProc _renderGlyph;
- typedef void (*ScaledRenderProc)(byte*, const byte*, int, int, int);
- ScaledRenderProc _renderScaled;
- uint16 _textAlignX;
- uint16 _hScaleMult;
- uint16 _vScaleMult;
- uint16 _vScaleDiv;
- byte *_scaledBitmap;
-private:
- virtual void renderBitmap(const byte *src, int pitch, int dx, int dy, int w, int h, int &realWidth, int &realHeight);
- const bool _scaleCursor;
- uint16 _cursorWidth;
- uint16 _cursorHeight;
- bool _needCursorBuffer;
-};
-
-class WindowsGfx256ColorsDriver final : public UpscaledGfxDriver {
-public:
- WindowsGfx256ColorsDriver(bool coloredDosStyleCursors, bool smallWindow, bool rgbRendering);
- ~WindowsGfx256ColorsDriver() override {}
- void initScreen(const Graphics::PixelFormat *format) override;
- void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) override;
- void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
- Common::Point getRealCoords(Common::Point &pos) const override;
- void setColorMap(const byte *colorMap) override { _colorMap = colorMap; }
- void setFlags(uint32 flags) override;
- void clearFlags(uint32 flags) override;
- bool supportsHiResGraphics() const override { return !_smallWindow; }
-protected:
- typedef void (*LineProc)(byte*&, const byte*, int, int, int);
- LineProc _renderLine;
-private:
- typedef void (*LineProcSpec)(byte*&, const byte*, int, int, const byte*);
- LineProcSpec _renderLine2;
- void renderBitmap(const byte *src, int pitch, int dx, int dy, int w, int h, int &realWidth, int &realHeight) override;
- uint32 _flags;
- const byte *_colorMap;
- const bool _smallWindow;
- const bool _dosStyleCursors;
- uint16 _vScaleMult2;
-};
-
-class WindowsGfx16ColorsDriver final : public SCI1_EGADriver {
-public:
- // The original does not take into account the extra lines required for the 200->440 vertical scaling. There is a noticeable dithering glitch every 11th line, as the
- // two pixels of the checkerbox pattern appear in the wrong order. I have implemented a fix for this which can be activated with the fixDithering parameter.
- WindowsGfx16ColorsDriver(bool fixDithering, bool rgbRendering);
- ~WindowsGfx16ColorsDriver() override {}
- void initScreen(const Graphics::PixelFormat *format) override;
- void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
- Common::Point getRealCoords(Common::Point &pos) const override;
- static bool validateMode(Common::Platform p) { return (p == Common::kPlatformWindows && checkDriver(&_driverFile, 1)); }
-private:
- void loadData() override;
- void renderBitmap(byte *dst, const byte *src, int pitch, int y, int w, int h, const byte *patterns, const byte *palette, uint16 &realWidth, uint16 &realHeight) override;
- LineProc _renderLine2;
- const bool _enhancedDithering;
- static const char *_driverFile;
-};
-
-class PC98Gfx16ColorsDriver final : public UpscaledGfxDriver {
-public:
- enum SjisFontStyle {
- kFontStyleNone,
- kFontStyleTextMode,
- kFontStyleSpecialSCI1
- };
-
- PC98Gfx16ColorsDriver(int textAlignX, bool cursorScaleWidth, bool cursorScaleHeight, SjisFontStyle sjisFontStyle, bool rgbRendering, bool needsUnditheringPalette);
- ~PC98Gfx16ColorsDriver() override;
- void initScreen(const Graphics::PixelFormat *format) override;
- void setPalette(const byte*, uint, uint, bool, const PaletteMod*, const byte*) override {}
- void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
- byte remapTextColor(byte color) const override;
-private:
- const byte *_convPalette;
- const byte *_textModePalette;
- const bool _cursorScaleHeightOnly;
- SjisFontStyle _fontStyle;
-};
-
-class SCI0_PC98Gfx8ColorsDriver final : public UpscaledGfxDriver {
-public:
- SCI0_PC98Gfx8ColorsDriver(bool cursorScaleHeight, bool useTextModeForSJISChars, bool rgbRendering);
- ~SCI0_PC98Gfx8ColorsDriver() override;
- void initScreen(const Graphics::PixelFormat *format) override;
- void setPalette(const byte*, uint, uint, bool, const PaletteMod*, const byte*) override {}
- void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
- byte remapTextColor(byte color) const override;
- static bool validateMode(Common::Platform p) { return (p == Common::kPlatformPC98) && checkDriver(_driverFiles, 2); }
-private:
- const byte *_convPalette;
- const bool _cursorScaleHeightOnly;
- const bool _useTextMode;
- static const char *_driverFiles[2];
-};
-
-class SCI1_PC98Gfx8ColorsDriver final : public UpscaledGfxDriver {
-public:
- SCI1_PC98Gfx8ColorsDriver(bool rgbRendering);
- ~SCI1_PC98Gfx8ColorsDriver() override;
- void initScreen(const Graphics::PixelFormat *format) override;
- void setPalette(const byte*, uint, uint, bool, const PaletteMod*, const byte*) override {}
- void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) override;
- void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
- byte remapTextColor(byte) const override;
- static bool validateMode(Common::Platform p) { return (p == Common::kPlatformPC98) && checkDriver(&_driverFile, 1); }
-private:
- const byte *_ditheringTable;
- const byte *_convPalette;
- static const char *_driverFile;
-};
-
-} // End of namespace Sci
-
-#endif // SCI_GRAPHICS_GFXDRIVERS_H
diff --git a/engines/sci/graphics/maciconbar.cpp b/engines/sci/graphics/maciconbar.cpp
index 27017b6834a..c384958607c 100644
--- a/engines/sci/graphics/maciconbar.cpp
+++ b/engines/sci/graphics/maciconbar.cpp
@@ -23,7 +23,7 @@
#include "sci/engine/kernel.h"
#include "sci/engine/selector.h"
#include "sci/engine/state.h"
-#include "sci/graphics/gfxdrivers.h"
+#include "sci/graphics/drivers/gfxdriver.h"
#include "sci/graphics/maciconbar.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/screen.h"
diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp
index 977470c548e..c57b2d5ce6f 100644
--- a/engines/sci/graphics/paint16.cpp
+++ b/engines/sci/graphics/paint16.cpp
@@ -33,7 +33,7 @@
#include "sci/graphics/picture.h"
#include "sci/graphics/view.h"
#include "sci/graphics/screen.h"
-#include "sci/graphics/gfxdrivers.h"
+#include "sci/graphics/drivers/gfxdriver.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/portrait.h"
#include "sci/graphics/text16.h"
diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp
index 85a9bd12686..ad75722e27f 100644
--- a/engines/sci/graphics/palette.cpp
+++ b/engines/sci/graphics/palette.cpp
@@ -27,7 +27,7 @@
#include "sci/sci.h"
#include "sci/engine/state.h"
#include "sci/graphics/cache.h"
-#include "sci/graphics/gfxdrivers.h"
+#include "sci/graphics/drivers/gfxdriver.h"
#include "sci/graphics/maciconbar.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/remap.h"
diff --git a/engines/sci/graphics/portrait.cpp b/engines/sci/graphics/portrait.cpp
index 5e4f28c95f8..62af1c70b2b 100644
--- a/engines/sci/graphics/portrait.cpp
+++ b/engines/sci/graphics/portrait.cpp
@@ -26,7 +26,7 @@
#include "sci/sci.h"
#include "sci/event.h"
#include "sci/engine/state.h"
-#include "sci/graphics/gfxdrivers.h"
+#include "sci/graphics/drivers/gfxdriver.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/portrait.h"
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index 02412073f88..0ac7f3947f2 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -34,7 +34,7 @@
#include "sci/graphics/view.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/scifx.h"
-#include "sci/graphics/gfxdrivers.h"
+#include "sci/graphics/drivers/gfxdriver.h"
namespace Sci {
@@ -143,84 +143,7 @@ GfxScreen::GfxScreen(ResourceManager *resMan, Common::RenderMode renderMode) : _
}
}
- bool enablePaletteMods = ConfMan.hasKey("palette_mods") && ConfMan.getBool("palette_mods");
- bool requestRGB = enablePaletteMods || (ConfMan.hasKey("rgb_rendering") && ConfMan.getBool("rgb_rendering"));
-
- _gfxDrv = nullptr;
- switch (renderMode) {
- case Common::kRenderCGA:
- _gfxDrv = new SCI0_CGADriver(false, requestRGB);
- break;
- case Common::kRenderCGA_BW:
- _gfxDrv = new SCI0_CGABWDriver(0xffffff, requestRGB);
- break;
- case Common::kRenderHercA:
- case Common::kRenderHercG:
- _gfxDrv = new SCI0_HerculesDriver(renderMode == Common::kRenderHercG ? 0x66ff66 : 0xffbf66, requestRGB, false);
- break;
- case Common::kRenderEGA:
- if (getSciVersion() > SCI_VERSION_1_EGA_ONLY)
- _gfxDrv = new SCI1_EGADriver(requestRGB);
- break;
- case Common::kRenderVGAGrey:
- _gfxDrv = new SCI1_VGAGreyScaleDriver(requestRGB);
- break;
- case Common::kRenderWin16c:
- _gfxDrv = new WindowsGfx16ColorsDriver(true, requestRGB);
- break;
- case Common::kRenderPC98_8c:
- if (g_sci->getGameId() == GID_PQ2)
- // PQ2 is a bit special, probably the oldest of the PC-98 ports. Unlike all the others, it uses text mode print
- // and it doesn't even have a 16 colors drivers. See comment below...
- _gfxDrv = new SCI0_PC98Gfx8ColorsDriver(true, true, requestRGB);
- else if (getSciVersion() <= SCI_VERSION_01)
- _gfxDrv = new SCI0_PC98Gfx8ColorsDriver(false, false, requestRGB);
- else
- _gfxDrv = new SCI1_PC98Gfx8ColorsDriver(requestRGB);
- _hiresGlyphBuffer = new byte[16 * 16]();
- break;
- default:
- break;
- }
-
- if (_gfxDrv == nullptr) {
- switch (g_sci->getPlatform()) {
- case Common::kPlatformPC98:
- if (g_sci->getGameId() == GID_PQ2)
- // PQ2 is a bit special, probably the oldest of the PC-98 ports. Unlike all the others, it uses text mode print,
- // so the text color is a system color outside the normal 16 colors palette. The original does not even have a
- // 16 colors mode driver. Only the 8 colors mode, where the colors are identical for text and graphics mode.
- // But we do want to provide the 16 colors mode, since it is not a big deal (i.e., it does not require data
- // from a driver file and the fat print is also already there for the 8 colors mode). So we just make the
- // necessary adjustments.
- _gfxDrv = new PC98Gfx16ColorsDriver(8, false, true, PC98Gfx16ColorsDriver::kFontStyleTextMode, requestRGB, ConfMan.getBool("disable_dithering"));
- else if (getSciVersion() <= SCI_VERSION_01)
- _gfxDrv = new PC98Gfx16ColorsDriver(8, false, false, PC98Gfx16ColorsDriver::kFontStyleNone, requestRGB, true);
- else
- _gfxDrv = new PC98Gfx16ColorsDriver(1, true, true, PC98Gfx16ColorsDriver::kFontStyleSpecialSCI1, requestRGB, true);
- break;
-
- case Common::kPlatformWindows:
- case Common::kPlatformDOS:
- // King's Quest 6 has hires content in the Windows version which we also allow to be optionally enabled in the DOS version
- // and which we also optionally allow to be disabled in the Windows version. Also, the Windows versions of King's Quest 6
- // and Space Quest 4 have support in the original interpreter code for a small 320 x 240 window on desktops with resolutions
- // of less than 640 x 480, but I haven't managed to produce it in a Win95 VM; the windows setting don't seem to allow less
- // than 640 x 480, so I don't know if it is actually possible to set it up. Anyway, we can use it here, for the configs that
- // do not require hires support.
- if ((g_sci->getGameId() == GID_KQ6 || g_sci->getGameId() == GID_SQ4) && (g_sci->getPlatform() == Common::kPlatformWindows || g_sci->useHiresGraphics())) {
- _gfxDrv = new WindowsGfx256ColorsDriver(!ConfMan.getBool("windows_cursors"), !g_sci->useHiresGraphics(), requestRGB);
- break;
- }
- // fallthrough
- default:
- if (g_sci->getLanguage() == Common::KO_KOR)
- _gfxDrv = new UpscaledGfxDriver(1, true, requestRGB);
- else // The driver has to be told if is SCI_VERSION_01, since that cannot be determined from the number of colors.
- _gfxDrv = new GfxDefaultDriver(_displayWidth, _displayHeight + extraHeight, getSciVersion() < SCI_VERSION_01, requestRGB);
- break;
- }
- }
+ _gfxDrv = SciGfxDriver::create(renderMode, _displayWidth, _displayHeight + extraHeight);
assert(_gfxDrv);
// Buffer for rendering a single two-byte character
@@ -265,7 +188,7 @@ GfxScreen::GfxScreen(ResourceManager *resMan, Common::RenderMode renderMode) : _
}
// Set up palette mods if requested
- if (enablePaletteMods)
+ if (ConfMan.hasKey("palette_mods") && ConfMan.getBool("palette_mods"))
setupCustomPaletteMods(this);
// Initialize the actual screen
diff --git a/engines/sci/graphics/transitions.cpp b/engines/sci/graphics/transitions.cpp
index bfd144a71d6..58b935e462d 100644
--- a/engines/sci/graphics/transitions.cpp
+++ b/engines/sci/graphics/transitions.cpp
@@ -25,7 +25,7 @@
#include "sci/sci.h"
#include "sci/engine/state.h"
-#include "sci/graphics/gfxdrivers.h"
+#include "sci/graphics/drivers/gfxdriver.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/transitions.h"
diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp
index 25b84f65cf3..dd87ed973b1 100644
--- a/engines/sci/graphics/view.cpp
+++ b/engines/sci/graphics/view.cpp
@@ -21,7 +21,7 @@
#include "sci/sci.h"
#include "sci/engine/state.h"
-#include "sci/graphics/gfxdrivers.h"
+#include "sci/graphics/drivers/gfxdriver.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/remap.h"
diff --git a/engines/sci/module.mk b/engines/sci/module.mk
index 51b3a2d8b9c..8801ea412e3 100644
--- a/engines/sci/module.mk
+++ b/engines/sci/module.mk
@@ -50,7 +50,6 @@ MODULE_OBJS := \
graphics/cursor.o \
graphics/fontkorean.o \
graphics/fontsjis.o \
- graphics/gfxdrivers.o \
graphics/macfont.o \
graphics/maciconbar.o \
graphics/menu.o \
@@ -66,6 +65,20 @@ MODULE_OBJS := \
graphics/text16.o \
graphics/transitions.o \
graphics/view.o \
+ graphics/drivers/cga.o \
+ graphics/drivers/cgabw.o \
+ graphics/drivers/common.o \
+ graphics/drivers/default.o \
+ graphics/drivers/ega.o \
+ graphics/drivers/hercules.o \
+ graphics/drivers/init.o \
+ graphics/drivers/pc98_8col_sci0.o \
+ graphics/drivers/pc98_8col_sci1.o \
+ graphics/drivers/pc98_16col.o \
+ graphics/drivers/upscaled.o \
+ graphics/drivers/vgagrey.o \
+ graphics/drivers/win16col.o \
+ graphics/drivers/win256col.o \
parser/grammar.o \
parser/said.o \
parser/vocabulary.o \
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 9334370bbef..41007473fe9 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -54,7 +54,7 @@
#include "sci/graphics/controls16.h"
#include "sci/graphics/coordadjuster.h"
#include "sci/graphics/cursor.h"
-#include "sci/graphics/gfxdrivers.h"
+#include "sci/graphics/drivers/gfxdriver.h"
#include "sci/graphics/macfont.h"
#include "sci/graphics/maciconbar.h"
#include "sci/graphics/menu.h"
@@ -319,29 +319,11 @@ Common::Error SciEngine::run() {
}
if (getSciVersion() < SCI_VERSION_2) {
- Common::RenderMode renderMode = Common::kRenderDefault;
-
bool undither = ConfMan.getBool("disable_dithering");
- if (ConfMan.hasKey("render_mode"))
- renderMode = Common::parseRenderMode(ConfMan.get("render_mode"));
-
- // Check if the selected render mode is available for the game. This is quite specific for each game.
- // Sometime it is only EGA, sometimes only CGA b/w without CGA 4 colors, etc. Also set default mode if undithering is enabled.
- Common::Platform p = getPlatform();
- if ((renderMode == Common::kRenderEGA && (((getSciVersion() <= SCI_VERSION_0_LATE || getSciVersion() == SCI_VERSION_1_EGA_ONLY) && undither) ||
- (getSciVersion() >= SCI_VERSION_1_EARLY && getSciVersion() <= SCI_VERSION_1_1 && !SCI1_EGADriver::validateMode(p)))) ||
- (renderMode == Common::kRenderVGAGrey && !SCI1_VGAGreyScaleDriver::validateMode(p)) ||
- (renderMode == Common::kRenderCGA && !SCI0_CGADriver::validateMode(p)) ||
- (renderMode == Common::kRenderCGA_BW && !SCI0_CGABWDriver::validateMode(p)) ||
- ((renderMode == Common::kRenderHercA || renderMode == Common::kRenderHercG) && !SCI0_HerculesDriver::validateMode(p)) ||
- (renderMode == Common::kRenderPC98_8c && ((getSciVersion() <= SCI_VERSION_01 && !SCI0_PC98Gfx8ColorsDriver::validateMode(p)) ||
- (getSciVersion() > SCI_VERSION_01 && !SCI1_PC98Gfx8ColorsDriver::validateMode(p)))) ||
- (renderMode == Common::kRenderWin16c && getSciVersion() >= SCI_VERSION_1_1 && !WindowsGfx16ColorsDriver::validateMode(p)) ||
- (renderMode == Common::kRenderPC98_16c && undither) ||
- (getLanguage() == Common::KO_KOR)) // No extra modes supported for the Korean fan-patched games
- renderMode = Common::kRenderDefault;
-
- // Disable undithering for CGA, Hercules and other unsuitable video modes
+ Common::RenderMode renderMode = SciGfxDriver::getRenderMode();
+
+ // Disable undithering for CGA, Hercules and other unsuitable video modes. The render mode should have been set to
+ // kRenderDefault by determineRenderMode() if undithering is selected, but we want to make sure that this matches.
if (renderMode != Common::kRenderDefault)
undither = false;
More information about the Scummvm-git-logs
mailing list