diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2024-03-25 03:46:21 +1100 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2024-03-25 03:46:21 +1100 |
commit | 560ae08424956bb495bc2453973467d138029c7c (patch) | |
tree | f506d79185388e7217af75a43074884f17349cb2 /source/base | |
parent | ff6e349aef9c5504896d1249b2d4a3b862c37d09 (diff) |
Add support for directly setting image assets and processing Image userdata
Diffstat (limited to 'source/base')
-rw-r--r-- | source/base/CMakeLists.txt | 4 | ||||
-rw-r--r-- | source/base/StarAssets.cpp | 20 | ||||
-rw-r--r-- | source/base/StarAssets.hpp | 1 | ||||
-rw-r--r-- | source/base/StarMemoryAssetSource.cpp | 59 | ||||
-rw-r--r-- | source/base/StarMemoryAssetSource.hpp | 9 | ||||
-rw-r--r-- | source/base/StarRootBase.cpp | 23 | ||||
-rw-r--r-- | source/base/StarRootBase.hpp | 24 | ||||
-rw-r--r-- | source/base/scripting/StarImageLuaBindings.cpp | 38 | ||||
-rw-r--r-- | source/base/scripting/StarImageLuaBindings.hpp | 17 |
9 files changed, 179 insertions, 16 deletions
diff --git a/source/base/CMakeLists.txt b/source/base/CMakeLists.txt index 8f4d18b..e813e45 100644 --- a/source/base/CMakeLists.txt +++ b/source/base/CMakeLists.txt @@ -17,9 +17,11 @@ SET (star_base_HEADERS StarMemoryAssetSource.hpp StarMixer.hpp StarPackedAssetSource.hpp + StarRootBase.hpp StarVersion.hpp StarVersionOptionParser.hpp StarWorldGeometry.hpp + scripting/StarImageLuaBindings.hpp ) SET (star_base_SOURCES @@ -32,8 +34,10 @@ SET (star_base_SOURCES StarMemoryAssetSource.cpp StarMixer.cpp StarPackedAssetSource.cpp + StarRootBase.cpp StarVersionOptionParser.cpp StarWorldGeometry.cpp + scripting/StarImageLuaBindings.cpp ) CONFIGURE_FILE (StarVersion.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/StarVersion.cpp) diff --git a/source/base/StarAssets.cpp b/source/base/StarAssets.cpp index d4b7228..9718ec8 100644 --- a/source/base/StarAssets.cpp +++ b/source/base/StarAssets.cpp @@ -145,7 +145,10 @@ Assets::Assets(Settings settings, StringList assetSources) { ByteArray bytes; if (auto str = engine.luaMaybeTo<String>(data)) bytes = ByteArray(str->utf8Ptr(), str->utf8Size()); - else { + else if (auto image = engine.luaMaybeTo<Image>(data)) { + newFiles->set(path, std::move(*image)); + return; + } else { auto json = engine.luaTo<Json>(data).repr(); bytes = ByteArray(json.utf8Ptr(), json.utf8Size()); } @@ -855,6 +858,19 @@ ByteArray Assets::read(String const& path) const { throw AssetException(strf("No such asset '{}'", path)); } +ImageConstPtr Assets::readImage(String const& path) const { + if (auto p = m_files.ptr(path)) { + ImageConstPtr image; + if (auto memorySource = as<MemoryAssetSource>(p->source)) + image = memorySource->image(p->sourceName); + if (!image) + image = make_shared<Image>(Image::readPng(p->source->open(p->sourceName))); + return image; + } + throw AssetException(strf("No such asset '{}'", path)); +} + + Json Assets::checkPatchArray(String const& path, AssetSourcePtr const& source, Json const result, JsonArray const patchData, Maybe<Json> const external) const { auto externalRef = external.value(); auto newResult = result; @@ -1140,7 +1156,7 @@ shared_ptr<Assets::AssetData> Assets::loadImage(AssetPath const& path) const { } else { auto imageData = make_shared<ImageData>(); imageData->image = unlockDuring([&]() { - return make_shared<Image>(Image::readPng(open(path.basePath))); + return readImage(path.basePath); }); imageData->frames = bestFramesSpecification(path.basePath); diff --git a/source/base/StarAssets.hpp b/source/base/StarAssets.hpp index 8cfbc52..952e024 100644 --- a/source/base/StarAssets.hpp +++ b/source/base/StarAssets.hpp @@ -275,6 +275,7 @@ private: IODevicePtr open(String const& basePath) const; ByteArray read(String const& basePath) const; + ImageConstPtr readImage(String const& path) const; Json readJson(String const& basePath) const; Json checkPatchArray(String const& path, AssetSourcePtr const& source, Json const result, JsonArray const patchData, Maybe<Json> const external) const; diff --git a/source/base/StarMemoryAssetSource.cpp b/source/base/StarMemoryAssetSource.cpp index 17e3749..a0c220d 100644 --- a/source/base/StarMemoryAssetSource.cpp +++ b/source/base/StarMemoryAssetSource.cpp @@ -1,7 +1,7 @@ #include "StarMemoryAssetSource.hpp" #include "StarDataStreamDevices.hpp" #include "StarDataStreamExtra.hpp" -#include "StarSha256.hpp" +#include "StarImage.hpp" namespace Star { @@ -21,11 +21,17 @@ StringList MemoryAssetSource::assetPaths() const { IODevicePtr MemoryAssetSource::open(String const& path) { struct AssetReader : public IODevice { - AssetReader(ByteArrayPtr assetData, String name) : assetData(assetData), name(name) { setMode(IOMode::Read); } + AssetReader(char* assetData, size_t assetSize, String name) { + this->assetData = assetData; + this->assetSize = assetSize; + this->name = std::move(name); + setMode(IOMode::Read); + } size_t read(char* data, size_t len) override { - len = min<StreamOffset>(len, StreamOffset(assetData->size()) - assetPos); - assetData->copyTo(data, len); + len = min<StreamOffset>(len, StreamOffset(assetSize) - assetPos); + memcpy(data, assetData + assetPos, len); + assetPos += len; return len; } @@ -33,25 +39,26 @@ IODevicePtr MemoryAssetSource::open(String const& path) { throw IOException("Assets IODevices are read-only"); } - StreamOffset size() override { return assetData->size(); } + StreamOffset size() override { return assetSize; } StreamOffset pos() override { return assetPos; } String deviceName() const override { return name; } bool atEnd() override { - return assetPos >= assetData->size(); + return assetPos >= assetSize; } void seek(StreamOffset p, IOSeek mode) override { if (mode == IOSeek::Absolute) assetPos = p; else if (mode == IOSeek::Relative) - assetPos = clamp<StreamOffset>(assetPos + p, 0, assetData->size()); + assetPos = clamp<StreamOffset>(assetPos + p, 0, assetSize); else - assetPos = clamp<StreamOffset>(assetPos - p, 0, assetData->size()); + assetPos = clamp<StreamOffset>(assetPos - p, 0, assetSize); } - ByteArrayPtr assetData; + char* assetData; + size_t assetSize; StreamOffset assetPos = 0; String name; }; @@ -59,8 +66,12 @@ IODevicePtr MemoryAssetSource::open(String const& path) { auto p = m_files.ptr(path); if (!p) throw AssetSourceException::format("Requested file '{}' does not exist in memory", path); - - return make_shared<AssetReader>(*p, path); + else if (auto byteArray = p->ptr<ByteArray>()) + return make_shared<AssetReader>(byteArray->ptr(), byteArray->size(), path); + else { + auto image = p->get<ImagePtr>().get(); + return make_shared<AssetReader>((char*)image->data(), image->width() * image->height() * image->bytesPerPixel(), path); + } } bool MemoryAssetSource::empty() const { @@ -76,15 +87,37 @@ bool MemoryAssetSource::erase(String const& path) { } void MemoryAssetSource::set(String const& path, ByteArray data) { - m_files[path] = make_shared<ByteArray>(std::move(data)); + m_files[path] = std::move(data); +} + +void MemoryAssetSource::set(String const& path, Image const& image) { + m_files[path] = make_shared<Image>(image); +} + +void MemoryAssetSource::set(String const& path, Image&& image) { + m_files[path] = make_shared<Image>(std::move(image)); } ByteArray MemoryAssetSource::read(String const& path) { auto p = m_files.ptr(path); if (!p) throw AssetSourceException::format("Requested file '{}' does not exist in memory", path); + else if (auto bytes = p->ptr<ByteArray>()) + return *bytes; + else { + Image const* image = p->get<ImagePtr>().get(); + return ByteArray((char const*)image->data(), image->width() * image->height() * image->bytesPerPixel()); + } +} + +ImageConstPtr MemoryAssetSource::image(String const& path) { + auto p = m_files.ptr(path); + if (!p) + throw AssetSourceException::format("Requested file '{}' does not exist in memory", path); + else if (auto imagePtr = p->ptr<ImagePtr>()) + return *imagePtr; else - return *p->get(); // this is a double indirection, and that freaking sucks!! + return nullptr; } } diff --git a/source/base/StarMemoryAssetSource.hpp b/source/base/StarMemoryAssetSource.hpp index e5ef740..1fc5733 100644 --- a/source/base/StarMemoryAssetSource.hpp +++ b/source/base/StarMemoryAssetSource.hpp @@ -6,6 +6,7 @@ namespace Star { STAR_CLASS(MemoryAssetSource); +STAR_CLASS(Image); class MemoryAssetSource : public AssetSource { public: @@ -15,17 +16,23 @@ public: JsonObject metadata() const override; StringList assetPaths() const override; + // do not use the returned IODevice after the file is gone or bad things will happen IODevicePtr open(String const& path) override; bool empty() const; bool contains(String const& path) const; bool erase(String const& path); void set(String const& path, ByteArray data); + void set(String const& path, Image const& image); + void set(String const& path, Image&& image); ByteArray read(String const& path) override; + ImageConstPtr image(String const& path); private: + typedef Variant<ByteArray, ImagePtr> FileEntry; + String m_name; JsonObject m_metadata; - StringMap<ByteArrayPtr> m_files; + StringMap<FileEntry> m_files; }; } diff --git a/source/base/StarRootBase.cpp b/source/base/StarRootBase.cpp new file mode 100644 index 0000000..e6bd99d --- /dev/null +++ b/source/base/StarRootBase.cpp @@ -0,0 +1,23 @@ +#include "StarRootBase.hpp" + +namespace Star { + atomic<RootBase*> RootBase::s_singleton; + + RootBase* RootBase::singletonPtr() { + return s_singleton.load(); + } + + RootBase& RootBase::singleton() { + auto ptr = s_singleton.load(); + if (!ptr) + throw RootException("RootBase::singleton() called with no Root instance available"); + else + return *ptr; + } + + RootBase::RootBase() { + RootBase* oldRoot = nullptr; + if (!s_singleton.compare_exchange_strong(oldRoot, this)) + throw RootException("Singleton Root has been constructed twice"); + } +}
\ No newline at end of file diff --git a/source/base/StarRootBase.hpp b/source/base/StarRootBase.hpp new file mode 100644 index 0000000..48a6a5e --- /dev/null +++ b/source/base/StarRootBase.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "StarAssets.hpp" + +namespace Star { + +STAR_CLASS(Configuration); + +STAR_EXCEPTION(RootException, StarException); + +class RootBase { +public: + static RootBase* singletonPtr(); + static RootBase& singleton(); + + virtual AssetsConstPtr assets() = 0; + virtual ConfigurationPtr configuration() = 0; +protected: + RootBase(); + + static atomic<RootBase*> s_singleton; +}; + +}
\ No newline at end of file diff --git a/source/base/scripting/StarImageLuaBindings.cpp b/source/base/scripting/StarImageLuaBindings.cpp new file mode 100644 index 0000000..0f5d1e4 --- /dev/null +++ b/source/base/scripting/StarImageLuaBindings.cpp @@ -0,0 +1,38 @@ +#include "StarImageLuaBindings.hpp" +#include "StarLuaConverters.hpp" +#include "StarImage.hpp" +#include "StarRootBase.hpp" + +namespace Star { + +LuaMethods<Image> LuaUserDataMethods<Image>::make() { + LuaMethods<Image> methods; + + methods.registerMethodWithSignature<Vec2U, Image&>("size", mem_fn(&Image::size)); + methods.registerMethodWithSignature<void, Image&, Vec2U, Image&>("drawInto", mem_fn(&Image::drawInto)); + methods.registerMethodWithSignature<void, Image&, Vec2U, Image&>("copyInto", mem_fn(&Image::copyInto)); + methods.registerMethod("set", [](Image& image, unsigned x, unsigned y, Color const& color) { + image.set(x, y, color.toRgba()); + }); + + methods.registerMethod("get", [](Image& image, unsigned x, unsigned y) { + return Color::rgba(image.get(x, y)); + }); + + methods.registerMethod("subImage", [](Image& image, Vec2U const& min, Vec2U const& size) { + return image.subImage(min, size); + }); + + methods.registerMethod("process", [](Image& image, String const& directives) { + return processImageOperations(parseImageOperations(directives), image, [](String const& path) -> Image const* { + if (auto root = RootBase::singletonPtr()) + return root->assets()->image(path).get(); + else + return nullptr; + }); + }); + + return methods; +} + +} diff --git a/source/base/scripting/StarImageLuaBindings.hpp b/source/base/scripting/StarImageLuaBindings.hpp new file mode 100644 index 0000000..b49598d --- /dev/null +++ b/source/base/scripting/StarImageLuaBindings.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "StarLua.hpp" + +namespace Star { + +STAR_CLASS(Image); + +template <> +struct LuaConverter<Image> : LuaUserDataConverter<Image> {}; + +template <> +struct LuaUserDataMethods<Image> { + static LuaMethods<Image> make(); +}; + +} |