1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-02-02 19:56:13 +01:00

Implement plugin ownership of images

This commit is contained in:
Ted John
2022-02-25 18:49:52 +00:00
parent a977bbaebe
commit e3a1733cdd
5 changed files with 162 additions and 15 deletions

View File

@@ -11,7 +11,11 @@
# include "CustomImages.h"
# include <openrct2/Context.h>
# include <openrct2/drawing/Image.h>
# include <openrct2/drawing/ImageImporter.h>
# include <openrct2/scripting/Plugin.h>
using namespace OpenRCT2::Drawing;
namespace OpenRCT2::Scripting
@@ -43,6 +47,97 @@ namespace OpenRCT2::Scripting
DukValue Data;
};
struct AllocatedImageList
{
std::shared_ptr<Plugin> Owner;
ImageList Range;
};
static std::vector<AllocatedImageList> _allocatedImages;
static void FreeImages(ImageList range)
{
for (ImageIndex i = 0; i < range.Count; i++)
{
auto index = range.BaseId + i;
auto g1 = gfx_get_g1_element(index);
if (g1 != nullptr)
{
// Free pixel data
delete[] g1->offset;
// Replace slot with empty element
rct_g1_element empty{};
gfx_set_g1_element(index, &empty);
}
}
gfx_object_free_images(range.BaseId, range.Count);
}
std::optional<ImageList> AllocateCustomImages(const std::shared_ptr<Plugin>& plugin, uint32_t count)
{
std::vector<rct_g1_element> images;
images.resize(count);
auto base = gfx_object_allocate_images(images.data(), count);
if (base == ImageIndexUndefined)
{
return {};
}
auto range = ImageList(base, count);
AllocatedImageList item;
item.Owner = plugin;
item.Range = range;
_allocatedImages.push_back(std::move(item));
return range;
}
bool FreeCustomImages(const std::shared_ptr<Plugin>& plugin, ImageList range)
{
auto it = std::find_if(
_allocatedImages.begin(), _allocatedImages.end(),
[&plugin, range](const AllocatedImageList& item) { return item.Owner == plugin && item.Range == range; });
if (it == _allocatedImages.end())
{
return false;
}
FreeImages(it->Range);
_allocatedImages.erase(it);
return true;
}
bool DoesPluginOwnImage(const std::shared_ptr<Plugin>& plugin, ImageIndex index)
{
auto it = std::find_if(
_allocatedImages.begin(), _allocatedImages.end(),
[&plugin, index](const AllocatedImageList& item) { return item.Owner == plugin && item.Range.Contains(index); });
return it != _allocatedImages.end();
}
static void FreeCustomImages(const std::shared_ptr<Plugin>& plugin)
{
auto it = _allocatedImages.begin();
while (it != _allocatedImages.end())
{
if (it->Owner == plugin)
{
FreeImages(it->Range);
it = _allocatedImages.erase(it);
}
else
{
it++;
}
}
}
void InitialiseCustomImages(ScriptEngine& scriptEngine)
{
scriptEngine.SubscribeToPluginStoppedEvent([](std::shared_ptr<Plugin> plugin) -> void { FreeCustomImages(plugin); });
}
DukValue DukGetImageInfo(duk_context* ctx, ImageIndex id)
{
auto* g1 = gfx_get_g1_element(id);

View File

@@ -11,11 +11,17 @@
#ifdef ENABLE_SCRIPTING
# include <openrct2/drawing/Image.h>
# include <openrct2/drawing/ImageId.hpp>
# include <openrct2/scripting/Duktape.hpp>
# include <openrct2/scripting/ScriptEngine.h>
namespace OpenRCT2::Scripting
{
void InitialiseCustomImages(ScriptEngine& scriptEngine);
std::optional<ImageList> AllocateCustomImages(const std::shared_ptr<Plugin>& plugin, uint32_t count);
bool FreeCustomImages(const std::shared_ptr<Plugin>& plugin, ImageList range);
bool DoesPluginOwnImage(const std::shared_ptr<Plugin>& plugin, ImageIndex index);
DukValue DukGetImageInfo(duk_context* ctx, ImageIndex id);
DukValue DukGetImagePixelData(duk_context* ctx, ImageIndex id);
void DukSetPixelData(duk_context* ctx, ImageIndex id, const DukValue& dukPixelData);

View File

@@ -13,6 +13,7 @@
# include "CustomImages.h"
# include <openrct2/Context.h>
# include <openrct2/drawing/Image.h>
# include <openrct2/scripting/Duktape.hpp>
# include <openrct2/sprites.h>
@@ -83,22 +84,25 @@ namespace OpenRCT2::Scripting
DukValue allocate(int32_t count)
{
std::vector<rct_g1_element> images;
images.resize(count);
auto base = gfx_object_allocate_images(images.data(), count);
if (base == ImageIndexUndefined)
{
return ToDuk(_ctx, nullptr);
}
return CreateImageIndexRange(base, count);
auto& scriptEngine = GetContext()->GetScriptEngine();
auto plugin = scriptEngine.GetExecInfo().GetCurrentPlugin();
auto range = AllocateCustomImages(plugin, count);
return range ? CreateImageIndexRange(range->BaseId, range->Count) : ToDuk(_ctx, nullptr);
}
void free(const DukValue& range)
void free(const DukValue& dukRange)
{
auto start = range["start"].as_int();
auto count = range["count"].as_int();
gfx_object_free_images(start, count);
auto start = dukRange["start"].as_int();
auto count = dukRange["count"].as_int();
ImageList range(start, count);
auto& scriptEngine = GetContext()->GetScriptEngine();
auto plugin = scriptEngine.GetExecInfo().GetCurrentPlugin();
if (!FreeCustomImages(plugin, range))
{
duk_error(_ctx, DUK_ERR_ERROR, "This plugin did not allocate the specified image range.");
}
}
DukValue getImageInfo(int32_t id)
@@ -113,6 +117,13 @@ namespace OpenRCT2::Scripting
void setPixelData(int32_t id, const DukValue& pixelData)
{
auto& scriptEngine = GetContext()->GetScriptEngine();
auto plugin = scriptEngine.GetExecInfo().GetCurrentPlugin();
if (!DoesPluginOwnImage(plugin, id))
{
duk_error(_ctx, DUK_ERR_ERROR, "This plugin did not allocate the specified image.");
}
DukSetPixelData(_ctx, id, pixelData);
}

View File

@@ -11,6 +11,7 @@
# include "UiExtensions.h"
# include "CustomImages.h"
# include "CustomMenu.h"
# include "ScGraphicsContext.hpp"
# include "ScImageManager.hpp"
@@ -55,6 +56,7 @@ void UiScriptExtensions::Extend(ScriptEngine& scriptEngine)
ScTitleSequencePark::Register(ctx);
ScWindow::Register(ctx);
InitialiseCustomImages(scriptEngine);
InitialiseCustomMenuItems(scriptEngine);
scriptEngine.SubscribeToPluginStoppedEvent(
[](std::shared_ptr<Plugin> plugin) -> void { CloseWindowsOwnedByPlugin(plugin); });

View File

@@ -12,15 +12,48 @@
#include <cstddef>
#include <cstdint>
#include <list>
#include <openrct2/drawing/ImageId.hpp>
struct rct_g1_element;
struct ImageList
{
uint32_t BaseId;
uint32_t Count;
ImageIndex BaseId{};
ImageIndex Count{};
ImageList() = default;
ImageList(ImageIndex baseId, ImageIndex count)
: BaseId(baseId)
, Count(count)
{
}
bool Contains(ImageIndex index) const
{
return index >= BaseId && index < GetEnd();
}
ImageIndex GetEnd() const
{
return BaseId + Count;
}
static ImageList FromBeginEnd(ImageIndex begin, ImageIndex end)
{
return ImageList(begin, end - begin);
}
};
constexpr bool operator==(const ImageList& lhs, const ImageList& rhs)
{
return lhs.BaseId == rhs.BaseId && lhs.Count == rhs.Count;
}
constexpr bool operator!=(const ImageList& lhs, const ImageList& rhs)
{
return !(lhs == rhs);
}
uint32_t gfx_object_allocate_images(const rct_g1_element* images, uint32_t count);
void gfx_object_free_images(uint32_t baseImageId, uint32_t count);
void gfx_object_check_all_images_freed();