mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-09 03:10:22 +00:00
MTROPOLIS: Improve image optimization
This commit is contained in:
parent
ea7eaa4a15
commit
256b2f9ef5
@ -125,6 +125,51 @@ size_t MovieAsset::getStreamIndex() const {
|
||||
return _streamIndex;
|
||||
}
|
||||
|
||||
|
||||
CachedImage::CachedImage() : _colorDepth(kColorDepthModeInvalid), _isOptimized(false) {
|
||||
}
|
||||
|
||||
void CachedImage::resetSurface(ColorDepthMode colorDepth, const Common::SharedPtr<Graphics::Surface> &surface) {
|
||||
_optimizedSurface.reset();
|
||||
_isOptimized = false;
|
||||
|
||||
_colorDepth = colorDepth;
|
||||
_surface = surface;
|
||||
}
|
||||
|
||||
const Common::SharedPtr<Graphics::Surface> &CachedImage::optimize(Runtime *runtime) {
|
||||
ColorDepthMode renderDepth = runtime->getRealColorDepth();
|
||||
const Graphics::PixelFormat &renderFmt = runtime->getRenderPixelFormat();
|
||||
|
||||
if (renderDepth != _colorDepth) {
|
||||
size_t w = _surface->w;
|
||||
size_t h = _surface->h;
|
||||
|
||||
if (renderDepth == kColorDepthMode16Bit && _colorDepth == kColorDepthMode32Bit) {
|
||||
_optimizedSurface.reset(new Graphics::Surface());
|
||||
_optimizedSurface->create(w, h, renderFmt);
|
||||
Render::convert32To16(*_optimizedSurface, *_surface);
|
||||
} else if (renderDepth == kColorDepthMode32Bit && _colorDepth == kColorDepthMode16Bit) {
|
||||
_optimizedSurface.reset(new Graphics::Surface());
|
||||
_optimizedSurface->create(w, h, renderFmt);
|
||||
Render::convert16To32(*_optimizedSurface, *_surface);
|
||||
} else {
|
||||
_optimizedSurface = _surface; // Can't optimize
|
||||
}
|
||||
} else {
|
||||
_surface->convertToInPlace(renderFmt, nullptr);
|
||||
_optimizedSurface = _surface;
|
||||
}
|
||||
|
||||
return _optimizedSurface;
|
||||
}
|
||||
|
||||
ImageAsset::ImageAsset() {
|
||||
}
|
||||
|
||||
ImageAsset::~ImageAsset() {
|
||||
}
|
||||
|
||||
bool ImageAsset::load(AssetLoaderContext &context, const Data::ImageAsset &data) {
|
||||
_assetID = data.assetID;
|
||||
if (!_rect.load(data.rect1))
|
||||
@ -194,6 +239,158 @@ ImageAsset::ImageFormat ImageAsset::getImageFormat() const {
|
||||
return _imageFormat;
|
||||
}
|
||||
|
||||
const Common::SharedPtr<CachedImage> &ImageAsset::loadAndCacheImage(Runtime *runtime) {
|
||||
if (_imageCache)
|
||||
return _imageCache;
|
||||
|
||||
ColorDepthMode renderDepth = runtime->getRealColorDepth();
|
||||
|
||||
size_t streamIndex = getStreamIndex();
|
||||
int segmentIndex = runtime->getProject()->getSegmentForStreamIndex(streamIndex);
|
||||
runtime->getProject()->openSegmentStream(segmentIndex);
|
||||
Common::SeekableReadStream *stream = runtime->getProject()->getStreamForSegment(segmentIndex);
|
||||
|
||||
if (!stream || !stream->seek(getFilePosition())) {
|
||||
warning("Image element failed to load");
|
||||
return _imageCache;
|
||||
}
|
||||
|
||||
size_t bytesPerRow = 0;
|
||||
|
||||
Rect16 imageRect = getRect();
|
||||
int width = imageRect.right - imageRect.left;
|
||||
int height = imageRect.bottom - imageRect.top;
|
||||
|
||||
if (width <= 0 || height < 0) {
|
||||
warning("Image asset has invalid size");
|
||||
return _imageCache;
|
||||
}
|
||||
|
||||
Graphics::PixelFormat pixelFmt;
|
||||
switch (getColorDepth()) {
|
||||
case kColorDepthMode1Bit:
|
||||
bytesPerRow = (width + 7) / 8;
|
||||
pixelFmt = Graphics::PixelFormat::createFormatCLUT8();
|
||||
break;
|
||||
case kColorDepthMode2Bit:
|
||||
bytesPerRow = (width + 3) / 4;
|
||||
pixelFmt = Graphics::PixelFormat::createFormatCLUT8();
|
||||
break;
|
||||
case kColorDepthMode4Bit:
|
||||
bytesPerRow = (width + 1) / 2;
|
||||
pixelFmt = Graphics::PixelFormat::createFormatCLUT8();
|
||||
break;
|
||||
case kColorDepthMode8Bit:
|
||||
bytesPerRow = width;
|
||||
pixelFmt = Graphics::PixelFormat::createFormatCLUT8();
|
||||
break;
|
||||
case kColorDepthMode16Bit:
|
||||
bytesPerRow = (width * 2 + 3) / 4 * 4;
|
||||
pixelFmt = Graphics::createPixelFormat<1555>();
|
||||
break;
|
||||
case kColorDepthMode32Bit:
|
||||
bytesPerRow = width * 4;
|
||||
pixelFmt = Graphics::createPixelFormat<8888>();
|
||||
break;
|
||||
default:
|
||||
warning("Image asset has an unrecognizable pixel format");
|
||||
return _imageCache;
|
||||
}
|
||||
|
||||
Common::Array<uint8> rowBuffer;
|
||||
rowBuffer.resize(bytesPerRow);
|
||||
|
||||
ImageAsset::ImageFormat imageFormat = getImageFormat();
|
||||
bool bottomUp = (imageFormat == ImageAsset::kImageFormatWindows);
|
||||
bool isBigEndian = (imageFormat == ImageAsset::kImageFormatMac);
|
||||
|
||||
Common::SharedPtr<Graphics::Surface> imageSurface;
|
||||
imageSurface.reset(new Graphics::Surface());
|
||||
imageSurface->create(width, height, pixelFmt);
|
||||
|
||||
for (int inRow = 0; inRow < height; inRow++) {
|
||||
int outRow = bottomUp ? (height - 1 - inRow) : inRow;
|
||||
|
||||
stream->read(&rowBuffer[0], bytesPerRow);
|
||||
const uint8 *inRowBytes = &rowBuffer[0];
|
||||
|
||||
void *outBase = imageSurface->getBasePtr(0, outRow);
|
||||
|
||||
switch (getColorDepth()) {
|
||||
case kColorDepthMode1Bit: {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int bit = (inRowBytes[x / 8] >> (7 - (x % 8))) & 1;
|
||||
static_cast<uint8 *>(outBase)[x] = bit;
|
||||
}
|
||||
} break;
|
||||
case kColorDepthMode2Bit: {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int bit = (inRowBytes[x / 4] >> (3 - (x % 4))) & 3;
|
||||
static_cast<uint8 *>(outBase)[x] = bit;
|
||||
}
|
||||
} break;
|
||||
case kColorDepthMode4Bit: {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int bit = (inRowBytes[x / 2] >> (1 - (x % 2))) & 15;
|
||||
static_cast<uint8 *>(outBase)[x] = bit;
|
||||
}
|
||||
} break;
|
||||
case kColorDepthMode8Bit:
|
||||
memcpy(outBase, inRowBytes, width);
|
||||
break;
|
||||
case kColorDepthMode16Bit: {
|
||||
if (isBigEndian) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
uint16 packedPixel = inRowBytes[x * 2 + 1] + (inRowBytes[x * 2 + 0] << 8);
|
||||
int r = ((packedPixel >> 10) & 0x1f);
|
||||
int g = ((packedPixel >> 5) & 0x1f);
|
||||
int b = (packedPixel & 0x1f);
|
||||
|
||||
uint16 repacked = (1 << pixelFmt.aShift) | (r << pixelFmt.rShift) | (g << pixelFmt.gShift) | (b << pixelFmt.bShift);
|
||||
static_cast<uint16 *>(outBase)[x] = repacked;
|
||||
}
|
||||
} else {
|
||||
for (int x = 0; x < width; x++) {
|
||||
uint16 packedPixel = inRowBytes[x * 2 + 0] + (inRowBytes[x * 2 + 1] << 8);
|
||||
int r = ((packedPixel >> 10) & 0x1f);
|
||||
int g = ((packedPixel >> 5) & 0x1f);
|
||||
int b = (packedPixel & 0x1f);
|
||||
|
||||
uint16 repacked = (1 << pixelFmt.aShift) | (r << pixelFmt.rShift) | (g << pixelFmt.gShift) | (b << pixelFmt.bShift);
|
||||
static_cast<uint16 *>(outBase)[x] = repacked;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case kColorDepthMode32Bit: {
|
||||
if (imageFormat == ImageAsset::kImageFormatMac) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
uint8 r = inRowBytes[x * 4 + 0];
|
||||
uint8 g = inRowBytes[x * 4 + 1];
|
||||
uint8 b = inRowBytes[x * 4 + 2];
|
||||
uint32 repacked = (255 << pixelFmt.aShift) | (r << pixelFmt.rShift) | (g << pixelFmt.gShift) | (b << pixelFmt.bShift);
|
||||
static_cast<uint32 *>(outBase)[x] = repacked;
|
||||
}
|
||||
} else if (imageFormat == ImageAsset::kImageFormatWindows) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
uint8 r = inRowBytes[x * 4 + 2];
|
||||
uint8 g = inRowBytes[x * 4 + 1];
|
||||
uint8 b = inRowBytes[x * 4 + 0];
|
||||
uint32 repacked = (255 << pixelFmt.aShift) | (r << pixelFmt.rShift) | (g << pixelFmt.gShift) | (b << pixelFmt.bShift);
|
||||
static_cast<uint32 *>(outBase)[x] = repacked;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_imageCache.reset(new CachedImage());
|
||||
_imageCache->resetSurface(renderDepth, imageSurface);
|
||||
|
||||
return _imageCache;
|
||||
}
|
||||
|
||||
bool MToonAsset::load(AssetLoaderContext &context, const Data::MToonAsset &data) {
|
||||
if (data.haveMacPart)
|
||||
_imageFormat = kImageFormatMac;
|
||||
@ -224,6 +421,8 @@ bool MToonAsset::load(AssetLoaderContext &context, const Data::MToonAsset &data)
|
||||
}
|
||||
|
||||
_codecData = data.codecData;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AssetType MToonAsset::getAssetType() const {
|
||||
|
@ -88,8 +88,27 @@ private:
|
||||
size_t _streamIndex;
|
||||
};
|
||||
|
||||
class CachedImage {
|
||||
public:
|
||||
CachedImage();
|
||||
|
||||
const Common::SharedPtr<Graphics::Surface> &optimize(Runtime *runtime);
|
||||
|
||||
void resetSurface(ColorDepthMode colorDepth, const Common::SharedPtr<Graphics::Surface> &surface);
|
||||
|
||||
private:
|
||||
Common::SharedPtr<Graphics::Surface> _surface;
|
||||
Common::SharedPtr<Graphics::Surface> _optimizedSurface;
|
||||
|
||||
ColorDepthMode _colorDepth;
|
||||
bool _isOptimized;
|
||||
};
|
||||
|
||||
class ImageAsset : public Asset {
|
||||
public:
|
||||
ImageAsset();
|
||||
~ImageAsset();
|
||||
|
||||
bool load(AssetLoaderContext &context, const Data::ImageAsset &data);
|
||||
AssetType getAssetType() const override;
|
||||
|
||||
@ -105,7 +124,7 @@ public:
|
||||
size_t getStreamIndex() const;
|
||||
ImageFormat getImageFormat() const;
|
||||
|
||||
const Common::SharedPtr<Graphics::Surface> &loadContent();
|
||||
const Common::SharedPtr<CachedImage> &loadAndCacheImage(Runtime *runtime);
|
||||
|
||||
private:
|
||||
Rect16 _rect;
|
||||
@ -115,7 +134,7 @@ private:
|
||||
size_t _streamIndex;
|
||||
ImageFormat _imageFormat;
|
||||
|
||||
Common::SharedPtr<Graphics::Surface> _surface;
|
||||
Common::SharedPtr<CachedImage> _imageCache;
|
||||
};
|
||||
|
||||
|
||||
|
@ -203,7 +203,6 @@ VThreadState MovieElement::startPlayingTask(const StartPlayingTaskData &taskData
|
||||
return kVThreadReturn;
|
||||
}
|
||||
|
||||
|
||||
ImageElement::ImageElement() : _cacheBitmap(false), _runtime(nullptr) {
|
||||
}
|
||||
|
||||
@ -243,162 +242,19 @@ void ImageElement::activate() {
|
||||
return;
|
||||
}
|
||||
|
||||
ImageAsset *imageAsset = static_cast<ImageAsset *>(asset.get());
|
||||
size_t streamIndex = imageAsset->getStreamIndex();
|
||||
int segmentIndex = project->getSegmentForStreamIndex(streamIndex);
|
||||
project->openSegmentStream(segmentIndex);
|
||||
Common::SeekableReadStream *stream = project->getStreamForSegment(segmentIndex);
|
||||
|
||||
if (!stream->seek(imageAsset->getFilePosition())) {
|
||||
warning("Image element failed to load");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t bytesPerRow = 0;
|
||||
|
||||
Rect16 imageRect = imageAsset->getRect();
|
||||
int width = imageRect.right - imageRect.left;
|
||||
int height = imageRect.bottom - imageRect.top;
|
||||
|
||||
if (width <= 0 || height < 0) {
|
||||
warning("Image asset has invalid size");
|
||||
return;
|
||||
}
|
||||
|
||||
Graphics::PixelFormat pixelFmt;
|
||||
switch (imageAsset->getColorDepth()) {
|
||||
case kColorDepthMode1Bit:
|
||||
bytesPerRow = (width + 7) / 8;
|
||||
pixelFmt = Graphics::PixelFormat::createFormatCLUT8();
|
||||
break;
|
||||
case kColorDepthMode2Bit:
|
||||
bytesPerRow = (width + 3) / 4;
|
||||
pixelFmt = Graphics::PixelFormat::createFormatCLUT8();
|
||||
break;
|
||||
case kColorDepthMode4Bit:
|
||||
bytesPerRow = (width + 1) / 2;
|
||||
pixelFmt = Graphics::PixelFormat::createFormatCLUT8();
|
||||
break;
|
||||
case kColorDepthMode8Bit:
|
||||
bytesPerRow = width;
|
||||
pixelFmt = Graphics::PixelFormat::createFormatCLUT8();
|
||||
break;
|
||||
case kColorDepthMode16Bit:
|
||||
bytesPerRow = (width * 2 + 3) / 4 * 4;
|
||||
pixelFmt = Graphics::createPixelFormat<1555>();
|
||||
break;
|
||||
case kColorDepthMode32Bit:
|
||||
bytesPerRow = width * 4;
|
||||
pixelFmt = Graphics::createPixelFormat<8888>();
|
||||
break;
|
||||
default:
|
||||
warning("Image asset has an unrecognizable pixel format");
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is the same mode as the render target, then copy the exact mode
|
||||
// so blits go faster
|
||||
if (imageAsset->getColorDepth() == _runtime->getRealColorDepth()) {
|
||||
pixelFmt = _runtime->getRenderPixelFormat();
|
||||
}
|
||||
|
||||
Common::Array<uint8> rowBuffer;
|
||||
rowBuffer.resize(bytesPerRow);
|
||||
|
||||
ImageAsset::ImageFormat imageFormat = imageAsset->getImageFormat();
|
||||
bool bottomUp = (imageFormat == ImageAsset::kImageFormatWindows);
|
||||
bool isBigEndian = (imageFormat == ImageAsset::kImageFormatMac);
|
||||
|
||||
_imageSurface.reset(new Graphics::Surface());
|
||||
_imageSurface->create(width, height, pixelFmt);
|
||||
|
||||
for (int inRow = 0; inRow < height; inRow++) {
|
||||
int outRow = bottomUp ? (height - 1 - inRow) : inRow;
|
||||
|
||||
stream->read(&rowBuffer[0], bytesPerRow);
|
||||
const uint8 *inRowBytes = &rowBuffer[0];
|
||||
|
||||
void *outBase = _imageSurface->getBasePtr(0, outRow);
|
||||
|
||||
switch (imageAsset->getColorDepth()) {
|
||||
case kColorDepthMode1Bit: {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int bit = (inRowBytes[x / 8] >> (7 - (x % 8))) & 1;
|
||||
static_cast<uint8 *>(outBase)[x] = bit;
|
||||
}
|
||||
} break;
|
||||
case kColorDepthMode2Bit: {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int bit = (inRowBytes[x / 4] >> (3 - (x % 4))) & 3;
|
||||
static_cast<uint8 *>(outBase)[x] = bit;
|
||||
}
|
||||
} break;
|
||||
case kColorDepthMode4Bit: {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int bit = (inRowBytes[x / 2] >> (1 - (x % 2))) & 15;
|
||||
static_cast<uint8 *>(outBase)[x] = bit;
|
||||
}
|
||||
} break;
|
||||
case kColorDepthMode8Bit:
|
||||
memcpy(outBase, inRowBytes, width);
|
||||
break;
|
||||
case kColorDepthMode16Bit: {
|
||||
if (isBigEndian) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
uint16 packedPixel = inRowBytes[x * 2 + 1] + (inRowBytes[x * 2 + 0] << 8);
|
||||
int r = ((packedPixel >> 10) & 0x1f);
|
||||
int g = ((packedPixel >> 5) & 0x1f);
|
||||
int b = (packedPixel & 0x1f);
|
||||
|
||||
uint16 repacked = (1 << pixelFmt.aShift) | (r << pixelFmt.rShift) | (g << pixelFmt.gShift) | (b << pixelFmt.bShift);
|
||||
static_cast<uint16 *>(outBase)[x] = repacked;
|
||||
}
|
||||
} else {
|
||||
for (int x = 0; x < width; x++) {
|
||||
uint16 packedPixel = inRowBytes[x * 2 + 0] + (inRowBytes[x * 2 + 1] << 8);
|
||||
int r = ((packedPixel >> 10) & 0x1f);
|
||||
int g = ((packedPixel >> 5) & 0x1f);
|
||||
int b = (packedPixel & 0x1f);
|
||||
|
||||
uint16 repacked = (1 << pixelFmt.aShift) | (r << pixelFmt.rShift) | (g << pixelFmt.gShift) | (b << pixelFmt.bShift);
|
||||
static_cast<uint16 *>(outBase)[x] = repacked;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case kColorDepthMode32Bit: {
|
||||
if (imageFormat == ImageAsset::kImageFormatMac) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
uint8 r = inRowBytes[x * 4 + 0];
|
||||
uint8 g = inRowBytes[x * 4 + 1];
|
||||
uint8 b = inRowBytes[x * 4 + 2];
|
||||
uint32 repacked = (255 << pixelFmt.aShift) | (r << pixelFmt.rShift) | (g << pixelFmt.gShift) | (b << pixelFmt.bShift);
|
||||
static_cast<uint32 *>(outBase)[x] = repacked;
|
||||
}
|
||||
} else if (imageFormat == ImageAsset::kImageFormatWindows) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
uint8 r = inRowBytes[x * 4 + 2];
|
||||
uint8 g = inRowBytes[x * 4 + 1];
|
||||
uint8 b = inRowBytes[x * 4 + 0];
|
||||
uint32 repacked = (255 << pixelFmt.aShift) | (r << pixelFmt.rShift) | (g << pixelFmt.gShift) | (b << pixelFmt.bShift);
|
||||
static_cast<uint32 *>(outBase)[x] = repacked;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
_cachedImage = static_cast<ImageAsset *>(asset.get())->loadAndCacheImage(_runtime);
|
||||
}
|
||||
|
||||
void ImageElement::deactivate() {
|
||||
_imageSurface.reset();
|
||||
_cachedImage.reset();
|
||||
}
|
||||
|
||||
void ImageElement::render(Window *window) {
|
||||
if (_imageSurface) {
|
||||
Common::Rect srcRect(_imageSurface->w, _imageSurface->h);
|
||||
if (_cachedImage) {
|
||||
Common::SharedPtr<Graphics::Surface> optimized = _cachedImage->optimize(_runtime);
|
||||
Common::Rect srcRect(optimized->w, optimized->h);
|
||||
Common::Rect destRect(_cachedAbsoluteOrigin.x, _cachedAbsoluteOrigin.y, _cachedAbsoluteOrigin.x + _rect.getWidth(), _cachedAbsoluteOrigin.y + _rect.getHeight());
|
||||
window->getSurface()->blitFrom(*_imageSurface, srcRect, destRect);
|
||||
window->getSurface()->blitFrom(*optimized, srcRect, destRect);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@ class VideoDecoder;
|
||||
|
||||
namespace MTropolis {
|
||||
|
||||
class CachedImage;
|
||||
struct ElementLoaderContext;
|
||||
|
||||
class GraphicElement : public VisualElement {
|
||||
@ -123,7 +124,7 @@ private:
|
||||
bool _cacheBitmap;
|
||||
uint32 _assetID;
|
||||
|
||||
Common::SharedPtr<Graphics::Surface> _imageSurface;
|
||||
Common::SharedPtr<CachedImage> _cachedImage;
|
||||
|
||||
Runtime *_runtime;
|
||||
};
|
||||
|
@ -46,9 +46,9 @@ struct RenderItem {
|
||||
template<class TNumber, int TResolution>
|
||||
void OrderedDitherGenerator<TNumber, TResolution>::generateOrderedDither(TNumber (&pattern)[TResolution][TResolution]) {
|
||||
const int kHalfResolution = TResolution / 2;
|
||||
byte halfRes[kHalfResolution][kHalfResolution];
|
||||
TNumber halfRes[kHalfResolution][kHalfResolution];
|
||||
|
||||
OrderedDitherGenerator<kHalfResolution>::generateOrderedDither(halfRes);
|
||||
OrderedDitherGenerator<TNumber, kHalfResolution>::generateOrderedDither(halfRes);
|
||||
|
||||
const int kHalfResNumSteps = kHalfResolution * kHalfResolution;
|
||||
for (int y = 0; y < kHalfResolution; y++) {
|
||||
@ -66,10 +66,18 @@ void OrderedDitherGenerator<TNumber, 1>::generateOrderedDither(TNumber (&pattern
|
||||
pattern[0][0] = 0;
|
||||
}
|
||||
|
||||
inline int quantize8To5(int value, byte orderedDither16x16) {
|
||||
inline int quantize8To5Byte(int value, byte orderedDither16x16) {
|
||||
return (value * 249 + (orderedDither16x16 << 3)) >> 11;
|
||||
}
|
||||
|
||||
inline int quantize8To5UShort(int value, uint16 orderedDither16x16) {
|
||||
return (value * 249 + orderedDither16x16) >> 11;
|
||||
}
|
||||
|
||||
inline int expand5To8(int value) {
|
||||
return (value * 33) >> 2;
|
||||
}
|
||||
|
||||
MacFontFormatting::MacFontFormatting() : fontID(0), fontFlags(0), size(12) {
|
||||
}
|
||||
|
||||
@ -244,6 +252,77 @@ void renderProject(Runtime *runtime, Window *mainWindow) {
|
||||
renderDirectElement(*it, mainWindow);
|
||||
}
|
||||
|
||||
void convert32To16(Graphics::Surface &destSurface, const Graphics::Surface &srcSurface) {
|
||||
const Graphics::PixelFormat srcFmt = srcSurface.format;
|
||||
const Graphics::PixelFormat destFmt = destSurface.format;
|
||||
|
||||
assert(srcFmt.bytesPerPixel == 4);
|
||||
assert(destFmt.bytesPerPixel == 2);
|
||||
assert(destSurface.w == srcSurface.w);
|
||||
assert(srcSurface.h == destSurface.h);
|
||||
|
||||
uint16 ditherPattern[16][16];
|
||||
OrderedDitherGenerator<uint16, 16>::generateOrderedDither(ditherPattern);
|
||||
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int y = 0; y < 16; y++)
|
||||
ditherPattern[y][x] <<= 3;
|
||||
}
|
||||
|
||||
|
||||
size_t w = srcSurface.w;
|
||||
size_t h = srcSurface.h;
|
||||
|
||||
for (size_t y = 0; y < h; y++) {
|
||||
const uint16 *ditherRow = ditherPattern[y % 16];
|
||||
const uint32 *srcRow = static_cast<const uint32*>(srcSurface.getBasePtr(0, y));
|
||||
uint16 *destRow = static_cast<uint16 *>(destSurface.getBasePtr(0, y));
|
||||
|
||||
for (size_t x = 0; x < w; x++) {
|
||||
uint16 ditherOffset = ditherRow[x % 16];
|
||||
uint32 packed32 = srcRow[x];
|
||||
uint8 r = (packed32 >> srcFmt.rShift) & 0xff;
|
||||
uint8 g = (packed32 >> srcFmt.gShift) & 0xff;
|
||||
uint8 b = (packed32 >> srcFmt.bShift) & 0xff;
|
||||
|
||||
r = quantize8To5UShort(r, ditherOffset);
|
||||
g = quantize8To5UShort(g, ditherOffset);
|
||||
b = quantize8To5UShort(b, ditherOffset);
|
||||
destRow[x] = (r << destFmt.rShift) | (g << destFmt.gShift) | (b << destFmt.bShift);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void convert16To32(Graphics::Surface &destSurface, const Graphics::Surface &srcSurface) {
|
||||
const Graphics::PixelFormat srcFmt = srcSurface.format;
|
||||
const Graphics::PixelFormat destFmt = destSurface.format;
|
||||
|
||||
assert(srcFmt.bytesPerPixel == 2);
|
||||
assert(destFmt.bytesPerPixel == 4);
|
||||
assert(destSurface.w == srcSurface.w);
|
||||
assert(srcSurface.h == destSurface.h);
|
||||
|
||||
size_t w = srcSurface.w;
|
||||
size_t h = srcSurface.h;
|
||||
|
||||
for (size_t y = 0; y < h; y++) {
|
||||
const uint32 *srcRow = static_cast<const uint32 *>(srcSurface.getBasePtr(0, y));
|
||||
uint16 *destRow = static_cast<uint16 *>(destSurface.getBasePtr(0, y));
|
||||
|
||||
for (size_t x = 0; x < w; x++) {
|
||||
uint32 packed16 = srcRow[x];
|
||||
uint8 r = (packed16 >> srcFmt.rShift) & 0x1f;
|
||||
uint8 g = (packed16 >> srcFmt.gShift) & 0x1f;
|
||||
uint8 b = (packed16 >> srcFmt.bShift) & 0x1f;
|
||||
|
||||
r = expand5To8(r);
|
||||
g = expand5To8(g);
|
||||
b = expand5To8(b);
|
||||
destRow[x] = (r << destFmt.rShift) | (g << destFmt.gShift) | (b << destFmt.bShift);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Render
|
||||
|
||||
} // End of namespace MTropolis
|
||||
|
@ -30,6 +30,7 @@
|
||||
namespace Graphics {
|
||||
|
||||
class ManagedSurface;
|
||||
struct Surface;
|
||||
|
||||
} // End of namespace Graphics
|
||||
|
||||
@ -111,6 +112,8 @@ namespace Render {
|
||||
|
||||
uint32 resolveRGB(uint8 r, uint8 g, uint8 b, const Graphics::PixelFormat &fmt);
|
||||
void renderProject(Runtime *runtime, Window *mainWindow);
|
||||
void convert32To16(Graphics::Surface &destSurface, const Graphics::Surface &srcSurface);
|
||||
void convert16To32(Graphics::Surface &destSurface, const Graphics::Surface &srcSurface);
|
||||
|
||||
} // End of namespace Render
|
||||
|
||||
|
@ -5044,6 +5044,15 @@ bool VariableModifier::isVariable() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VariableModifier::readAttribute(MiniscriptThread *thread, DynamicValue &result, const Common::String &attrib) {
|
||||
if (attrib == "value") {
|
||||
varGetValue(thread, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
return Modifier::readAttribute(thread, result, attrib);
|
||||
}
|
||||
|
||||
DynamicValueWriteProxy VariableModifier::createWriteProxy() {
|
||||
DynamicValueWriteProxy proxy;
|
||||
proxy.pod.objectRef = this;
|
||||
|
@ -2077,6 +2077,8 @@ public:
|
||||
virtual bool varSetValue(MiniscriptThread *thread, const DynamicValue &value) = 0;
|
||||
virtual void varGetValue(MiniscriptThread *thread, DynamicValue &dest) const = 0;
|
||||
|
||||
bool readAttribute(MiniscriptThread *thread, DynamicValue &result, const Common::String &attrib) override;
|
||||
|
||||
virtual DynamicValueWriteProxy createWriteProxy();
|
||||
|
||||
private:
|
||||
|
Loading…
Reference in New Issue
Block a user