aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorThierry Crozat2018-06-03 17:41:47 +0100
committerGitHub2018-06-03 17:41:47 +0100
commit4229e2642ef33f761528cc5811726df56f3a42d0 (patch)
tree05e7f223bd939694b5a72299e919c5aea5cf3a9a /engines
parente10c33fc2028a618c25a6bccbf6c90f2f2fa525d (diff)
parent999cf71dcf4ac9466915edd55a9c91094db1a99c (diff)
downloadscummvm-rg350-4229e2642ef33f761528cc5811726df56f3a42d0.tar.gz
scummvm-rg350-4229e2642ef33f761528cc5811726df56f3a42d0.tar.bz2
scummvm-rg350-4229e2642ef33f761528cc5811726df56f3a42d0.zip
Merge pull request #1141 from DanielSWolf/larryscale
SCI: High-quality "LarryScale" cel scaler for LSL7
Diffstat (limited to 'engines')
-rw-r--r--engines/sci/detection.cpp10
-rw-r--r--engines/sci/detection_tables.h5
-rw-r--r--engines/sci/graphics/celobj32.cpp107
-rw-r--r--engines/sci/sci.h1
4 files changed, 98 insertions, 25 deletions
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 9a70429e47..b0d78f753d 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -437,6 +437,16 @@ static const ADExtraGuiOptionsMap optionsList[] = {
#endif
{
+ GAMEOPTION_LARRYSCALE,
+ {
+ _s("Use high-quality \"LarryScale\" cel scaling"),
+ _s("Use special cartoon scaler for drawing character sprites"),
+ "enable_larryscale",
+ true
+ }
+ },
+
+ {
GAMEOPTION_PREFER_DIGITAL_SFX,
{
_s("Prefer digital sound effects"),
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index e9fba208e4..b908d5b964 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -2733,11 +2733,12 @@ static const struct ADGameDescription SciGameDescriptions[] = {
#define GUIO_LSL7_DEMO GUIO3(GUIO_NOASPECT, \
GUIO_NOMIDI, \
GUIO_NOLAUNCHLOAD)
-#define GUIO_LSL7 GUIO5(GUIO_NOASPECT, \
+#define GUIO_LSL7 GUIO6(GUIO_NOASPECT, \
GUIO_NOMIDI, \
GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
GAMEOPTION_ORIGINAL_SAVELOAD, \
- GAMEOPTION_HQ_VIDEO)
+ GAMEOPTION_HQ_VIDEO, \
+ GAMEOPTION_LARRYSCALE)
// Larry 7 - English DOS Demo (provided by richiefs in bug report #2670691)
// SCI interpreter version 2.100.002
diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp
index fb7abe8a77..f11c75ab2b 100644
--- a/engines/sci/graphics/celobj32.cpp
+++ b/engines/sci/graphics/celobj32.cpp
@@ -31,6 +31,8 @@
#include "sci/graphics/text32.h"
#include "sci/engine/workarounds.h"
#include "sci/util.h"
+#include "graphics/larryScale.h"
+#include "common/config-manager.h"
namespace Sci {
#pragma mark CelScaler
@@ -154,6 +156,9 @@ struct SCALER_Scale {
#endif
const byte *_row;
READER _reader;
+ // If _sourceBuffer is set, it contains the full (possibly scaled) source
+ // image and takes precedence over _reader.
+ Common::SharedPtr<Buffer> _sourceBuffer;
int16 _x;
static int16 _valuesX[kCelScalerTableSize];
static int16 _valuesY[kCelScalerTableSize];
@@ -167,7 +172,8 @@ struct SCALER_Scale {
// The maximum width of the scaled object may not be as wide as the source
// data it requires if downscaling, so just always make the reader
// decompress an entire line of source data when scaling
- _reader(celObj, celObj._width) {
+ _reader(celObj, celObj._width),
+ _sourceBuffer() {
#ifndef NDEBUG
assert(_minX <= _maxX);
#endif
@@ -196,43 +202,98 @@ struct SCALER_Scale {
const CelScalerTable &table = CelObj::_scaler->getScalerTable(scaleX, scaleY);
- if (g_sci->_gfxFrameout->getScriptWidth() == kLowResX) {
- const int16 unscaledX = (scaledPosition.x / scaleX).toInt();
- if (FLIP) {
- const int lastIndex = celObj._width - 1;
- for (int16 x = targetRect.left; x < targetRect.right; ++x) {
- _valuesX[x] = lastIndex - (table.valuesX[x] - unscaledX);
+ const bool useLarryScale = ConfMan.getBool("enable_larryscale");
+ if (useLarryScale) {
+ // LarryScale is an alternative, high-quality cel scaler implemented
+ // for ScummVM. Due to the nature of smooth upscaling, it does *not*
+ // respect the global scaling pattern. Instead, it simply scales the
+ // cel to the extent of targetRect.
+
+ class Copier: public Graphics::RowReader, public Graphics::RowWriter {
+ READER &_souceReader;
+ Buffer &_targetBuffer;
+ public:
+ Copier(READER& souceReader, Buffer& targetBuffer) :
+ _souceReader(souceReader),
+ _targetBuffer(targetBuffer) {}
+ const Graphics::LarryScaleColor* readRow(int y) {
+ return _souceReader.getRow(y);
}
- } else {
- for (int16 x = targetRect.left; x < targetRect.right; ++x) {
- _valuesX[x] = table.valuesX[x] - unscaledX;
+ void writeRow(int y, const Graphics::LarryScaleColor* row) {
+ memcpy(_targetBuffer.getBasePtr(0, y), row, _targetBuffer.w);
}
+ };
+
+ // Scale the cel using LarryScale and write it to _sourceBuffer
+ // scaledImageRect is not necessarily identical to targetRect
+ // because targetRect may be cropped to render only a segment.
+ Common::Rect scaledImageRect(
+ scaledPosition.x,
+ scaledPosition.y,
+ scaledPosition.x + (celObj._width * scaleX).toInt(),
+ scaledPosition.y + (celObj._height * scaleY).toInt());
+ _sourceBuffer = Common::SharedPtr<Buffer>(new Buffer(), Graphics::SurfaceDeleter());
+ _sourceBuffer->create(
+ scaledImageRect.width(), scaledImageRect.height(),
+ Graphics::PixelFormat::createFormatCLUT8());
+ Copier copier(_reader, *_sourceBuffer);
+ Graphics::larryScale(
+ celObj._width, celObj._height, celObj._skipColor, copier,
+ scaledImageRect.width(), scaledImageRect.height(), copier);
+
+ // Set _valuesX and _valuesY to reference the scaled image without additional scaling
+ for (int16 x = targetRect.left; x < targetRect.right; ++x) {
+ const int16 unsafeValue = FLIP
+ ? scaledImageRect.right - x - 1
+ : x - scaledImageRect.left;
+ _valuesX[x] = CLIP<int16>(unsafeValue, 0, scaledImageRect.width() - 1);
}
-
- const int16 unscaledY = (scaledPosition.y / scaleY).toInt();
for (int16 y = targetRect.top; y < targetRect.bottom; ++y) {
- _valuesY[y] = table.valuesY[y] - unscaledY;
+ const int16 unsafeValue = y - scaledImageRect.top;
+ _valuesY[y] = CLIP<int16>(unsafeValue, 0, scaledImageRect.height() - 1);
}
} else {
- if (FLIP) {
- const int lastIndex = celObj._width - 1;
- for (int16 x = targetRect.left; x < targetRect.right; ++x) {
- _valuesX[x] = lastIndex - table.valuesX[x - scaledPosition.x];
+ const bool useGlobalScaling = g_sci->_gfxFrameout->getScriptWidth() == kLowResX;
+ if (useGlobalScaling) {
+ const int16 unscaledX = (scaledPosition.x / scaleX).toInt();
+ if (FLIP) {
+ const int lastIndex = celObj._width - 1;
+ for (int16 x = targetRect.left; x < targetRect.right; ++x) {
+ _valuesX[x] = lastIndex - (table.valuesX[x] - unscaledX);
+ }
+ } else {
+ for (int16 x = targetRect.left; x < targetRect.right; ++x) {
+ _valuesX[x] = table.valuesX[x] - unscaledX;
+ }
+ }
+
+ const int16 unscaledY = (scaledPosition.y / scaleY).toInt();
+ for (int16 y = targetRect.top; y < targetRect.bottom; ++y) {
+ _valuesY[y] = table.valuesY[y] - unscaledY;
}
} else {
- for (int16 x = targetRect.left; x < targetRect.right; ++x) {
- _valuesX[x] = table.valuesX[x - scaledPosition.x];
+ if (FLIP) {
+ const int lastIndex = celObj._width - 1;
+ for (int16 x = targetRect.left; x < targetRect.right; ++x) {
+ _valuesX[x] = lastIndex - table.valuesX[x - scaledPosition.x];
+ }
+ } else {
+ for (int16 x = targetRect.left; x < targetRect.right; ++x) {
+ _valuesX[x] = table.valuesX[x - scaledPosition.x];
+ }
}
- }
- for (int16 y = targetRect.top; y < targetRect.bottom; ++y) {
- _valuesY[y] = table.valuesY[y - scaledPosition.y];
+ for (int16 y = targetRect.top; y < targetRect.bottom; ++y) {
+ _valuesY[y] = table.valuesY[y - scaledPosition.y];
+ }
}
}
}
inline void setTarget(const int16 x, const int16 y) {
- _row = _reader.getRow(_valuesY[y]);
+ _row = _sourceBuffer
+ ? static_cast<const byte *>( _sourceBuffer->getBasePtr(0, _valuesY[y]))
+ : _reader.getRow(_valuesY[y]);
_x = x;
assert(_x >= _minX && _x <= _maxX);
}
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index faa153221a..6245d186c6 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -58,6 +58,7 @@ namespace Sci {
#define GAMEOPTION_ENABLE_BLACK_LINED_VIDEO GUIO_GAMEOPTIONS9
#define GAMEOPTION_HQ_VIDEO GUIO_GAMEOPTIONS10
#define GAMEOPTION_ENABLE_CENSORING GUIO_GAMEOPTIONS11
+#define GAMEOPTION_LARRYSCALE GUIO_GAMEOPTIONS12
struct EngineState;
class Vocabulary;