mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-31 07:53:36 +00:00
Merge pull request #1141 from DanielSWolf/larryscale
SCI: High-quality "LarryScale" cel scaler for LSL7
This commit is contained in:
commit
4229e2642e
@ -84,6 +84,7 @@ const struct GameOpt {
|
||||
// "gameOption10" would be invalid here because it contains "gameOption1"
|
||||
{ GUIO_GAMEOPTIONS10, "gameOptionA" },
|
||||
{ GUIO_GAMEOPTIONS11, "gameOptionB" },
|
||||
{ GUIO_GAMEOPTIONS12, "gameOptionC" },
|
||||
|
||||
{ GUIO_NONE, nullptr }
|
||||
};
|
||||
|
@ -76,6 +76,7 @@
|
||||
#define GUIO_GAMEOPTIONS9 "\060"
|
||||
#define GUIO_GAMEOPTIONS10 "\061"
|
||||
#define GUIO_GAMEOPTIONS11 "\062"
|
||||
#define GUIO_GAMEOPTIONS12 "\063"
|
||||
|
||||
#define GUIO0() (GUIO_NONE)
|
||||
#define GUIO1(a) (a)
|
||||
|
@ -436,6 +436,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,
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
} else {
|
||||
for (int16 x = targetRect.left; x < targetRect.right; ++x) {
|
||||
_valuesX[x] = 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.
|
||||
|
||||
const int16 unscaledY = (scaledPosition.y / scaleY).toInt();
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
406
graphics/larryScale.cpp
Normal file
406
graphics/larryScale.cpp
Normal file
@ -0,0 +1,406 @@
|
||||
/* 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 2
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "larryScale.h"
|
||||
#include <cassert>
|
||||
#include "common/array.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
typedef LarryScaleColor Color;
|
||||
|
||||
const int kMargin = 2;
|
||||
|
||||
// A bitmap that has a margin of `kMargin` pixels all around it.
|
||||
// Allows fast access without time-consuming bounds checking.
|
||||
template<typename T>
|
||||
class MarginedBitmap {
|
||||
int _width;
|
||||
int _height;
|
||||
int _stride;
|
||||
Common::Array<T> _buffer;
|
||||
T *_origin;
|
||||
|
||||
public:
|
||||
MarginedBitmap(int width, int height, T marginValue) :
|
||||
_width(width),
|
||||
_height(height),
|
||||
_stride(width + 2 * kMargin),
|
||||
_buffer(_stride * (height + 2 * kMargin)),
|
||||
_origin(calculateOrigin())
|
||||
{
|
||||
fillMargin(marginValue);
|
||||
}
|
||||
|
||||
// We need a custom copy constructor.
|
||||
// Otherwise, _origin would point to the original buffer.
|
||||
MarginedBitmap(const MarginedBitmap &rhs) :
|
||||
_width(rhs._width),
|
||||
_height(rhs._height),
|
||||
_stride(rhs._stride),
|
||||
_buffer(rhs._buffer),
|
||||
_origin(calculateOrigin())
|
||||
{}
|
||||
|
||||
// We need a custom assignment operator.
|
||||
// Otherwise, _origin would point to the original buffer.
|
||||
MarginedBitmap &operator =(const MarginedBitmap &rhs) {
|
||||
_width = rhs._width;
|
||||
_height = rhs._height;
|
||||
_stride = rhs._stride;
|
||||
_buffer = rhs._buffer;
|
||||
_origin = calculateOrigin();
|
||||
return this;
|
||||
}
|
||||
|
||||
int getWidth() const { return _width; }
|
||||
int getHeight() const { return _height; }
|
||||
int getStride() const { return _stride; }
|
||||
const T *getOrigin() const { return _origin; }
|
||||
T *getOrigin() { return _origin; }
|
||||
|
||||
const T *getPointerTo(int x, int y) const {
|
||||
return _origin + y * _stride + x;
|
||||
}
|
||||
T *getPointerTo(int x, int y) {
|
||||
return _origin + y * _stride + x;
|
||||
}
|
||||
|
||||
T get(int x, int y) const {
|
||||
return _origin[y * _stride + x];
|
||||
}
|
||||
void set(int x, int y, T value) {
|
||||
_origin[y * _stride + x] = value;
|
||||
}
|
||||
|
||||
void fillMargin(T value);
|
||||
|
||||
private:
|
||||
T *calculateOrigin() {
|
||||
return _buffer.data() + kMargin * _stride + kMargin;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void MarginedBitmap<T>::fillMargin(T value) {
|
||||
T * const data = getOrigin();
|
||||
const int stride = getStride();
|
||||
|
||||
// Fill top margin
|
||||
for (int y = -kMargin; y < 0; ++y) {
|
||||
for (int x = -kMargin; x < _width + kMargin; ++x) {
|
||||
data[y * stride + x] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill sideways margins
|
||||
for (int y = 0; y < _height; ++y) {
|
||||
for (int x = -kMargin; x < 0; ++x) {
|
||||
data[y * stride + x] = value;
|
||||
}
|
||||
for (int x = _width; x < _width + kMargin; ++x) {
|
||||
data[y * stride + x] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill bottom margin
|
||||
for (int y = _height; y < _height + kMargin; ++y) {
|
||||
for (int x = -kMargin; x < _width + kMargin; ++x) {
|
||||
data[y * stride + x] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MarginedBitmap<Color> createMarginedBitmap(int width, int height, Color marginColor, RowReader &rowReader) {
|
||||
MarginedBitmap<Color> result(width, height, marginColor);
|
||||
for (int y = 0; y < height; ++y) {
|
||||
memcpy(result.getPointerTo(0, y), rowReader.readRow(y), width * sizeof(Color));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
class MarginedBitmapWriter : public RowWriter {
|
||||
MarginedBitmap<Color> &_target;
|
||||
public:
|
||||
explicit MarginedBitmapWriter(MarginedBitmap<Color> &target)
|
||||
: _target(target) {}
|
||||
|
||||
void writeRow(int y, const LarryScaleColor *row) {
|
||||
memcpy(_target.getPointerTo(0, y), row, _target.getWidth() * sizeof(Color));
|
||||
}
|
||||
};
|
||||
|
||||
inline bool isLinePixel(const MarginedBitmap<Color> &src, int x, int y) {
|
||||
#define EQUALS(xOffset, yOffset) (src.get(x + xOffset, y + yOffset) == pixel)
|
||||
|
||||
const Color pixel = src.get(x, y);
|
||||
|
||||
// Single pixels are fills
|
||||
if (!EQUALS(-1, -1) && !EQUALS(0, -1) && !EQUALS(1, -1) && !EQUALS(1, 0) && !EQUALS(1, 1) && !EQUALS(0, 1) && !EQUALS(-1, 1) && !EQUALS(-1, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2x2 blocks are fills
|
||||
if (EQUALS(0, -1) && EQUALS(1, -1) && EQUALS(1, 0)) return false;
|
||||
if (EQUALS(1, 0) && EQUALS(1, 1) && EQUALS(0, 1)) return false;
|
||||
if (EQUALS(0, 1) && EQUALS(-1, 1) && EQUALS(-1, 0)) return false;
|
||||
if (EQUALS(-1, 0) && EQUALS(-1, -1) && EQUALS(0, -1)) return false;
|
||||
|
||||
// A pixel adjacent to a 2x2 block is a fill.
|
||||
if (EQUALS(-1, -1) && EQUALS(0, -1) && EQUALS(-1, -2) && EQUALS(0, -2)) return false;
|
||||
if (EQUALS(0, -1) && EQUALS(1, -1) && EQUALS(0, -2) && EQUALS(1, -2)) return false;
|
||||
if (EQUALS(1, -1) && EQUALS(1, 0) && EQUALS(2, -1) && EQUALS(2, 0)) return false;
|
||||
if (EQUALS(1, 0) && EQUALS(1, 1) && EQUALS(2, 0) && EQUALS(2, 1)) return false;
|
||||
if (EQUALS(1, 1) && EQUALS(0, 1) && EQUALS(1, 2) && EQUALS(0, 2)) return false;
|
||||
if (EQUALS(0, 1) && EQUALS(-1, 1) && EQUALS(0, 2) && EQUALS(-1, 2)) return false;
|
||||
if (EQUALS(-1, 1) && EQUALS(-1, 0) && EQUALS(-2, 1) && EQUALS(-2, 0)) return false;
|
||||
if (EQUALS(-1, 0) && EQUALS(-1, -1) && EQUALS(-2, 0) && EQUALS(-2, -1)) return false;
|
||||
|
||||
// Everything else is part of a line
|
||||
return true;
|
||||
|
||||
#undef EQUALS
|
||||
}
|
||||
|
||||
MarginedBitmap<bool> createMarginedLinePixelsBitmap(const MarginedBitmap<Color> &src) {
|
||||
MarginedBitmap<bool> result(src.getWidth(), src.getHeight(), false);
|
||||
for (int y = 0; y < src.getHeight(); ++y) {
|
||||
for (int x = 0; x < src.getWidth(); ++x) {
|
||||
result.set(x, y, isLinePixel(src, x, y));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void scaleDown(
|
||||
const MarginedBitmap<Color> &src,
|
||||
Color transparentColor,
|
||||
int dstWidth, int dstHeight,
|
||||
RowWriter &rowWriter
|
||||
) {
|
||||
assert(src.getWidth() > 0);
|
||||
assert(src.getHeight() > 0);
|
||||
assert(dstWidth > 0 && dstWidth <= src.getWidth());
|
||||
assert(dstHeight > 0 && dstHeight <= src.getHeight());
|
||||
|
||||
Common::Array<Color> dstRow(dstWidth);
|
||||
for (int dstY = 0; dstY < dstHeight; ++dstY) {
|
||||
const int srcY1 = dstY * src.getHeight() / dstHeight;
|
||||
const int srcY2 = (dstY + 1) * src.getHeight() / dstHeight;
|
||||
|
||||
for (int dstX = 0; dstX < dstWidth; ++dstX) {
|
||||
const int srcX1 = dstX * src.getWidth() / dstWidth;
|
||||
const int srcX2 = (dstX + 1) * src.getWidth() / dstWidth;
|
||||
|
||||
const int blockPixelCount = (srcX2 - srcX1) * (srcY2 - srcY1);
|
||||
if (blockPixelCount <= 4) {
|
||||
// Downscaling to 50% or more. Prefer line pixels.
|
||||
Color bestLineColor = 0;
|
||||
int linePixelCount = 0;
|
||||
for (int srcY = srcY1; srcY < srcY2; ++srcY) {
|
||||
for (int srcX = srcX1; srcX < srcX2; ++srcX) {
|
||||
const bool colorIsFromLine = isLinePixel(src, srcX, srcY);
|
||||
if (colorIsFromLine) {
|
||||
bestLineColor = src.get(srcX, srcY);
|
||||
++linePixelCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
const bool sufficientLinePixels = linePixelCount * 2 >= blockPixelCount;
|
||||
const Color resultColor = sufficientLinePixels
|
||||
? bestLineColor
|
||||
: src.get(srcX1, srcY1);
|
||||
dstRow[dstX] = resultColor;
|
||||
} else {
|
||||
// Downscaling significantly. Prefer outline pixels.
|
||||
Color bestColor = src.get(srcX1, srcY1);
|
||||
for (int srcY = srcY1; srcY < srcY2; ++srcY) {
|
||||
for (int srcX = srcX1; srcX < srcX2; ++srcX) {
|
||||
const Color pixelColor = src.get(srcX, srcY);
|
||||
const bool isOutlinePixel = pixelColor != transparentColor && (
|
||||
src.get(srcX - 1, srcY) == transparentColor
|
||||
|| src.get(srcX + 1, srcY) == transparentColor
|
||||
|| src.get(srcX, srcY - 1) == transparentColor
|
||||
|| src.get(srcX, srcY + 1) == transparentColor
|
||||
);
|
||||
if (isOutlinePixel) {
|
||||
bestColor = pixelColor;
|
||||
goto foundOutlinePixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
foundOutlinePixel:
|
||||
dstRow[dstX] = bestColor;
|
||||
}
|
||||
}
|
||||
rowWriter.writeRow(dstY, dstRow.data());
|
||||
}
|
||||
}
|
||||
|
||||
// An equality matrix is a combination of eight Boolean flags indicating whether
|
||||
// each of the surrounding pixels has the same color as the central pixel.
|
||||
//
|
||||
// +------+------+------+
|
||||
// | 0x02 | 0x04 | 0x08 |
|
||||
// +------+------+------+
|
||||
// | 0x01 | Ref. | 0x10 |
|
||||
// +------+------+------+
|
||||
// | 0x80 | 0x40 | 0x20 |
|
||||
// +------+------+------+
|
||||
typedef byte EqualityMatrix;
|
||||
|
||||
EqualityMatrix getEqualityMatrix(const Color *pixel, int stride) {
|
||||
#define EQUALS(x, y) (pixel[y * stride + x] == *pixel)
|
||||
|
||||
return (EQUALS(-1, 0) ? 0x01 : 0x00)
|
||||
| (EQUALS(-1, -1) ? 0x02 : 0x00)
|
||||
| (EQUALS(0, -1) ? 0x04 : 0x00)
|
||||
| (EQUALS(1, -1) ? 0x08 : 0x00)
|
||||
| (EQUALS(1, 0) ? 0x10 : 0x00)
|
||||
| (EQUALS(1, 1) ? 0x20 : 0x00)
|
||||
| (EQUALS(0, 1) ? 0x40 : 0x00)
|
||||
| (EQUALS(-1, 1) ? 0x80 : 0x00);
|
||||
|
||||
#undef EQUALS
|
||||
}
|
||||
|
||||
// scapeUp() requires generated functions
|
||||
#include "larryScale_generated.cpp"
|
||||
|
||||
void scaleUp(
|
||||
const MarginedBitmap<Color> &src,
|
||||
int dstWidth, int dstHeight,
|
||||
RowWriter &rowWriter
|
||||
) {
|
||||
const int srcWidth = src.getWidth();
|
||||
const int srcHeight = src.getHeight();
|
||||
|
||||
assert(srcWidth > 0);
|
||||
assert(srcHeight > 0);
|
||||
assert(dstWidth >= srcWidth && dstWidth <= 2 * src.getWidth());
|
||||
assert(dstHeight >= srcHeight && dstHeight <= 2 * src.getHeight());
|
||||
|
||||
const MarginedBitmap<bool> linePixels = createMarginedLinePixelsBitmap(src);
|
||||
Common::Array<Color> topDstRow(dstWidth);
|
||||
Common::Array<Color> bottomDstRow(dstWidth);
|
||||
for (int srcY = 0; srcY < src.getHeight(); ++srcY) {
|
||||
const int dstY1 = srcY * dstHeight / src.getHeight();
|
||||
const int dstY2 = (srcY + 1) * dstHeight / src.getHeight();
|
||||
const int dstBlockHeight = dstY2 - dstY1;
|
||||
|
||||
for (int srcX = 0; srcX < src.getWidth(); ++srcX) {
|
||||
const int dstX1 = srcX * dstWidth / src.getWidth();
|
||||
const int dstX2 = (srcX + 1) * dstWidth / src.getWidth();
|
||||
const int dstBlockWidth = dstX2 - dstX1;
|
||||
|
||||
if (dstBlockWidth == 1) {
|
||||
if (dstBlockHeight == 1) {
|
||||
// 1x1
|
||||
topDstRow[dstX1] = src.get(srcX, srcY);
|
||||
} else {
|
||||
// 1x2
|
||||
Color &top = topDstRow[dstX1];
|
||||
Color &bottom = bottomDstRow[dstX1];
|
||||
scalePixelTo1x2(src, linePixels, srcX, srcY, top, bottom);
|
||||
}
|
||||
} else {
|
||||
if (dstBlockHeight == 1) {
|
||||
// 2x1
|
||||
Color &left = topDstRow[dstX1];
|
||||
Color &right = topDstRow[dstX1 + 1];
|
||||
scalePixelTo2x1(src, linePixels, srcX, srcY, left, right);
|
||||
} else {
|
||||
// 2x2
|
||||
Color &topLeft = topDstRow[dstX1];
|
||||
Color &topRight = topDstRow[dstX1 + 1];
|
||||
Color &bottomLeft = bottomDstRow[dstX1];
|
||||
Color &bottomRight = bottomDstRow[dstX1 + 1];
|
||||
scalePixelTo2x2(src, linePixels, srcX, srcY, topLeft, topRight, bottomLeft, bottomRight);
|
||||
}
|
||||
}
|
||||
}
|
||||
rowWriter.writeRow(dstY1, topDstRow.data());
|
||||
if (dstBlockHeight == 2) {
|
||||
rowWriter.writeRow(dstY1 + 1, bottomDstRow.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void copyRows(int height, RowReader &rowReader, RowWriter &rowWriter) {
|
||||
for (int y = 0; y < height; ++y) {
|
||||
rowWriter.writeRow(y, rowReader.readRow(y));
|
||||
}
|
||||
}
|
||||
|
||||
void larryScale(
|
||||
const MarginedBitmap<Color> &src,
|
||||
Color transparentColor,
|
||||
int dstWidth, int dstHeight,
|
||||
RowWriter &rowWriter
|
||||
) {
|
||||
const int srcWidth = src.getWidth();
|
||||
const int srcHeight = src.getHeight();
|
||||
|
||||
if (
|
||||
(dstWidth > srcWidth && dstHeight < srcHeight) // Upscaling along x axis, downscaling along y axis
|
||||
|| (dstWidth < srcWidth && dstHeight > srcHeight) // Downscaling along x axis, upscaling along y axis
|
||||
|| (dstWidth > 2 * srcWidth) // Upscaling to more than 200% along x axis
|
||||
|| (dstHeight > 2 * srcHeight) // Upscaling to more than 200% along y axis
|
||||
) {
|
||||
// We can't handle these cases with a single upscale.
|
||||
// Let's do an intermediate scale.
|
||||
const int tmpWidth = CLIP(dstWidth, srcWidth, 2 * srcWidth);
|
||||
const int tmpHeight = CLIP(dstHeight, srcHeight, 2 * srcHeight);
|
||||
MarginedBitmap<Color> tmp(tmpWidth, tmpHeight, transparentColor);
|
||||
MarginedBitmapWriter writer = MarginedBitmapWriter(tmp);
|
||||
larryScale(src, transparentColor, tmpWidth, tmpHeight, writer);
|
||||
larryScale(tmp, transparentColor, dstWidth, dstHeight, rowWriter);
|
||||
} else if (dstWidth > srcWidth || dstHeight > srcHeight) {
|
||||
// Upscaling to no more than 200%
|
||||
scaleUp(src, dstWidth, dstHeight, rowWriter);
|
||||
} else {
|
||||
// Downscaling
|
||||
scaleDown(src, transparentColor, dstWidth, dstHeight, rowWriter);
|
||||
}
|
||||
}
|
||||
|
||||
void larryScale(
|
||||
int srcWidth, int srcHeight,
|
||||
Color transparentColor,
|
||||
RowReader &rowReader,
|
||||
int dstWidth, int dstHeight,
|
||||
RowWriter &rowWriter
|
||||
) {
|
||||
// Select the appropriate scaler
|
||||
if (srcWidth <= 0 || srcHeight <= 0 || dstWidth <= 0 || dstHeight <= 0) {
|
||||
// Nothing to do
|
||||
} else if (dstWidth == srcWidth && dstHeight == srcHeight) {
|
||||
copyRows(srcHeight, rowReader, rowWriter);
|
||||
} else {
|
||||
const MarginedBitmap<Color> src =
|
||||
createMarginedBitmap(srcWidth, srcHeight, transparentColor, rowReader);
|
||||
larryScale(src, transparentColor, dstWidth, dstHeight, rowWriter);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
82
graphics/larryScale.h
Normal file
82
graphics/larryScale.h
Normal file
@ -0,0 +1,82 @@
|
||||
/* 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 2
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_LARRYSCALE_H
|
||||
#define GRAPHICS_LARRYSCALE_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
/*
|
||||
|
||||
LarryScale is a bitmap scaler for cartoon images.
|
||||
|
||||
Features:
|
||||
|
||||
* Supports arbitrary scaling factors along both axes (but looks best between 50% and 200%).
|
||||
* When downscaling: preserves fine details.
|
||||
* When upscaling: keeps lines smooth, introducing very few block artifacts.
|
||||
* Does not introduce additional colors.
|
||||
|
||||
Limitations:
|
||||
|
||||
* Lines must not be anti-aliased and should be only one pixel wide.
|
||||
* Fills should be flat without gradients.
|
||||
|
||||
*/
|
||||
|
||||
typedef byte LarryScaleColor;
|
||||
|
||||
class RowReader {
|
||||
public:
|
||||
virtual const LarryScaleColor *readRow(int y) = 0;
|
||||
virtual ~RowReader() {}
|
||||
};
|
||||
|
||||
class RowWriter {
|
||||
public:
|
||||
virtual void writeRow(int y, const LarryScaleColor *row) = 0;
|
||||
virtual ~RowWriter() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param srcWidth The width, in pixels, of the original image
|
||||
* @param srcHeight The height, in pixels, of the original image
|
||||
* @param transparentColor The transparent color. Used for outline detection.
|
||||
* @param rowReader An object with a callback method for reading the lines of the original
|
||||
* image
|
||||
* @param dstWidth The width, in pixels, of the scaled target image
|
||||
* @param dstHeight The height, in pixels, of the scaled target image
|
||||
* @param rowWriter An object with a callback method accepting the lines of the target image
|
||||
*/
|
||||
void larryScale(
|
||||
int srcWidth, int srcHeight,
|
||||
LarryScaleColor transparentColor,
|
||||
RowReader &rowReader,
|
||||
int dstWidth, int dstHeight,
|
||||
RowWriter &rowWriter
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
639
graphics/larryScale_generated.cpp
Normal file
639
graphics/larryScale_generated.cpp
Normal file
@ -0,0 +1,639 @@
|
||||
/* 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 2
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
// This file was generated by larryScale_generator.js.
|
||||
// Do not edit directly! Instead, edit the generator script and run it.
|
||||
|
||||
inline void scalePixelTo2x2(
|
||||
const MarginedBitmap<Color> &src,
|
||||
const MarginedBitmap<bool> &linePixels,
|
||||
int x, int y,
|
||||
// Out parameters
|
||||
Color &topLeft, Color &topRight, Color &bottomLeft, Color &bottomRight
|
||||
) {
|
||||
const Color pixel = src.get(x, y);
|
||||
const EqualityMatrix matrix = getEqualityMatrix(src.getPointerTo(x, y), src.getStride());
|
||||
|
||||
// Note: There is a case label for every possible value, so we don't need a default label.
|
||||
switch (matrix) {
|
||||
case 0x00 /*⠀⠂⠀*/: case 0x07 /*⠃⠃⠀*/: case 0x17 /*⠃⠃⠂*/: case 0x1c /*⠀⠃⠃*/: case 0x1d /*⠂⠃⠃*/: case 0x1e /*⠁⠃⠃*/: case 0x1f /*⠃⠃⠃*/: case 0x27 /*⠃⠃⠄*/:
|
||||
case 0x2f /*⠃⠃⠅*/: case 0x37 /*⠃⠃⠆*/: case 0x3c /*⠀⠃⠇*/: case 0x3d /*⠂⠃⠇*/: case 0x3e /*⠁⠃⠇*/: case 0x3f /*⠃⠃⠇*/: case 0x47 /*⠃⠇⠀*/: case 0x4f /*⠃⠇⠁*/:
|
||||
case 0x50 /*⠀⠆⠂*/: case 0x51 /*⠂⠆⠂*/: case 0x52 /*⠁⠆⠂*/: case 0x54 /*⠀⠇⠂*/: case 0x55 /*⠂⠇⠂*/: case 0x57 /*⠃⠇⠂*/: case 0x5c /*⠀⠇⠃*/: case 0x5d /*⠂⠇⠃*/:
|
||||
case 0x5e /*⠁⠇⠃*/: case 0x5f /*⠃⠇⠃*/: case 0x67 /*⠃⠇⠄*/: case 0x6f /*⠃⠇⠅*/: case 0x70 /*⠀⠆⠆*/: case 0x71 /*⠂⠆⠆*/: case 0x72 /*⠁⠆⠆*/: case 0x73 /*⠃⠆⠆*/:
|
||||
case 0x74 /*⠀⠇⠆*/: case 0x75 /*⠂⠇⠆*/: case 0x76 /*⠁⠇⠆*/: case 0x77 /*⠃⠇⠆*/: case 0x78 /*⠀⠆⠇*/: case 0x79 /*⠂⠆⠇*/: case 0x7a /*⠁⠆⠇*/: case 0x7b /*⠃⠆⠇*/:
|
||||
case 0x7c /*⠀⠇⠇*/: case 0x7d /*⠂⠇⠇*/: case 0x7e /*⠁⠇⠇*/: case 0x7f /*⠃⠇⠇*/: case 0x97 /*⠇⠃⠂*/: case 0x9c /*⠄⠃⠃*/: case 0x9d /*⠆⠃⠃*/: case 0x9e /*⠅⠃⠃*/:
|
||||
case 0x9f /*⠇⠃⠃*/: case 0xa7 /*⠇⠃⠄*/: case 0xaa /*⠅⠂⠅*/: case 0xaf /*⠇⠃⠅*/: case 0xb7 /*⠇⠃⠆*/: case 0xbc /*⠄⠃⠇*/: case 0xbd /*⠆⠃⠇*/: case 0xbe /*⠅⠃⠇*/:
|
||||
case 0xbf /*⠇⠃⠇*/: case 0xc1 /*⠆⠆⠀*/: case 0xc5 /*⠆⠇⠀*/: case 0xc7 /*⠇⠇⠀*/: case 0xc9 /*⠆⠆⠁*/: case 0xcb /*⠇⠆⠁*/: case 0xcd /*⠆⠇⠁*/: case 0xcf /*⠇⠇⠁*/:
|
||||
case 0xd1 /*⠆⠆⠂*/: case 0xd3 /*⠇⠆⠂*/: case 0xd5 /*⠆⠇⠂*/: case 0xd7 /*⠇⠇⠂*/: case 0xd9 /*⠆⠆⠃*/: case 0xdb /*⠇⠆⠃*/: case 0xdc /*⠄⠇⠃*/: case 0xdd /*⠆⠇⠃*/:
|
||||
case 0xde /*⠅⠇⠃*/: case 0xdf /*⠇⠇⠃*/: case 0xe5 /*⠆⠇⠄*/: case 0xe7 /*⠇⠇⠄*/: case 0xe9 /*⠆⠆⠅*/: case 0xeb /*⠇⠆⠅*/: case 0xed /*⠆⠇⠅*/: case 0xef /*⠇⠇⠅*/:
|
||||
case 0xf0 /*⠄⠆⠆*/: case 0xf1 /*⠆⠆⠆*/: case 0xf2 /*⠅⠆⠆*/: case 0xf3 /*⠇⠆⠆*/: case 0xf4 /*⠄⠇⠆*/: case 0xf5 /*⠆⠇⠆*/: case 0xf6 /*⠅⠇⠆*/: case 0xf7 /*⠇⠇⠆*/:
|
||||
case 0xf8 /*⠄⠆⠇*/: case 0xf9 /*⠆⠆⠇*/: case 0xfa /*⠅⠆⠇*/: case 0xfb /*⠇⠆⠇*/: case 0xfc /*⠄⠇⠇*/: case 0xfd /*⠆⠇⠇*/: case 0xfe /*⠅⠇⠇*/: case 0xff /*⠇⠇⠇*/:
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
break;
|
||||
case 0xa4 /*⠄⠃⠄*/:
|
||||
topLeft = bottomLeft = bottomRight = pixel;
|
||||
topRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
break;
|
||||
case 0x29 /*⠂⠂⠅*/:
|
||||
topLeft = topRight = bottomRight = pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
break;
|
||||
case 0x92 /*⠅⠂⠂*/: case 0x94 /*⠄⠃⠂*/:
|
||||
topLeft = topRight = bottomLeft = pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
break;
|
||||
case 0x44 /*⠀⠇⠀*/: case 0x45 /*⠂⠇⠀*/:
|
||||
topLeft = bottomLeft = pixel;
|
||||
topRight = bottomRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
break;
|
||||
case 0x11 /*⠂⠂⠂*/: case 0x15 /*⠂⠃⠂*/:
|
||||
topLeft = topRight = pixel;
|
||||
bottomLeft = bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
break;
|
||||
case 0x49 /*⠂⠆⠁*/: case 0x4a /*⠁⠆⠁*/:
|
||||
topLeft = topRight = bottomLeft = pixel;
|
||||
bottomRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
break;
|
||||
case 0x53 /*⠃⠆⠂*/: case 0x56 /*⠁⠇⠂*/: case 0x59 /*⠂⠆⠃*/: case 0x5a /*⠁⠆⠃*/: case 0x5b /*⠃⠆⠃*/: case 0xd2 /*⠅⠆⠂*/: case 0xd4 /*⠄⠇⠂*/: case 0xd6 /*⠅⠇⠂*/:
|
||||
case 0xda /*⠅⠆⠃*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0xa8 /*⠄⠂⠅*/:
|
||||
topLeft = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
topRight = bottomLeft = bottomRight = pixel;
|
||||
break;
|
||||
case 0x8a /*⠅⠂⠁*/: case 0x8f /*⠇⠃⠁*/:
|
||||
topLeft = topRight = bottomLeft = pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
break;
|
||||
case 0x2a /*⠁⠂⠅*/:
|
||||
topLeft = topRight = bottomRight = pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
break;
|
||||
case 0xa2 /*⠅⠂⠄*/: case 0xe3 /*⠇⠆⠄*/:
|
||||
topLeft = bottomLeft = bottomRight = pixel;
|
||||
topRight = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
break;
|
||||
case 0x25 /*⠂⠃⠄*/:
|
||||
topLeft = bottomRight = pixel;
|
||||
topRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
break;
|
||||
case 0xa6 /*⠅⠃⠄*/: case 0xac /*⠄⠃⠅*/: case 0xae /*⠅⠃⠅*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = bottomLeft = bottomRight = pixel;
|
||||
topRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x13 /*⠃⠂⠂*/: case 0x19 /*⠂⠂⠃*/: case 0x1b /*⠃⠂⠃*/: case 0x31 /*⠂⠂⠆*/: case 0x33 /*⠃⠂⠆*/: case 0x35 /*⠂⠃⠆*/: case 0x39 /*⠂⠂⠇*/: case 0x3b /*⠃⠂⠇*/:
|
||||
case 0x91 /*⠆⠂⠂*/: case 0x93 /*⠇⠂⠂*/: case 0x95 /*⠆⠃⠂*/: case 0x99 /*⠆⠂⠃*/: case 0x9b /*⠇⠂⠃*/: case 0xb1 /*⠆⠂⠆*/: case 0xb3 /*⠇⠂⠆*/: case 0xb5 /*⠆⠃⠆*/:
|
||||
case 0xb9 /*⠆⠂⠇*/: case 0xbb /*⠇⠂⠇*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = topRight = pixel;
|
||||
bottomLeft = bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x96 /*⠅⠃⠂*/: case 0x9a /*⠅⠂⠃*/: case 0xb2 /*⠅⠂⠆*/: case 0xb4 /*⠄⠃⠆*/: case 0xb6 /*⠅⠃⠆*/: case 0xba /*⠅⠂⠇*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = topRight = bottomLeft = pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x4b /*⠃⠆⠁*/: case 0x69 /*⠂⠆⠅*/: case 0x6a /*⠁⠆⠅*/: case 0x6b /*⠃⠆⠅*/: case 0xca /*⠅⠆⠁*/: case 0xea /*⠅⠆⠅*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = topRight = bottomLeft = pixel;
|
||||
bottomRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x2b /*⠃⠂⠅*/: case 0xa9 /*⠆⠂⠅*/: case 0xab /*⠇⠂⠅*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = topRight = bottomRight = pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x46 /*⠁⠇⠀*/: case 0x4c /*⠀⠇⠁*/: case 0x4d /*⠂⠇⠁*/: case 0x4e /*⠁⠇⠁*/: case 0x64 /*⠀⠇⠄*/: case 0x65 /*⠂⠇⠄*/: case 0x66 /*⠁⠇⠄*/: case 0x6c /*⠀⠇⠅*/:
|
||||
case 0x6d /*⠂⠇⠅*/: case 0x6e /*⠁⠇⠅*/: case 0xc4 /*⠄⠇⠀*/: case 0xc6 /*⠅⠇⠀*/: case 0xcc /*⠄⠇⠁*/: case 0xce /*⠅⠇⠁*/: case 0xe4 /*⠄⠇⠄*/: case 0xe6 /*⠅⠇⠄*/:
|
||||
case 0xec /*⠄⠇⠅*/: case 0xee /*⠅⠇⠅*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = bottomLeft = pixel;
|
||||
topRight = bottomRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x24 /*⠀⠃⠄*/:
|
||||
topLeft = !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
topRight = bottomRight = pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
break;
|
||||
case 0x04 /*⠀⠃⠀*/: case 0x84 /*⠄⠃⠀*/: case 0x87 /*⠇⠃⠀*/:
|
||||
topLeft = bottomLeft = pixel;
|
||||
topRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
break;
|
||||
case 0x90 /*⠄⠂⠂*/:
|
||||
topLeft = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
topRight = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : pixel;
|
||||
bottomLeft = bottomRight = pixel;
|
||||
break;
|
||||
case 0x21 /*⠂⠂⠄*/: case 0xe1 /*⠆⠆⠄*/:
|
||||
topLeft = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : pixel;
|
||||
topRight = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomLeft = bottomRight = pixel;
|
||||
break;
|
||||
case 0x48 /*⠀⠆⠁*/:
|
||||
topLeft = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
topRight = bottomRight = pixel;
|
||||
bottomLeft = !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
break;
|
||||
case 0x01 /*⠂⠂⠀*/: case 0x09 /*⠂⠂⠁*/: case 0x0f /*⠃⠃⠁*/:
|
||||
topLeft = topRight = pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
break;
|
||||
case 0x10 /*⠀⠂⠂*/: case 0x12 /*⠁⠂⠂*/: case 0x14 /*⠀⠃⠂*/:
|
||||
topLeft = topRight = pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
break;
|
||||
case 0x40 /*⠀⠆⠀*/: case 0x41 /*⠂⠆⠀*/: case 0x42 /*⠁⠆⠀*/: case 0xc3 /*⠇⠆⠀*/:
|
||||
topLeft = bottomLeft = pixel;
|
||||
topRight = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
break;
|
||||
case 0xd8 /*⠄⠆⠃*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
topRight = bottomLeft = bottomRight = pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0xa0 /*⠄⠂⠄*/:
|
||||
topLeft = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
topRight = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomLeft = bottomRight = pixel;
|
||||
break;
|
||||
case 0x0a /*⠁⠂⠁*/:
|
||||
topLeft = topRight = pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
break;
|
||||
case 0x08 /*⠀⠂⠁*/: case 0x80 /*⠄⠂⠀*/: case 0x88 /*⠄⠂⠁*/:
|
||||
topLeft = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
topRight = bottomLeft = pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
break;
|
||||
case 0x28 /*⠀⠂⠅*/:
|
||||
topLeft = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
topRight = bottomRight = pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
break;
|
||||
case 0x02 /*⠁⠂⠀*/: case 0x20 /*⠀⠂⠄*/: case 0x22 /*⠁⠂⠄*/:
|
||||
topLeft = bottomRight = pixel;
|
||||
topRight = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
break;
|
||||
case 0x82 /*⠅⠂⠀*/:
|
||||
topLeft = bottomLeft = pixel;
|
||||
topRight = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
break;
|
||||
case 0x2d /*⠂⠃⠅*/: case 0xa5 /*⠆⠃⠄*/: case 0xad /*⠆⠃⠅*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = bottomRight = pixel;
|
||||
topRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x05 /*⠂⠃⠀*/:
|
||||
topLeft = pixel;
|
||||
topRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
break;
|
||||
case 0x68 /*⠀⠆⠅*/: case 0xc8 /*⠄⠆⠁*/: case 0xe8 /*⠄⠆⠅*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
topRight = bottomLeft = pixel;
|
||||
bottomRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x26 /*⠁⠃⠄*/: case 0x2c /*⠀⠃⠅*/: case 0x2e /*⠁⠃⠅*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = bottomRight = pixel;
|
||||
topRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0xc0 /*⠄⠆⠀*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = bottomLeft = pixel;
|
||||
topRight = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x18 /*⠀⠂⠃*/: case 0x1a /*⠁⠂⠃*/: case 0x30 /*⠀⠂⠆*/: case 0x32 /*⠁⠂⠆*/: case 0x36 /*⠁⠃⠆*/: case 0x38 /*⠀⠂⠇*/: case 0x3a /*⠁⠂⠇*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = topRight = pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x06 /*⠁⠃⠀*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = bottomLeft = pixel;
|
||||
topRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x98 /*⠄⠂⠃*/: case 0xb0 /*⠄⠂⠆*/: case 0xb8 /*⠄⠂⠇*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
topRight = bottomLeft = pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x58 /*⠀⠆⠃*/: case 0xd0 /*⠄⠆⠂*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
topRight = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : pixel;
|
||||
bottomLeft = !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
bottomRight = pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x16 /*⠁⠃⠂*/: case 0x34 /*⠀⠃⠆*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
topRight = pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = bottomRight = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x60 /*⠀⠆⠄*/: case 0x62 /*⠁⠆⠄*/: case 0x63 /*⠃⠆⠄*/: case 0xc2 /*⠅⠆⠀*/: case 0xe0 /*⠄⠆⠄*/: case 0xe2 /*⠅⠆⠄*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = bottomLeft = pixel;
|
||||
topRight = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
} else {
|
||||
topLeft = bottomLeft = bottomRight = pixel;
|
||||
topRight = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
}
|
||||
break;
|
||||
case 0x23 /*⠃⠂⠄*/: case 0xa1 /*⠆⠂⠄*/: case 0xa3 /*⠇⠂⠄*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = bottomRight = pixel;
|
||||
topRight = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
} else {
|
||||
topLeft = bottomLeft = bottomRight = pixel;
|
||||
topRight = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
}
|
||||
break;
|
||||
case 0x0b /*⠃⠂⠁*/: case 0x81 /*⠆⠂⠀*/: case 0x83 /*⠇⠂⠀*/: case 0x89 /*⠆⠂⠁*/: case 0x8b /*⠇⠂⠁*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = topRight = pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
}
|
||||
break;
|
||||
case 0x03 /*⠃⠂⠀*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = topRight = pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
} else {
|
||||
topLeft = bottomLeft = bottomRight = pixel;
|
||||
topRight = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
}
|
||||
break;
|
||||
case 0x0c /*⠀⠃⠁*/: case 0x0e /*⠁⠃⠁*/: case 0x86 /*⠅⠃⠀*/: case 0x8c /*⠄⠃⠁*/: case 0x8e /*⠅⠃⠁*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = bottomLeft = pixel;
|
||||
topRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
}
|
||||
break;
|
||||
case 0x0d /*⠂⠃⠁*/: case 0x85 /*⠆⠃⠀*/: case 0x8d /*⠆⠃⠁*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = pixel;
|
||||
topRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomLeft = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
} else {
|
||||
topLeft = topRight = bottomLeft = pixel;
|
||||
bottomRight = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
}
|
||||
break;
|
||||
case 0x43 /*⠃⠆⠀*/: case 0x61 /*⠂⠆⠄*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
topLeft = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : pixel;
|
||||
topRight = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottomLeft = pixel;
|
||||
bottomRight = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
} else {
|
||||
topLeft = bottomLeft = bottomRight = pixel;
|
||||
topRight = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void scalePixelTo2x1(
|
||||
const MarginedBitmap<Color> &src,
|
||||
const MarginedBitmap<bool> &linePixels,
|
||||
int x, int y,
|
||||
// Out parameters
|
||||
Color &left, Color &right
|
||||
) {
|
||||
const Color pixel = src.get(x, y);
|
||||
const EqualityMatrix matrix = getEqualityMatrix(src.getPointerTo(x, y), src.getStride());
|
||||
|
||||
// Note: There is a case label for every possible value, so we don't need a default label.
|
||||
switch (matrix) {
|
||||
case 0x00 /*⠀⠂⠀*/: case 0x01 /*⠂⠂⠀*/: case 0x02 /*⠁⠂⠀*/: case 0x07 /*⠃⠃⠀*/: case 0x08 /*⠀⠂⠁*/: case 0x09 /*⠂⠂⠁*/: case 0x0a /*⠁⠂⠁*/: case 0x0f /*⠃⠃⠁*/:
|
||||
case 0x10 /*⠀⠂⠂*/: case 0x11 /*⠂⠂⠂*/: case 0x12 /*⠁⠂⠂*/: case 0x14 /*⠀⠃⠂*/: case 0x15 /*⠂⠃⠂*/: case 0x17 /*⠃⠃⠂*/: case 0x1c /*⠀⠃⠃*/: case 0x1d /*⠂⠃⠃*/:
|
||||
case 0x1e /*⠁⠃⠃*/: case 0x1f /*⠃⠃⠃*/: case 0x20 /*⠀⠂⠄*/: case 0x21 /*⠂⠂⠄*/: case 0x22 /*⠁⠂⠄*/: case 0x25 /*⠂⠃⠄*/: case 0x27 /*⠃⠃⠄*/: case 0x29 /*⠂⠂⠅*/:
|
||||
case 0x2a /*⠁⠂⠅*/: case 0x2f /*⠃⠃⠅*/: case 0x37 /*⠃⠃⠆*/: case 0x3c /*⠀⠃⠇*/: case 0x3d /*⠂⠃⠇*/: case 0x3e /*⠁⠃⠇*/: case 0x3f /*⠃⠃⠇*/: case 0x47 /*⠃⠇⠀*/:
|
||||
case 0x49 /*⠂⠆⠁*/: case 0x4a /*⠁⠆⠁*/: case 0x4f /*⠃⠇⠁*/: case 0x50 /*⠀⠆⠂*/: case 0x51 /*⠂⠆⠂*/: case 0x52 /*⠁⠆⠂*/: case 0x54 /*⠀⠇⠂*/: case 0x55 /*⠂⠇⠂*/:
|
||||
case 0x57 /*⠃⠇⠂*/: case 0x5c /*⠀⠇⠃*/: case 0x5d /*⠂⠇⠃*/: case 0x5e /*⠁⠇⠃*/: case 0x5f /*⠃⠇⠃*/: case 0x67 /*⠃⠇⠄*/: case 0x6f /*⠃⠇⠅*/: case 0x70 /*⠀⠆⠆*/:
|
||||
case 0x71 /*⠂⠆⠆*/: case 0x72 /*⠁⠆⠆*/: case 0x73 /*⠃⠆⠆*/: case 0x74 /*⠀⠇⠆*/: case 0x75 /*⠂⠇⠆*/: case 0x76 /*⠁⠇⠆*/: case 0x77 /*⠃⠇⠆*/: case 0x78 /*⠀⠆⠇*/:
|
||||
case 0x79 /*⠂⠆⠇*/: case 0x7a /*⠁⠆⠇*/: case 0x7b /*⠃⠆⠇*/: case 0x7c /*⠀⠇⠇*/: case 0x7d /*⠂⠇⠇*/: case 0x7e /*⠁⠇⠇*/: case 0x7f /*⠃⠇⠇*/: case 0x80 /*⠄⠂⠀*/:
|
||||
case 0x88 /*⠄⠂⠁*/: case 0x8a /*⠅⠂⠁*/: case 0x8f /*⠇⠃⠁*/: case 0x90 /*⠄⠂⠂*/: case 0x92 /*⠅⠂⠂*/: case 0x94 /*⠄⠃⠂*/: case 0x97 /*⠇⠃⠂*/: case 0x9c /*⠄⠃⠃*/:
|
||||
case 0x9d /*⠆⠃⠃*/: case 0x9e /*⠅⠃⠃*/: case 0x9f /*⠇⠃⠃*/: case 0xa0 /*⠄⠂⠄*/: case 0xa2 /*⠅⠂⠄*/: case 0xa4 /*⠄⠃⠄*/: case 0xa7 /*⠇⠃⠄*/: case 0xa8 /*⠄⠂⠅*/:
|
||||
case 0xaa /*⠅⠂⠅*/: case 0xaf /*⠇⠃⠅*/: case 0xb7 /*⠇⠃⠆*/: case 0xbc /*⠄⠃⠇*/: case 0xbd /*⠆⠃⠇*/: case 0xbe /*⠅⠃⠇*/: case 0xbf /*⠇⠃⠇*/: case 0xc1 /*⠆⠆⠀*/:
|
||||
case 0xc5 /*⠆⠇⠀*/: case 0xc7 /*⠇⠇⠀*/: case 0xc9 /*⠆⠆⠁*/: case 0xcb /*⠇⠆⠁*/: case 0xcd /*⠆⠇⠁*/: case 0xcf /*⠇⠇⠁*/: case 0xd1 /*⠆⠆⠂*/: case 0xd3 /*⠇⠆⠂*/:
|
||||
case 0xd5 /*⠆⠇⠂*/: case 0xd7 /*⠇⠇⠂*/: case 0xd9 /*⠆⠆⠃*/: case 0xdb /*⠇⠆⠃*/: case 0xdc /*⠄⠇⠃*/: case 0xdd /*⠆⠇⠃*/: case 0xde /*⠅⠇⠃*/: case 0xdf /*⠇⠇⠃*/:
|
||||
case 0xe1 /*⠆⠆⠄*/: case 0xe3 /*⠇⠆⠄*/: case 0xe5 /*⠆⠇⠄*/: case 0xe7 /*⠇⠇⠄*/: case 0xe9 /*⠆⠆⠅*/: case 0xeb /*⠇⠆⠅*/: case 0xed /*⠆⠇⠅*/: case 0xef /*⠇⠇⠅*/:
|
||||
case 0xf0 /*⠄⠆⠆*/: case 0xf1 /*⠆⠆⠆*/: case 0xf2 /*⠅⠆⠆*/: case 0xf3 /*⠇⠆⠆*/: case 0xf4 /*⠄⠇⠆*/: case 0xf5 /*⠆⠇⠆*/: case 0xf6 /*⠅⠇⠆*/: case 0xf7 /*⠇⠇⠆*/:
|
||||
case 0xf8 /*⠄⠆⠇*/: case 0xf9 /*⠆⠆⠇*/: case 0xfa /*⠅⠆⠇*/: case 0xfb /*⠇⠆⠇*/: case 0xfc /*⠄⠇⠇*/: case 0xfd /*⠆⠇⠇*/: case 0xfe /*⠅⠇⠇*/: case 0xff /*⠇⠇⠇*/:
|
||||
left = right = pixel;
|
||||
break;
|
||||
case 0x44 /*⠀⠇⠀*/: case 0x45 /*⠂⠇⠀*/:
|
||||
left = pixel;
|
||||
right = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
break;
|
||||
case 0x03 /*⠃⠂⠀*/: case 0x0b /*⠃⠂⠁*/: case 0x13 /*⠃⠂⠂*/: case 0x18 /*⠀⠂⠃*/: case 0x19 /*⠂⠂⠃*/: case 0x1a /*⠁⠂⠃*/: case 0x1b /*⠃⠂⠃*/: case 0x23 /*⠃⠂⠄*/:
|
||||
case 0x26 /*⠁⠃⠄*/: case 0x2b /*⠃⠂⠅*/: case 0x2c /*⠀⠃⠅*/: case 0x2d /*⠂⠃⠅*/: case 0x2e /*⠁⠃⠅*/: case 0x30 /*⠀⠂⠆*/: case 0x31 /*⠂⠂⠆*/: case 0x32 /*⠁⠂⠆*/:
|
||||
case 0x33 /*⠃⠂⠆*/: case 0x35 /*⠂⠃⠆*/: case 0x36 /*⠁⠃⠆*/: case 0x38 /*⠀⠂⠇*/: case 0x39 /*⠂⠂⠇*/: case 0x3a /*⠁⠂⠇*/: case 0x3b /*⠃⠂⠇*/: case 0x4b /*⠃⠆⠁*/:
|
||||
case 0x53 /*⠃⠆⠂*/: case 0x56 /*⠁⠇⠂*/: case 0x59 /*⠂⠆⠃*/: case 0x5a /*⠁⠆⠃*/: case 0x5b /*⠃⠆⠃*/: case 0x68 /*⠀⠆⠅*/: case 0x69 /*⠂⠆⠅*/: case 0x6a /*⠁⠆⠅*/:
|
||||
case 0x6b /*⠃⠆⠅*/: case 0x81 /*⠆⠂⠀*/: case 0x83 /*⠇⠂⠀*/: case 0x89 /*⠆⠂⠁*/: case 0x8b /*⠇⠂⠁*/: case 0x91 /*⠆⠂⠂*/: case 0x93 /*⠇⠂⠂*/: case 0x95 /*⠆⠃⠂*/:
|
||||
case 0x96 /*⠅⠃⠂*/: case 0x98 /*⠄⠂⠃*/: case 0x99 /*⠆⠂⠃*/: case 0x9a /*⠅⠂⠃*/: case 0x9b /*⠇⠂⠃*/: case 0xa1 /*⠆⠂⠄*/: case 0xa3 /*⠇⠂⠄*/: case 0xa5 /*⠆⠃⠄*/:
|
||||
case 0xa6 /*⠅⠃⠄*/: case 0xa9 /*⠆⠂⠅*/: case 0xab /*⠇⠂⠅*/: case 0xac /*⠄⠃⠅*/: case 0xad /*⠆⠃⠅*/: case 0xae /*⠅⠃⠅*/: case 0xb0 /*⠄⠂⠆*/: case 0xb1 /*⠆⠂⠆*/:
|
||||
case 0xb2 /*⠅⠂⠆*/: case 0xb3 /*⠇⠂⠆*/: case 0xb4 /*⠄⠃⠆*/: case 0xb5 /*⠆⠃⠆*/: case 0xb6 /*⠅⠃⠆*/: case 0xb8 /*⠄⠂⠇*/: case 0xb9 /*⠆⠂⠇*/: case 0xba /*⠅⠂⠇*/:
|
||||
case 0xbb /*⠇⠂⠇*/: case 0xc8 /*⠄⠆⠁*/: case 0xca /*⠅⠆⠁*/: case 0xd2 /*⠅⠆⠂*/: case 0xd4 /*⠄⠇⠂*/: case 0xd6 /*⠅⠇⠂*/: case 0xd8 /*⠄⠆⠃*/: case 0xda /*⠅⠆⠃*/:
|
||||
case 0xe8 /*⠄⠆⠅*/: case 0xea /*⠅⠆⠅*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
left = right = pixel;
|
||||
} else {
|
||||
left = right = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x48 /*⠀⠆⠁*/:
|
||||
left = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
right = pixel;
|
||||
break;
|
||||
case 0x40 /*⠀⠆⠀*/: case 0x41 /*⠂⠆⠀*/: case 0x42 /*⠁⠆⠀*/: case 0xc3 /*⠇⠆⠀*/:
|
||||
left = pixel;
|
||||
right = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
break;
|
||||
case 0x24 /*⠀⠃⠄*/:
|
||||
left = !linePixels.get(x - 1, y) ? src.get(x - 1, y) : !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
right = pixel;
|
||||
break;
|
||||
case 0x04 /*⠀⠃⠀*/: case 0x05 /*⠂⠃⠀*/: case 0x84 /*⠄⠃⠀*/: case 0x87 /*⠇⠃⠀*/:
|
||||
left = pixel;
|
||||
right = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
break;
|
||||
case 0x46 /*⠁⠇⠀*/: case 0x4c /*⠀⠇⠁*/: case 0x4d /*⠂⠇⠁*/: case 0x4e /*⠁⠇⠁*/: case 0x64 /*⠀⠇⠄*/: case 0x65 /*⠂⠇⠄*/: case 0x66 /*⠁⠇⠄*/: case 0x6c /*⠀⠇⠅*/:
|
||||
case 0x6d /*⠂⠇⠅*/: case 0x6e /*⠁⠇⠅*/: case 0xc4 /*⠄⠇⠀*/: case 0xc6 /*⠅⠇⠀*/: case 0xcc /*⠄⠇⠁*/: case 0xce /*⠅⠇⠁*/: case 0xe4 /*⠄⠇⠄*/: case 0xe6 /*⠅⠇⠄*/:
|
||||
case 0xec /*⠄⠇⠅*/: case 0xee /*⠅⠇⠅*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
left = pixel;
|
||||
right = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
} else {
|
||||
left = right = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x28 /*⠀⠂⠅*/:
|
||||
left = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
right = pixel;
|
||||
break;
|
||||
case 0x82 /*⠅⠂⠀*/:
|
||||
left = pixel;
|
||||
right = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
break;
|
||||
case 0x43 /*⠃⠆⠀*/: case 0x60 /*⠀⠆⠄*/: case 0x61 /*⠂⠆⠄*/: case 0x62 /*⠁⠆⠄*/: case 0x63 /*⠃⠆⠄*/: case 0xc0 /*⠄⠆⠀*/: case 0xc2 /*⠅⠆⠀*/: case 0xe0 /*⠄⠆⠄*/:
|
||||
case 0xe2 /*⠅⠆⠄*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
left = pixel;
|
||||
right = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
} else {
|
||||
left = right = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x16 /*⠁⠃⠂*/: case 0x34 /*⠀⠃⠆*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
left = !linePixels.get(x - 1, y) ? src.get(x - 1, y) : !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
right = pixel;
|
||||
} else {
|
||||
left = right = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x06 /*⠁⠃⠀*/: case 0x0c /*⠀⠃⠁*/: case 0x0d /*⠂⠃⠁*/: case 0x0e /*⠁⠃⠁*/: case 0x85 /*⠆⠃⠀*/: case 0x86 /*⠅⠃⠀*/: case 0x8c /*⠄⠃⠁*/: case 0x8d /*⠆⠃⠁*/:
|
||||
case 0x8e /*⠅⠃⠁*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
left = pixel;
|
||||
right = !linePixels.get(x + 1, y) ? src.get(x + 1, y) : !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
} else {
|
||||
left = right = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x58 /*⠀⠆⠃*/: case 0xd0 /*⠄⠆⠂*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
left = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
right = pixel;
|
||||
} else {
|
||||
left = right = pixel;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void scalePixelTo1x2(
|
||||
const MarginedBitmap<Color> &src,
|
||||
const MarginedBitmap<bool> &linePixels,
|
||||
int x, int y,
|
||||
// Out parameters
|
||||
Color &top, Color &bottom
|
||||
) {
|
||||
const Color pixel = src.get(x, y);
|
||||
const EqualityMatrix matrix = getEqualityMatrix(src.getPointerTo(x, y), src.getStride());
|
||||
|
||||
// Note: There is a case label for every possible value, so we don't need a default label.
|
||||
switch (matrix) {
|
||||
case 0x00 /*⠀⠂⠀*/: case 0x02 /*⠁⠂⠀*/: case 0x04 /*⠀⠃⠀*/: case 0x07 /*⠃⠃⠀*/: case 0x08 /*⠀⠂⠁*/: case 0x17 /*⠃⠃⠂*/: case 0x1c /*⠀⠃⠃*/: case 0x1d /*⠂⠃⠃*/:
|
||||
case 0x1e /*⠁⠃⠃*/: case 0x1f /*⠃⠃⠃*/: case 0x20 /*⠀⠂⠄*/: case 0x22 /*⠁⠂⠄*/: case 0x24 /*⠀⠃⠄*/: case 0x25 /*⠂⠃⠄*/: case 0x27 /*⠃⠃⠄*/: case 0x28 /*⠀⠂⠅*/:
|
||||
case 0x29 /*⠂⠂⠅*/: case 0x2a /*⠁⠂⠅*/: case 0x2f /*⠃⠃⠅*/: case 0x37 /*⠃⠃⠆*/: case 0x3c /*⠀⠃⠇*/: case 0x3d /*⠂⠃⠇*/: case 0x3e /*⠁⠃⠇*/: case 0x3f /*⠃⠃⠇*/:
|
||||
case 0x40 /*⠀⠆⠀*/: case 0x41 /*⠂⠆⠀*/: case 0x42 /*⠁⠆⠀*/: case 0x44 /*⠀⠇⠀*/: case 0x45 /*⠂⠇⠀*/: case 0x47 /*⠃⠇⠀*/: case 0x48 /*⠀⠆⠁*/: case 0x49 /*⠂⠆⠁*/:
|
||||
case 0x4a /*⠁⠆⠁*/: case 0x4f /*⠃⠇⠁*/: case 0x50 /*⠀⠆⠂*/: case 0x51 /*⠂⠆⠂*/: case 0x52 /*⠁⠆⠂*/: case 0x54 /*⠀⠇⠂*/: case 0x55 /*⠂⠇⠂*/: case 0x57 /*⠃⠇⠂*/:
|
||||
case 0x5c /*⠀⠇⠃*/: case 0x5d /*⠂⠇⠃*/: case 0x5e /*⠁⠇⠃*/: case 0x5f /*⠃⠇⠃*/: case 0x67 /*⠃⠇⠄*/: case 0x6f /*⠃⠇⠅*/: case 0x70 /*⠀⠆⠆*/: case 0x71 /*⠂⠆⠆*/:
|
||||
case 0x72 /*⠁⠆⠆*/: case 0x73 /*⠃⠆⠆*/: case 0x74 /*⠀⠇⠆*/: case 0x75 /*⠂⠇⠆*/: case 0x76 /*⠁⠇⠆*/: case 0x77 /*⠃⠇⠆*/: case 0x78 /*⠀⠆⠇*/: case 0x79 /*⠂⠆⠇*/:
|
||||
case 0x7a /*⠁⠆⠇*/: case 0x7b /*⠃⠆⠇*/: case 0x7c /*⠀⠇⠇*/: case 0x7d /*⠂⠇⠇*/: case 0x7e /*⠁⠇⠇*/: case 0x7f /*⠃⠇⠇*/: case 0x80 /*⠄⠂⠀*/: case 0x82 /*⠅⠂⠀*/:
|
||||
case 0x84 /*⠄⠃⠀*/: case 0x87 /*⠇⠃⠀*/: case 0x88 /*⠄⠂⠁*/: case 0x8a /*⠅⠂⠁*/: case 0x8f /*⠇⠃⠁*/: case 0x92 /*⠅⠂⠂*/: case 0x94 /*⠄⠃⠂*/: case 0x97 /*⠇⠃⠂*/:
|
||||
case 0x9c /*⠄⠃⠃*/: case 0x9d /*⠆⠃⠃*/: case 0x9e /*⠅⠃⠃*/: case 0x9f /*⠇⠃⠃*/: case 0xa2 /*⠅⠂⠄*/: case 0xa4 /*⠄⠃⠄*/: case 0xa7 /*⠇⠃⠄*/: case 0xa8 /*⠄⠂⠅*/:
|
||||
case 0xaa /*⠅⠂⠅*/: case 0xaf /*⠇⠃⠅*/: case 0xb7 /*⠇⠃⠆*/: case 0xbc /*⠄⠃⠇*/: case 0xbd /*⠆⠃⠇*/: case 0xbe /*⠅⠃⠇*/: case 0xbf /*⠇⠃⠇*/: case 0xc1 /*⠆⠆⠀*/:
|
||||
case 0xc3 /*⠇⠆⠀*/: case 0xc5 /*⠆⠇⠀*/: case 0xc7 /*⠇⠇⠀*/: case 0xc9 /*⠆⠆⠁*/: case 0xcb /*⠇⠆⠁*/: case 0xcd /*⠆⠇⠁*/: case 0xcf /*⠇⠇⠁*/: case 0xd1 /*⠆⠆⠂*/:
|
||||
case 0xd3 /*⠇⠆⠂*/: case 0xd5 /*⠆⠇⠂*/: case 0xd7 /*⠇⠇⠂*/: case 0xd9 /*⠆⠆⠃*/: case 0xdb /*⠇⠆⠃*/: case 0xdc /*⠄⠇⠃*/: case 0xdd /*⠆⠇⠃*/: case 0xde /*⠅⠇⠃*/:
|
||||
case 0xdf /*⠇⠇⠃*/: case 0xe3 /*⠇⠆⠄*/: case 0xe5 /*⠆⠇⠄*/: case 0xe7 /*⠇⠇⠄*/: case 0xe9 /*⠆⠆⠅*/: case 0xeb /*⠇⠆⠅*/: case 0xed /*⠆⠇⠅*/: case 0xef /*⠇⠇⠅*/:
|
||||
case 0xf0 /*⠄⠆⠆*/: case 0xf1 /*⠆⠆⠆*/: case 0xf2 /*⠅⠆⠆*/: case 0xf3 /*⠇⠆⠆*/: case 0xf4 /*⠄⠇⠆*/: case 0xf5 /*⠆⠇⠆*/: case 0xf6 /*⠅⠇⠆*/: case 0xf7 /*⠇⠇⠆*/:
|
||||
case 0xf8 /*⠄⠆⠇*/: case 0xf9 /*⠆⠆⠇*/: case 0xfa /*⠅⠆⠇*/: case 0xfb /*⠇⠆⠇*/: case 0xfc /*⠄⠇⠇*/: case 0xfd /*⠆⠇⠇*/: case 0xfe /*⠅⠇⠇*/: case 0xff /*⠇⠇⠇*/:
|
||||
top = bottom = pixel;
|
||||
break;
|
||||
case 0x11 /*⠂⠂⠂*/: case 0x15 /*⠂⠃⠂*/:
|
||||
top = pixel;
|
||||
bottom = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
break;
|
||||
case 0x06 /*⠁⠃⠀*/: case 0x0c /*⠀⠃⠁*/: case 0x0e /*⠁⠃⠁*/: case 0x23 /*⠃⠂⠄*/: case 0x26 /*⠁⠃⠄*/: case 0x2b /*⠃⠂⠅*/: case 0x2c /*⠀⠃⠅*/: case 0x2d /*⠂⠃⠅*/:
|
||||
case 0x2e /*⠁⠃⠅*/: case 0x46 /*⠁⠇⠀*/: case 0x4b /*⠃⠆⠁*/: case 0x4c /*⠀⠇⠁*/: case 0x4d /*⠂⠇⠁*/: case 0x4e /*⠁⠇⠁*/: case 0x53 /*⠃⠆⠂*/: case 0x56 /*⠁⠇⠂*/:
|
||||
case 0x59 /*⠂⠆⠃*/: case 0x5a /*⠁⠆⠃*/: case 0x5b /*⠃⠆⠃*/: case 0x60 /*⠀⠆⠄*/: case 0x62 /*⠁⠆⠄*/: case 0x63 /*⠃⠆⠄*/: case 0x64 /*⠀⠇⠄*/: case 0x65 /*⠂⠇⠄*/:
|
||||
case 0x66 /*⠁⠇⠄*/: case 0x68 /*⠀⠆⠅*/: case 0x69 /*⠂⠆⠅*/: case 0x6a /*⠁⠆⠅*/: case 0x6b /*⠃⠆⠅*/: case 0x6c /*⠀⠇⠅*/: case 0x6d /*⠂⠇⠅*/: case 0x6e /*⠁⠇⠅*/:
|
||||
case 0x86 /*⠅⠃⠀*/: case 0x8c /*⠄⠃⠁*/: case 0x8e /*⠅⠃⠁*/: case 0x96 /*⠅⠃⠂*/: case 0x98 /*⠄⠂⠃*/: case 0x9a /*⠅⠂⠃*/: case 0xa1 /*⠆⠂⠄*/: case 0xa3 /*⠇⠂⠄*/:
|
||||
case 0xa5 /*⠆⠃⠄*/: case 0xa6 /*⠅⠃⠄*/: case 0xa9 /*⠆⠂⠅*/: case 0xab /*⠇⠂⠅*/: case 0xac /*⠄⠃⠅*/: case 0xad /*⠆⠃⠅*/: case 0xae /*⠅⠃⠅*/: case 0xb0 /*⠄⠂⠆*/:
|
||||
case 0xb2 /*⠅⠂⠆*/: case 0xb4 /*⠄⠃⠆*/: case 0xb6 /*⠅⠃⠆*/: case 0xb8 /*⠄⠂⠇*/: case 0xba /*⠅⠂⠇*/: case 0xc0 /*⠄⠆⠀*/: case 0xc2 /*⠅⠆⠀*/: case 0xc4 /*⠄⠇⠀*/:
|
||||
case 0xc6 /*⠅⠇⠀*/: case 0xc8 /*⠄⠆⠁*/: case 0xca /*⠅⠆⠁*/: case 0xcc /*⠄⠇⠁*/: case 0xce /*⠅⠇⠁*/: case 0xd2 /*⠅⠆⠂*/: case 0xd4 /*⠄⠇⠂*/: case 0xd6 /*⠅⠇⠂*/:
|
||||
case 0xd8 /*⠄⠆⠃*/: case 0xda /*⠅⠆⠃*/: case 0xe0 /*⠄⠆⠄*/: case 0xe2 /*⠅⠆⠄*/: case 0xe4 /*⠄⠇⠄*/: case 0xe6 /*⠅⠇⠄*/: case 0xe8 /*⠄⠆⠅*/: case 0xea /*⠅⠆⠅*/:
|
||||
case 0xec /*⠄⠇⠅*/: case 0xee /*⠅⠇⠅*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
top = bottom = pixel;
|
||||
} else {
|
||||
top = bottom = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x90 /*⠄⠂⠂*/:
|
||||
top = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
bottom = pixel;
|
||||
break;
|
||||
case 0x21 /*⠂⠂⠄*/: case 0xe1 /*⠆⠆⠄*/:
|
||||
top = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottom = pixel;
|
||||
break;
|
||||
case 0x10 /*⠀⠂⠂*/: case 0x12 /*⠁⠂⠂*/: case 0x14 /*⠀⠃⠂*/:
|
||||
top = pixel;
|
||||
bottom = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
break;
|
||||
case 0x01 /*⠂⠂⠀*/: case 0x05 /*⠂⠃⠀*/: case 0x09 /*⠂⠂⠁*/: case 0x0f /*⠃⠃⠁*/:
|
||||
top = pixel;
|
||||
bottom = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
break;
|
||||
case 0x13 /*⠃⠂⠂*/: case 0x19 /*⠂⠂⠃*/: case 0x1b /*⠃⠂⠃*/: case 0x31 /*⠂⠂⠆*/: case 0x33 /*⠃⠂⠆*/: case 0x35 /*⠂⠃⠆*/: case 0x39 /*⠂⠂⠇*/: case 0x3b /*⠃⠂⠇*/:
|
||||
case 0x91 /*⠆⠂⠂*/: case 0x93 /*⠇⠂⠂*/: case 0x95 /*⠆⠃⠂*/: case 0x99 /*⠆⠂⠃*/: case 0x9b /*⠇⠂⠃*/: case 0xb1 /*⠆⠂⠆*/: case 0xb3 /*⠇⠂⠆*/: case 0xb5 /*⠆⠃⠆*/:
|
||||
case 0xb9 /*⠆⠂⠇*/: case 0xbb /*⠇⠂⠇*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
top = pixel;
|
||||
bottom = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : pixel;
|
||||
} else {
|
||||
top = bottom = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x0a /*⠁⠂⠁*/:
|
||||
top = pixel;
|
||||
bottom = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
break;
|
||||
case 0xa0 /*⠄⠂⠄*/:
|
||||
top = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottom = pixel;
|
||||
break;
|
||||
case 0x16 /*⠁⠃⠂*/: case 0x18 /*⠀⠂⠃*/: case 0x1a /*⠁⠂⠃*/: case 0x30 /*⠀⠂⠆*/: case 0x32 /*⠁⠂⠆*/: case 0x34 /*⠀⠃⠆*/: case 0x36 /*⠁⠃⠆*/: case 0x38 /*⠀⠂⠇*/:
|
||||
case 0x3a /*⠁⠂⠇*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
top = pixel;
|
||||
bottom = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
} else {
|
||||
top = bottom = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x43 /*⠃⠆⠀*/: case 0x61 /*⠂⠆⠄*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
top = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
bottom = pixel;
|
||||
} else {
|
||||
top = bottom = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x58 /*⠀⠆⠃*/: case 0xd0 /*⠄⠆⠂*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
top = !linePixels.get(x, y - 1) ? src.get(x, y - 1) : !linePixels.get(x - 1, y) ? src.get(x - 1, y) : pixel;
|
||||
bottom = pixel;
|
||||
} else {
|
||||
top = bottom = pixel;
|
||||
}
|
||||
break;
|
||||
case 0x03 /*⠃⠂⠀*/: case 0x0b /*⠃⠂⠁*/: case 0x0d /*⠂⠃⠁*/: case 0x81 /*⠆⠂⠀*/: case 0x83 /*⠇⠂⠀*/: case 0x85 /*⠆⠃⠀*/: case 0x89 /*⠆⠂⠁*/: case 0x8b /*⠇⠂⠁*/:
|
||||
case 0x8d /*⠆⠃⠁*/:
|
||||
if (linePixels.get(x, y)) {
|
||||
top = pixel;
|
||||
bottom = !linePixels.get(x, y + 1) ? src.get(x, y + 1) : !linePixels.get(x + 1, y) ? src.get(x + 1, y) : pixel;
|
||||
} else {
|
||||
top = bottom = pixel;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
402
graphics/larryScale_generator.js
Normal file
402
graphics/larryScale_generator.js
Normal file
@ -0,0 +1,402 @@
|
||||
/* 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 2
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
// This file re-generates 'larryScale_generated.cpp'.
|
||||
// To run it, install Node 8.0+, then run 'node larryScale_generator.js'.
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
// Compass directions
|
||||
const Direction = {
|
||||
W: 0,
|
||||
NW: 1,
|
||||
N: 2,
|
||||
NE: 3,
|
||||
E: 4,
|
||||
SE: 5,
|
||||
S: 6,
|
||||
SW: 7,
|
||||
|
||||
sanitize(direction) {
|
||||
return ((direction % 8) + 8) % 8;
|
||||
}
|
||||
};
|
||||
|
||||
function getVector(direction) {
|
||||
switch (direction) {
|
||||
case Direction.W: return [-1, 0];
|
||||
case Direction.NW: return [-1, -1];
|
||||
case Direction.N: return [0, -1];
|
||||
case Direction.NE: return [1, -1];
|
||||
case Direction.E: return [1, 0];
|
||||
case Direction.SE: return [1, 1];
|
||||
case Direction.S: return [0, 1];
|
||||
case Direction.SW: return [-1, 1];
|
||||
default:
|
||||
throw new Error(`Invalid direction: ${direction}`);
|
||||
}
|
||||
}
|
||||
|
||||
// An equality matrix is a combination of eight Boolean flags indicating whether
|
||||
// each of the surrounding pixels has the same color as the central pixel.
|
||||
//
|
||||
// +-----------+-----------+-----------+
|
||||
// | NW = 0x02 | N = 0x04 | NE = 0x08 |
|
||||
// +-----------+-----------+-----------+
|
||||
// | W = 0x01 | Reference | E = 0x10 |
|
||||
// +-----------+-----------+-----------+
|
||||
// | SW = 0x80 | S = 0x40 | SE = 0x20 |
|
||||
// +-----------+-----------+-----------+
|
||||
class EqualityMatrix {
|
||||
constructor(value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
get(direction) {
|
||||
const mask = 0x01 << Direction.sanitize(direction);
|
||||
return (this.value & mask) != 0;
|
||||
}
|
||||
|
||||
set(direction, flag) {
|
||||
const mask = 0x01 << Direction.sanitize(direction);
|
||||
this.value = this.value & ~mask | (flag ? mask : 0x00);
|
||||
}
|
||||
|
||||
get w() { return this.get(Direction.W); }
|
||||
set w(flag) { this.set(Direction.W, flag); }
|
||||
|
||||
get nw() { return this.get(Direction.NW); }
|
||||
set nw(flag) { this.set(Direction.NW, flag); }
|
||||
|
||||
get n() { return this.get(Direction.N); }
|
||||
set n(flag) { this.set(Direction.N, flag); }
|
||||
|
||||
get ne() { return this.get(Direction.NE); }
|
||||
set ne(flag) { this.set(Direction.NE, flag); }
|
||||
|
||||
get e() { return this.get(Direction.E); }
|
||||
set e(flag) { this.set(Direction.E, flag); }
|
||||
|
||||
get se() { return this.get(Direction.SE); }
|
||||
set se(flag) { this.set(Direction.SE, flag); }
|
||||
|
||||
get s() { return this.get(Direction.S); }
|
||||
set s(flag) { this.set(Direction.S, flag); }
|
||||
|
||||
get sw() { return this.get(Direction.SW); }
|
||||
set sw(flag) { this.set(Direction.SW, flag); }
|
||||
|
||||
toBraille() {
|
||||
return getBrailleColumn(this.nw, this.w, this.sw)
|
||||
+ getBrailleColumn(this.n, true, this.s)
|
||||
+ getBrailleColumn(this.ne, this.e, this.se);
|
||||
}
|
||||
}
|
||||
|
||||
function getBrailleColumn(top, middle, bottom) {
|
||||
const codepoint = 0x2800 | (top ? 1 : 0) | (middle ? 2 : 0) | (bottom ? 4 : 0);
|
||||
return String.fromCodePoint(codepoint);
|
||||
}
|
||||
|
||||
function indent(string, tabCount = 1) {
|
||||
const indentation = '\t'.repeat(tabCount);
|
||||
return string
|
||||
.split(/\r?\n/)
|
||||
.map(s => indentation + s)
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
function toHex(number, minLength = 2) {
|
||||
const hex = number.toString(16);
|
||||
const padding = '0'.repeat(Math.max(minLength - hex.length, 0));
|
||||
return `0x${padding}${hex}`;
|
||||
}
|
||||
|
||||
function generateCaseLabel(matrix) {
|
||||
return `case ${toHex(matrix.value)} /*${matrix.toBraille()}*/:`
|
||||
}
|
||||
|
||||
function generateCaseBlock(matrixes, body) {
|
||||
const maxLabelsPerLine = 8;
|
||||
const labels = matrixes
|
||||
.map(generateCaseLabel)
|
||||
.reduce((a, b, index) => a + ((index % maxLabelsPerLine === 0) ? '\n' : '\t') + b);
|
||||
return `${labels}\n${indent(body)}`;
|
||||
}
|
||||
|
||||
function generateSwitchBlock(variableName, getCaseBody) {
|
||||
const matrixesByBody = new Map();
|
||||
for (let value = 0; value <= 0xFF; value++) {
|
||||
const matrix = new EqualityMatrix(value);
|
||||
const body = getCaseBody(matrix);
|
||||
if (!matrixesByBody.has(body)) {
|
||||
matrixesByBody.set(body, []);
|
||||
}
|
||||
matrixesByBody.get(body).push(matrix);
|
||||
}
|
||||
const orderedPairs = [...matrixesByBody.entries()]
|
||||
// For readability: order cases by increasing code length
|
||||
.sort((a, b) => a[0].length - b[0].length);
|
||||
const switchStatements = orderedPairs
|
||||
.map(([body, matrixes]) => generateCaseBlock(matrixes, body))
|
||||
.join('\n');
|
||||
const comment = '// Note: There is a case label for every possible value, so we don\'t need a default label.';
|
||||
return `${comment}\nswitch (${variableName}) {\n${switchStatements}\n}`;
|
||||
}
|
||||
|
||||
const PixelType = {
|
||||
// Pixel is part of a line
|
||||
LINE: 'line',
|
||||
// Pixel is part of a fill
|
||||
FILL: 'fill',
|
||||
// Pixel is part of a line *or* a fill
|
||||
INDETERMINATE: 'indeterminate'
|
||||
};
|
||||
|
||||
function getPixelType(matrix) {
|
||||
// Single pixels are fills
|
||||
if (matrix.value === 0) return PixelType.FILL;
|
||||
|
||||
// 2x2 blocks are fills
|
||||
if (
|
||||
(matrix.n && matrix.ne && matrix.e)
|
||||
|| (matrix.e && matrix.se && matrix.s)
|
||||
|| (matrix.s && matrix.sw && matrix.w)
|
||||
|| (matrix.w && matrix.nw && matrix.n)
|
||||
) return PixelType.FILL;
|
||||
|
||||
// A pixel adjacent to a 2x2 block is a fill.
|
||||
// This requires reading out of the matrix, so we can't be sure.
|
||||
if (
|
||||
(matrix.n && matrix.ne)
|
||||
|| (matrix.ne && matrix.e)
|
||||
|| (matrix.e && matrix.se)
|
||||
|| (matrix.se && matrix.s)
|
||||
|| (matrix.s && matrix.sw)
|
||||
|| (matrix.sw && matrix.w)
|
||||
|| (matrix.w && matrix.nw)
|
||||
|| (matrix.nw && matrix.n)
|
||||
) return PixelType.INDETERMINATE;
|
||||
|
||||
// Everything else is part of a line
|
||||
return PixelType.LINE;
|
||||
}
|
||||
|
||||
function isPowerOfTwo(number) {
|
||||
return Math.log2(number) % 1 === 0;
|
||||
}
|
||||
|
||||
// Upscales a line pixel to 2x2.
|
||||
// Returns a 4-element array of Booleans in order top-left, top-right, bottom-left, bottom-right.
|
||||
// Each Boolean indicates whether the upscaled pixel should be filled with the original color.
|
||||
function getLineUpscaleFlags(matrix) {
|
||||
// The rules for upscaling lines are *not* symmetrical but biased toward the left
|
||||
|
||||
// Special rules for upscaling smooth angled lines
|
||||
switch (matrix.value) {
|
||||
case 0x34 /*⠀⠃⠆*/:
|
||||
return [false, true, false, false]; // [ ▀]
|
||||
case 0x58 /*⠀⠆⠃*/:
|
||||
return [false, false, false, true]; // [ ▄]
|
||||
case 0x43 /*⠃⠆⠀*/:
|
||||
return [false, false, true, false]; // [▄ ]
|
||||
|
||||
case 0x61 /*⠂⠆⠄*/:
|
||||
return [false, false, true, false]; // [▄ ]
|
||||
case 0x16 /*⠁⠃⠂*/:
|
||||
return [false, true, false, false]; // [ ▀]
|
||||
case 0xD0 /*⠄⠆⠂*/:
|
||||
return [false, false, false, true]; // [ ▄]
|
||||
|
||||
case 0x24 /*⠀⠃⠄*/:
|
||||
case 0x48 /*⠀⠆⠁*/:
|
||||
return [false, true, false, true]; // [ █]
|
||||
|
||||
case 0x21 /*⠂⠂⠄*/:
|
||||
case 0x90 /*⠄⠂⠂*/:
|
||||
return [false, false, true, true]; // [▄▄]
|
||||
|
||||
case 0x50 /*⠀⠆⠂*/:
|
||||
return [true, true, true, false]; // [█▀]
|
||||
}
|
||||
|
||||
// Generic rules for upscaling lines
|
||||
|
||||
// Ignore diagonals next to fully-adjacent pixels
|
||||
matrix = new EqualityMatrix(matrix.value);
|
||||
if (matrix.w) {
|
||||
matrix.sw = matrix.nw = false;
|
||||
}
|
||||
if (matrix.n) {
|
||||
matrix.nw = matrix.ne = false;
|
||||
}
|
||||
if (matrix.e) {
|
||||
matrix.ne = matrix.se = false;
|
||||
}
|
||||
if (matrix.s) {
|
||||
matrix.se = matrix.sw = false;
|
||||
}
|
||||
|
||||
// Mirror single lines
|
||||
if (isPowerOfTwo(matrix.value)) {
|
||||
matrix.value |= (matrix.value << 4) | (matrix.value >> 4);
|
||||
}
|
||||
|
||||
return [
|
||||
matrix.w || matrix.nw || matrix.n,
|
||||
matrix.ne || matrix.e,
|
||||
matrix.s || matrix.sw,
|
||||
matrix.se
|
||||
];
|
||||
}
|
||||
|
||||
// Upscales a fill pixel to 2x2.
|
||||
// Same result format as getLineUpscaleFlags.
|
||||
function getFillUpscaleFlags(matrix) {
|
||||
// The rules for upscaling fills are *not* symmetrical but biased toward the top-left
|
||||
|
||||
// Special rules for upscaling cornered fills
|
||||
switch (matrix.value) {
|
||||
case 0xE1 /*⠆⠆⠄*/:
|
||||
return [false, false, true, true]; // [▄▄]
|
||||
case 0x0F /*⠃⠃⠁*/:
|
||||
return [true, true, false, false]; // [▀▀]
|
||||
case 0xC3 /*⠇⠆⠀*/:
|
||||
case 0x87 /*⠇⠃⠀*/:
|
||||
return [true, false, true, false]; // [█ ]
|
||||
}
|
||||
|
||||
// Generic rules for upscaling fills
|
||||
if (!matrix.s && !matrix.se && !matrix.e && (matrix.sw || matrix.ne)) {
|
||||
return [true, true, true, false]; // [█▀]
|
||||
} else if (!matrix.n && !matrix.ne && !matrix.e && (matrix.nw || matrix.se)) {
|
||||
return [true, false, true, true]; // [█▄]
|
||||
} else {
|
||||
return [true, true, true, true]; // [██]
|
||||
}
|
||||
}
|
||||
|
||||
function formatOffset(number) {
|
||||
if (number < 0) {
|
||||
return ` - ${-number}`;
|
||||
}
|
||||
if (number > 0) {
|
||||
return ` + ${number}`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function generatePixelUpscaleCode(matrix, flags, pixelRecords, { generateBreak = true } = {}) {
|
||||
const targetsByValue = new Map();
|
||||
function addAssignment(param, value) {
|
||||
if (targetsByValue.has(value)) {
|
||||
targetsByValue.get(value).push(param);
|
||||
} else {
|
||||
targetsByValue.set(value, [param]);
|
||||
}
|
||||
}
|
||||
for (const pixelRecord of pixelRecords) {
|
||||
const param = pixelRecord.param;
|
||||
const useSourceColor = flags
|
||||
.filter((flag, index) => pixelRecord.flagIndexes.includes(index))
|
||||
.some(flag => flag);
|
||||
if (useSourceColor) {
|
||||
addAssignment(param, 'pixel');
|
||||
} else {
|
||||
const sourceDirections = pixelRecord.sourceDirections
|
||||
.filter(d => !matrix.get(d));
|
||||
const value = sourceDirections
|
||||
.filter(d => !matrix.get(d)) // We don't want to get our own color
|
||||
.map(d => {
|
||||
const vector = getVector(d);
|
||||
const otherValueCode = `src.get(x${formatOffset(vector[0])}, y${formatOffset(vector[1])})`;
|
||||
return `!linePixels.get(x${formatOffset(vector[0])}, y${formatOffset(vector[1])}) ? ${otherValueCode} : `;
|
||||
})
|
||||
.join('') + 'pixel';
|
||||
addAssignment(param, value);
|
||||
}
|
||||
}
|
||||
|
||||
return [...targetsByValue.entries()]
|
||||
.map(([value, targets]) => [...targets, value].join(' = ') + ';')
|
||||
.concat(generateBreak ? ['break;'] : [])
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
function generateScalePixelFunction(width, height, pixelRecords) {
|
||||
const params = pixelRecords
|
||||
.map((pixelRecord, index) => `Color &${pixelRecord.param}`)
|
||||
.join(', ');
|
||||
const header =
|
||||
`inline void scalePixelTo${width}x${height}(\n\tconst MarginedBitmap<Color> &src,\n\tconst MarginedBitmap<bool> &linePixels,\n\tint x, int y,\n\t// Out parameters\n\t${params}\n)`;
|
||||
const prefix =
|
||||
'const Color pixel = src.get(x, y);\n'
|
||||
+ 'const EqualityMatrix matrix = getEqualityMatrix(src.getPointerTo(x, y), src.getStride());';
|
||||
const switchBlock = generateSwitchBlock('matrix', matrix => {
|
||||
const pixelType = getPixelType(matrix);
|
||||
switch (pixelType) {
|
||||
case PixelType.LINE:
|
||||
return generatePixelUpscaleCode(matrix, getLineUpscaleFlags(matrix), pixelRecords);
|
||||
case PixelType.FILL:
|
||||
return generatePixelUpscaleCode(matrix, getFillUpscaleFlags(matrix), pixelRecords);
|
||||
case PixelType.INDETERMINATE:
|
||||
const lineUpscaleCode = generatePixelUpscaleCode(matrix, getLineUpscaleFlags(matrix), pixelRecords, { generateBreak: false });
|
||||
const fillUpscaleCode = generatePixelUpscaleCode(matrix, getFillUpscaleFlags(matrix), pixelRecords, { generateBreak: false });
|
||||
return `if (linePixels.get(x, y)) {\n${indent(lineUpscaleCode)}\n} else {\n${indent(fillUpscaleCode)}\n}\nbreak;`;
|
||||
}
|
||||
});
|
||||
return `${header} {\n${indent(prefix)}\n\n${indent(switchBlock)}\n}`;
|
||||
}
|
||||
|
||||
function generateScalePixelTo2x2() {
|
||||
const pixelRecords = [
|
||||
{ param: 'topLeft', flagIndexes: [0], sourceDirections: [Direction.N, Direction.W] },
|
||||
{ param: 'topRight', flagIndexes: [1], sourceDirections: [Direction.N, Direction.E] },
|
||||
{ param: 'bottomLeft', flagIndexes: [2], sourceDirections: [Direction.S, Direction.W] },
|
||||
{ param: 'bottomRight', flagIndexes: [3], sourceDirections: [Direction.S, Direction.E] }
|
||||
];
|
||||
return generateScalePixelFunction(2, 2, pixelRecords);
|
||||
}
|
||||
|
||||
function generateScalePixelTo2x1() {
|
||||
const pixelRecords = [
|
||||
{ param: 'left', flagIndexes: [0, 2], sourceDirections: [Direction.N, Direction.W, Direction.S] },
|
||||
{ param: 'right', flagIndexes: [1, 3], sourceDirections: [Direction.N, Direction.E, Direction.S] }
|
||||
];
|
||||
return generateScalePixelFunction(2, 1, pixelRecords);
|
||||
}
|
||||
|
||||
function generateScalePixelTo1x2() {
|
||||
const pixelRecords = [
|
||||
{ param: 'top', flagIndexes: [0, 1], sourceDirections: [Direction.N, Direction.W, Direction.E] },
|
||||
{ param: 'bottom', flagIndexes: [2, 3], sourceDirections: [Direction.S, Direction.W, Direction.E] }
|
||||
];
|
||||
return generateScalePixelFunction(1, 2, pixelRecords);
|
||||
}
|
||||
|
||||
const generators = [generateScalePixelTo2x2, generateScalePixelTo2x1, generateScalePixelTo1x2];
|
||||
const generatedFunctions = generators
|
||||
.map(generator => generator())
|
||||
.join('\n\n');
|
||||
const legalese = fs.readFileSync(__filename, 'utf8').match(/\/\*[\s\S]*?\*\//)[0];
|
||||
const headerComment = '// This file was generated by larryScale_generator.js.\n// Do not edit directly! Instead, edit the generator script and run it.'
|
||||
fs.writeFileSync('./larryScale_generated.cpp', `${legalese}\n\n${headerComment}\n\n${generatedFunctions}\n`);
|
@ -12,6 +12,7 @@ MODULE_OBJS := \
|
||||
fonts/newfont.o \
|
||||
fonts/ttf.o \
|
||||
fonts/winfont.o \
|
||||
larryScale.o \
|
||||
maccursor.o \
|
||||
macgui/macfontmanager.o \
|
||||
macgui/macmenu.o \
|
||||
|
Loading…
x
Reference in New Issue
Block a user