Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/base
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2024-03-25 03:46:21 +1100
committerKae <80987908+Novaenia@users.noreply.github.com>2024-03-25 03:46:21 +1100
commit560ae08424956bb495bc2453973467d138029c7c (patch)
treef506d79185388e7217af75a43074884f17349cb2 /source/base
parentff6e349aef9c5504896d1249b2d4a3b862c37d09 (diff)
Add support for directly setting image assets and processing Image userdata
Diffstat (limited to 'source/base')
-rw-r--r--source/base/CMakeLists.txt4
-rw-r--r--source/base/StarAssets.cpp20
-rw-r--r--source/base/StarAssets.hpp1
-rw-r--r--source/base/StarMemoryAssetSource.cpp59
-rw-r--r--source/base/StarMemoryAssetSource.hpp9
-rw-r--r--source/base/StarRootBase.cpp23
-rw-r--r--source/base/StarRootBase.hpp24
-rw-r--r--source/base/scripting/StarImageLuaBindings.cpp38
-rw-r--r--source/base/scripting/StarImageLuaBindings.hpp17
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();
+};
+
+}