1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-22 06:23:04 +01:00

Add draw to image API

This commit is contained in:
Ted John
2022-02-25 20:05:10 +00:00
parent e3a1733cdd
commit 818dcacb31
5 changed files with 83 additions and 5 deletions

View File

@@ -2829,7 +2829,9 @@ declare global {
setPixelData(id: number, data: PixelData): void;
/**
* Gets a {@link GraphicsContext} for the given image so that you can draw directly to it.
* Calls the given function with a {@link GraphicsContext} for the given image, allowing the
* ability to draw directly to it.
*
* Allocates or reallocates the image if not previously allocated or if the size is changed.
* The pixels of the image will persist between calls, so you can draw over the top of what
* is currently there. The default pixel colour will be 0 (transparent).
@@ -2838,10 +2840,11 @@ declare global {
* can in images is a good way to improve performance.
*
* Will error if given an ID of an image not owned by this plugin.
* @param id The id of the image to get a {@link GraphicsContext} for.
* @param id The id of the image to draw to.
* @param size The size the image that should be allocated.
* @param callback The function that will draw to the image.
*/
getGraphicsContext(id: number, size: ScreenSize): GraphicsContext;
draw(id: number, size: ScreenSize, callback: (g: GraphicsContext) => void): void;
}
type PixelData = RawPixelData | RlePixelData | PngPixelData;

View File

@@ -11,9 +11,12 @@
# include "CustomImages.h"
# include "ScGraphicsContext.hpp"
# include <openrct2/Context.h>
# include <openrct2/drawing/Image.h>
# include <openrct2/drawing/ImageImporter.h>
# include <openrct2/drawing/X8DrawingEngine.h>
# include <openrct2/scripting/Plugin.h>
using namespace OpenRCT2::Drawing;
@@ -393,6 +396,7 @@ namespace OpenRCT2::Scripting
el.flags |= G1_FLAG_RLE_COMPRESSION;
}
gfx_set_g1_element(id, &el);
drawing_engine_invalidate_image(id);
}
void DukSetPixelData(duk_context* ctx, ImageIndex id, const DukValue& dukPixelData)
@@ -409,6 +413,59 @@ namespace OpenRCT2::Scripting
}
}
void DukDrawCustomImage(ScriptEngine& scriptEngine, ImageIndex id, ScreenSize size, const DukValue& callback)
{
auto* ctx = scriptEngine.GetContext();
auto plugin = scriptEngine.GetExecInfo().GetCurrentPlugin();
auto drawingEngine = std::make_unique<X8DrawingEngine>(GetContext()->GetUiContext());
rct_drawpixelinfo dpi;
dpi.DrawingEngine = drawingEngine.get();
dpi.width = size.width;
dpi.height = size.height;
auto createNewImage = false;
auto g1 = gfx_get_g1_element(id);
if (g1 == nullptr || g1->width != size.width || g1->height != size.height || (g1->flags & G1_FLAG_RLE_COMPRESSION))
{
createNewImage = true;
}
if (createNewImage)
{
auto bufferSize = size.width* size.height;
dpi.bits = new uint8_t[bufferSize];
std::memset(dpi.bits, 0, bufferSize);
// Draw the original image if we are creating a new one
gfx_draw_sprite(&dpi, ImageId(id), { 0, 0 });
}
else
{
dpi.bits = g1->offset;
}
auto dukG = GetObjectAsDukValue(ctx, std::make_shared<ScGraphicsContext>(ctx, dpi));
scriptEngine.ExecutePluginCall(plugin, callback, { dukG }, false);
if (createNewImage)
{
rct_g1_element newg1{};
if (g1 != nullptr)
{
delete[] g1->offset;
newg1 = *g1;
}
newg1.offset = dpi.bits;
newg1.width = size.width;
newg1.height = size.height;
newg1.flags = 0;
gfx_set_g1_element(id, &newg1);
}
drawing_engine_invalidate_image(id);
}
} // namespace OpenRCT2::Scripting
#endif

View File

@@ -25,6 +25,7 @@ namespace OpenRCT2::Scripting
DukValue DukGetImageInfo(duk_context* ctx, ImageIndex id);
DukValue DukGetImagePixelData(duk_context* ctx, ImageIndex id);
void DukSetPixelData(duk_context* ctx, ImageIndex id, const DukValue& dukPixelData);
void DukDrawCustomImage(ScriptEngine& scriptEngine, ImageIndex id, ScreenSize size, const DukValue& callback);
} // namespace OpenRCT2::Scripting

View File

@@ -40,6 +40,7 @@ namespace OpenRCT2::Scripting
dukglue_register_method(ctx, &ScImageManager::getImageInfo, "getImageInfo");
dukglue_register_method(ctx, &ScImageManager::getPixelData, "getPixelData");
dukglue_register_method(ctx, &ScImageManager::setPixelData, "setPixelData");
dukglue_register_method(ctx, &ScImageManager::draw, "draw");
}
private:
@@ -127,6 +128,21 @@ namespace OpenRCT2::Scripting
DukSetPixelData(_ctx, id, pixelData);
}
void draw(int32_t id, const DukValue& dukSize, const DukValue& callback)
{
auto width = dukSize["width"].as_int();
auto height = dukSize["height"].as_int();
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.");
}
DukDrawCustomImage(scriptEngine, id, { width, height }, callback);
}
DukValue CreateImageIndexRange(size_t start, size_t count) const
{
DukObject obj(_ctx);

View File

@@ -89,17 +89,18 @@ void Plugin::Start()
throw std::runtime_error("No main function specified.");
}
_hasStarted = true;
mainFunc.push();
auto result = duk_pcall(_context, 0);
if (result != DUK_ERR_NONE)
{
auto val = std::string(duk_safe_to_string(_context, -1));
duk_pop(_context);
_hasStarted = false;
throw std::runtime_error("[" + _metadata.Name + "] " + val);
}
duk_pop(_context);
_hasStarted = true;
}
void Plugin::StopBegin()