mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-12 22:51:11 +00:00
MTROPOLIS: Add image assets and elements
This commit is contained in:
parent
a1940c352a
commit
c5434a80dc
@ -63,6 +63,8 @@ IAssetFactory *getAssetFactoryForDataObjectType(const Data::DataObjectTypes::Dat
|
||||
return AssetFactory<AudioAsset, Data::AudioAsset>::getInstance();
|
||||
case Data::DataObjectTypes::kMovieAsset:
|
||||
return AssetFactory<MovieAsset, Data::MovieAsset>::getInstance();
|
||||
case Data::DataObjectTypes::kImageAsset:
|
||||
return AssetFactory<ImageAsset, Data::ImageAsset>::getInstance();
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
|
@ -122,5 +122,74 @@ size_t MovieAsset::getStreamIndex() const {
|
||||
return _streamIndex;
|
||||
}
|
||||
|
||||
bool ImageAsset::load(AssetLoaderContext &context, const Data::ImageAsset &data) {
|
||||
_assetID = data.assetID;
|
||||
if (!_rect.load(data.rect1))
|
||||
return false;
|
||||
_filePosition = data.filePosition;
|
||||
_size = data.size;
|
||||
_streamIndex = context.streamIndex;
|
||||
|
||||
switch (data.bitsPerPixel) {
|
||||
case 1:
|
||||
_colorDepth = kColorDepthMode1Bit;
|
||||
break;
|
||||
case 2:
|
||||
_colorDepth = kColorDepthMode2Bit;
|
||||
break;
|
||||
case 4:
|
||||
_colorDepth = kColorDepthMode4Bit;
|
||||
break;
|
||||
case 8:
|
||||
_colorDepth = kColorDepthMode8Bit;
|
||||
break;
|
||||
case 16:
|
||||
_colorDepth = kColorDepthMode16Bit;
|
||||
break;
|
||||
case 32:
|
||||
_colorDepth = kColorDepthMode32Bit;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data.haveMacPart)
|
||||
_imageFormat = kImageFormatMac;
|
||||
else if (data.haveWinPart)
|
||||
_imageFormat = kImageFormatWindows;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AssetType ImageAsset::getAssetType() const {
|
||||
return kAssetTypeImage;
|
||||
}
|
||||
|
||||
const Rect16& ImageAsset::getRect() const {
|
||||
return _rect;
|
||||
}
|
||||
|
||||
ColorDepthMode ImageAsset::getColorDepth() const {
|
||||
return _colorDepth;
|
||||
}
|
||||
|
||||
uint32 ImageAsset::getFilePosition() const {
|
||||
return _filePosition;
|
||||
}
|
||||
|
||||
uint32 ImageAsset::getSize() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
size_t ImageAsset::getStreamIndex() const {
|
||||
return _streamIndex;
|
||||
}
|
||||
|
||||
ImageAsset::ImageFormat ImageAsset::getImageFormat() const {
|
||||
return _imageFormat;
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace MTropolis
|
||||
|
@ -87,6 +87,32 @@ private:
|
||||
size_t _streamIndex;
|
||||
};
|
||||
|
||||
class ImageAsset : public Asset {
|
||||
public:
|
||||
bool load(AssetLoaderContext &context, const Data::ImageAsset &data);
|
||||
AssetType getAssetType() const override;
|
||||
|
||||
enum ImageFormat {
|
||||
kImageFormatMac,
|
||||
kImageFormatWindows,
|
||||
};
|
||||
|
||||
const Rect16 &getRect() const;
|
||||
ColorDepthMode getColorDepth() const;
|
||||
uint32 getFilePosition() const;
|
||||
uint32 getSize() const;
|
||||
size_t getStreamIndex() const;
|
||||
ImageFormat getImageFormat() const;
|
||||
|
||||
private:
|
||||
Rect16 _rect;
|
||||
ColorDepthMode _colorDepth;
|
||||
uint32 _filePosition;
|
||||
uint32 _size;
|
||||
size_t _streamIndex;
|
||||
ImageFormat _imageFormat;
|
||||
};
|
||||
|
||||
} // End of namespace MTropolis
|
||||
|
||||
#endif
|
||||
|
@ -1544,6 +1544,36 @@ DataReadErrorCode AudioAsset::load(DataReader &reader) {
|
||||
return kDataReadErrorNone;
|
||||
}
|
||||
|
||||
DataReadErrorCode ImageAsset::load(DataReader &reader) {
|
||||
if (_revision != 1)
|
||||
return kDataReadErrorUnsupportedRevision;
|
||||
|
||||
if (!reader.readU32(persistFlags) || !reader.readU32(unknown1) || !reader.readBytes(unknown2)
|
||||
|| !reader.readU32(assetID) || !reader.readU32(unknown3))
|
||||
return kDataReadErrorReadFailed;
|
||||
|
||||
haveWinPart = false;
|
||||
haveMacPart = false;
|
||||
|
||||
if (reader.getProjectFormat() == kProjectFormatMacintosh) {
|
||||
haveMacPart = true;
|
||||
if (!reader.readBytes(platform.mac.unknown7))
|
||||
return kDataReadErrorReadFailed;
|
||||
} else if (reader.getProjectFormat() == kProjectFormatWindows) {
|
||||
haveWinPart = true;
|
||||
if (!reader.readBytes(platform.win.unknown8))
|
||||
return kDataReadErrorReadFailed;
|
||||
} else
|
||||
return kDataReadErrorUnrecognized;
|
||||
|
||||
if (!rect1.load(reader) || !reader.readU32(hdpiFixed) || !reader.readU32(vdpiFixed) || !reader.readU16(bitsPerPixel)
|
||||
|| !reader.readBytes(unknown4) || !reader.readBytes(unknown5) || !reader.readBytes(unknown6)
|
||||
|| !rect2.load(reader) || !reader.readU32(filePosition) || !reader.readU32(size))
|
||||
return kDataReadErrorReadFailed;
|
||||
|
||||
return kDataReadErrorNone;
|
||||
}
|
||||
|
||||
DataReadErrorCode AssetDataChunk::load(DataReader &reader) {
|
||||
if (_revision != 0)
|
||||
return kDataReadErrorUnsupportedRevision;
|
||||
@ -1728,7 +1758,7 @@ DataReadErrorCode loadDataObject(const PlugInModifierRegistry ®istry, DataRea
|
||||
break;
|
||||
|
||||
case DataObjectTypes::kImageAsset:
|
||||
//dataObject = new ImageAsset();
|
||||
dataObject = new ImageAsset();
|
||||
break;
|
||||
|
||||
case DataObjectTypes::kMToonAsset:
|
||||
|
@ -1412,6 +1412,45 @@ protected:
|
||||
DataReadErrorCode load(DataReader &reader) override;
|
||||
};
|
||||
|
||||
struct ImageAsset : public DataObject {
|
||||
struct MacPart {
|
||||
uint8 unknown7[44];
|
||||
};
|
||||
|
||||
struct WinPart {
|
||||
uint8 unknown8[10];
|
||||
};
|
||||
|
||||
union PlatformPart {
|
||||
WinPart win;
|
||||
MacPart mac;
|
||||
};
|
||||
|
||||
uint32 persistFlags;
|
||||
uint32 unknown1;
|
||||
uint8_t unknown2[4];
|
||||
uint32 assetID;
|
||||
uint32 unknown3;
|
||||
|
||||
Rect rect1;
|
||||
uint32 hdpiFixed;
|
||||
uint32 vdpiFixed;
|
||||
uint16 bitsPerPixel;
|
||||
uint8 unknown4[2];
|
||||
uint8 unknown5[4];
|
||||
uint8 unknown6[8];
|
||||
Rect rect2;
|
||||
uint32 filePosition;
|
||||
uint32 size;
|
||||
|
||||
bool haveMacPart;
|
||||
bool haveWinPart;
|
||||
PlatformPart platform;
|
||||
|
||||
protected:
|
||||
DataReadErrorCode load(DataReader &reader) override;
|
||||
};
|
||||
|
||||
struct AssetDataChunk : public DataObject {
|
||||
uint32 unknown1;
|
||||
uint32 sizeIncludingTag;
|
||||
|
@ -64,6 +64,8 @@ IElementFactory *getElementFactoryForDataObjectType(const Data::DataObjectTypes:
|
||||
return ElementFactory<GraphicElement, Data::GraphicElement>::getInstance();
|
||||
case Data::DataObjectTypes::kMovieElement:
|
||||
return ElementFactory<MovieElement, Data::MovieElement>::getInstance();
|
||||
case Data::DataObjectTypes::kImageElement:
|
||||
return ElementFactory<ImageElement, Data::ImageElement>::getInstance();
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
|
@ -137,7 +137,6 @@ void MovieElement::activate() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Video::QuickTimeDecoder *qtDecoder = new Video::QuickTimeDecoder();
|
||||
qtDecoder->setChunkBeginOffset(movieAsset->getMovieDataPos());
|
||||
|
||||
@ -231,4 +230,197 @@ VThreadState MovieElement::startPlayingTask(const StartPlayingTaskData &taskData
|
||||
return kVThreadReturn;
|
||||
}
|
||||
|
||||
|
||||
ImageElement::ImageElement() : _cacheBitmap(false), _runtime(nullptr) {
|
||||
}
|
||||
|
||||
ImageElement::~ImageElement() {
|
||||
}
|
||||
|
||||
bool ImageElement::load(ElementLoaderContext &context, const Data::ImageElement &data) {
|
||||
if (!VisualElement::loadCommon(data.name, data.guid, data.rect1, data.elementFlags, data.layer, data.streamLocator, data.sectionID))
|
||||
return false;
|
||||
|
||||
_cacheBitmap = ((data.elementFlags & Data::ElementFlags::kCacheBitmap) != 0);
|
||||
_runtime = context.runtime;
|
||||
_assetID = data.imageAssetID;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImageElement::readAttribute(MiniscriptThread *thread, DynamicValue &result, const Common::String &attrib) {
|
||||
return VisualElement::readAttribute(thread, result, attrib);
|
||||
}
|
||||
|
||||
bool ImageElement::writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &writeProxy, const Common::String &attrib) {
|
||||
return VisualElement::writeRefAttribute(thread, writeProxy, attrib);
|
||||
}
|
||||
|
||||
void ImageElement::activate() {
|
||||
Project *project = _runtime->getProject();
|
||||
Common::SharedPtr<Asset> asset = project->getAssetByID(_assetID).lock();
|
||||
|
||||
if (!asset) {
|
||||
warning("Image element references asset %i but the asset isn't loaded!", _assetID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (asset->getAssetType() != kAssetTypeImage) {
|
||||
warning("Image element assigned an asset that isn't an image");
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImageElement::deactivate() {
|
||||
_imageSurface.reset();
|
||||
}
|
||||
|
||||
void ImageElement::render(Window *window) {
|
||||
if (_imageSurface) {
|
||||
Common::Rect srcRect(_imageSurface->w, _imageSurface->h);
|
||||
Common::Rect destRect(_rect.left, _rect.top, _rect.right, _rect.bottom);
|
||||
window->getSurface()->blitFrom(*_imageSurface, srcRect, destRect);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace MTropolis
|
||||
|
@ -60,8 +60,8 @@ public:
|
||||
|
||||
bool load(ElementLoaderContext &context, const Data::MovieElement &data);
|
||||
|
||||
bool readAttribute(MiniscriptThread *thread, DynamicValue &result, const Common::String &attrib);
|
||||
bool writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &writeProxy, const Common::String &attrib);
|
||||
bool readAttribute(MiniscriptThread *thread, DynamicValue &result, const Common::String &attrib) override;
|
||||
bool writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &writeProxy, const Common::String &attrib) override;
|
||||
VThreadState consumeCommand(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) override;
|
||||
|
||||
void activate() override;
|
||||
@ -103,6 +103,35 @@ private:
|
||||
Runtime *_runtime;
|
||||
};
|
||||
|
||||
class ImageElement : public VisualElement {
|
||||
public:
|
||||
ImageElement();
|
||||
~ImageElement();
|
||||
|
||||
bool load(ElementLoaderContext &context, const Data::ImageElement &data);
|
||||
|
||||
bool readAttribute(MiniscriptThread *thread, DynamicValue &result, const Common::String &attrib);
|
||||
bool writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &writeProxy, const Common::String &attrib);
|
||||
|
||||
void activate() override;
|
||||
void deactivate() override;
|
||||
|
||||
void render(Window *window) override;
|
||||
|
||||
#ifdef MTROPOLIS_DEBUG_ENABLE
|
||||
const char *debugGetTypeName() const override { return "Image Element"; }
|
||||
SupportStatus debugGetSupportStatus() const override { return kSupportStatusPartial; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool _cacheBitmap;
|
||||
uint32 _assetID;
|
||||
|
||||
Common::SharedPtr<Graphics::Surface> _imageSurface;
|
||||
|
||||
Runtime *_runtime;
|
||||
};
|
||||
|
||||
} // End of namespace MTropolis
|
||||
|
||||
#endif
|
||||
|
@ -2787,7 +2787,7 @@ void Runtime::removeWindow(Window *window) {
|
||||
}
|
||||
}
|
||||
|
||||
void Runtime::setupDisplayMode(ColorDepthMode displayMode, const Graphics::PixelFormat& pixelFormat) {
|
||||
void Runtime::setupDisplayMode(ColorDepthMode displayMode, const Graphics::PixelFormat &pixelFormat) {
|
||||
_displayModeSupported[displayMode] = true;
|
||||
_displayModePixelFormats[displayMode] = pixelFormat;
|
||||
}
|
||||
|
@ -1713,6 +1713,7 @@ enum AssetType {
|
||||
kAssetTypeMovie,
|
||||
kAssetTypeAudio,
|
||||
kAssetTypeColorTable,
|
||||
kAssetTypeImage,
|
||||
};
|
||||
|
||||
class Asset {
|
||||
|
Loading…
x
Reference in New Issue
Block a user