/***************************************************************************** * Copyright (c) 2014-2025 OpenRCT2 developers * * For a complete list of all authors, please refer to contributors.md * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 * * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ #pragma once #ifdef ENABLE_SCRIPTING #include "CustomImages.h" #include #include namespace OpenRCT2::Scripting { class ScGraphicsContext { private: duk_context* _ctx{}; DrawPixelInfo _dpi{}; std::optional _colour{}; std::optional _secondaryColour{}; std::optional _tertiaryColour{}; std::optional _paletteId{}; uint8_t _stroke{}; uint8_t _fill{}; public: ScGraphicsContext(duk_context* ctx, const DrawPixelInfo& dpi) : _ctx(ctx) , _dpi(dpi) { } static void Register(duk_context* ctx) { dukglue_register_property(ctx, &ScGraphicsContext::colour_get, &ScGraphicsContext::colour_set, "colour"); dukglue_register_property( ctx, &ScGraphicsContext::secondaryColour_get, &ScGraphicsContext::secondaryColour_set, "secondaryColour"); dukglue_register_property( ctx, &ScGraphicsContext::tertiaryColour_get, &ScGraphicsContext::tertiaryColour_set, "ternaryColour"); dukglue_register_property( ctx, &ScGraphicsContext::tertiaryColour_get, &ScGraphicsContext::tertiaryColour_set, "tertiaryColour"); dukglue_register_property(ctx, &ScGraphicsContext::paletteId_get, &ScGraphicsContext::paletteId_set, "paletteId"); dukglue_register_property(ctx, &ScGraphicsContext::fill_get, &ScGraphicsContext::fill_set, "fill"); dukglue_register_property(ctx, &ScGraphicsContext::stroke_get, &ScGraphicsContext::stroke_set, "stroke"); dukglue_register_property(ctx, &ScGraphicsContext::width_get, nullptr, "width"); dukglue_register_property(ctx, &ScGraphicsContext::height_get, nullptr, "height"); dukglue_register_method(ctx, &ScGraphicsContext::getImage, "getImage"); dukglue_register_method(ctx, &ScGraphicsContext::measureText, "measureText"); dukglue_register_method(ctx, &ScGraphicsContext::box, "box"); dukglue_register_method(ctx, &ScGraphicsContext::clear, "clear"); dukglue_register_method(ctx, &ScGraphicsContext::clip, "clip"); dukglue_register_method(ctx, &ScGraphicsContext::image, "image"); dukglue_register_method(ctx, &ScGraphicsContext::line, "line"); dukglue_register_method(ctx, &ScGraphicsContext::rect, "rect"); dukglue_register_method(ctx, &ScGraphicsContext::text, "text"); dukglue_register_method(ctx, &ScGraphicsContext::well, "well"); } private: DukValue colour_get() const { return ToDuk(_ctx, _colour); } void colour_set(DukValue value) { if (value.type() == DukValue::NUMBER) _colour = static_cast(value.as_uint()); else _colour = {}; } DukValue secondaryColour_get() const { return ToDuk(_ctx, _secondaryColour); } void secondaryColour_set(DukValue value) { if (value.type() == DukValue::NUMBER) _secondaryColour = static_cast(value.as_uint()); else _secondaryColour = {}; } DukValue tertiaryColour_get() const { return ToDuk(_ctx, _tertiaryColour); } void tertiaryColour_set(DukValue value) { if (value.type() == DukValue::NUMBER) _tertiaryColour = static_cast(value.as_uint()); else _tertiaryColour = {}; } DukValue paletteId_get() const { return ToDuk(_ctx, _paletteId); } void paletteId_set(DukValue value) { if (value.type() == DukValue::NUMBER) _paletteId = static_cast(value.as_uint()); else _paletteId = {}; } uint8_t fill_get() const { return _fill; } void fill_set(uint8_t value) { _fill = value; } uint8_t stroke_get() const { return _stroke; } void stroke_set(uint8_t value) { _stroke = value; } int32_t width_get() const { return _dpi.width; } int32_t height_get() const { return _dpi.height; } DukValue getImage(uint32_t id) { return DukGetImageInfo(_ctx, id); } DukValue measureText(const std::string& text) { auto width = GfxGetStringWidth(text, FontStyle::Medium); auto height = StringGetHeightRaw(text.c_str(), FontStyle::Medium); return ToDuk(_ctx, { width, height }); } void box(int32_t x, int32_t y, int32_t width, int32_t height) { GfxFillRectInset(_dpi, { x, y, x + width - 1, y + height - 1 }, { _colour.value_or(0) }, 0); } void well(int32_t x, int32_t y, int32_t width, int32_t height) { GfxFillRectInset( _dpi, { x, y, x + width - 1, y + height - 1 }, { _colour.value_or(0) }, INSET_RECT_FLAG_BORDER_INSET | INSET_RECT_FLAG_FILL_DONT_LIGHTEN); } void clear() { GfxClear(_dpi, _fill); } void clip(int32_t x, int32_t y, int32_t width, int32_t height) { DrawPixelInfo newDpi; ClipDrawPixelInfo(newDpi, _dpi, { x, y }, width, height); _dpi = newDpi; } void image(uint32_t id, int32_t x, int32_t y) { ImageId img; img = img.WithIndex(id); if (_paletteId) { img = img.WithRemap(*_paletteId); } else { if (_colour) { img = img.WithPrimary(*_colour); } if (_secondaryColour) { img = img.WithSecondary(*_secondaryColour); } } GfxDrawSprite(_dpi, img.WithTertiary(_tertiaryColour.value_or(0)), { x, y }); } void line(int32_t x1, int32_t y1, int32_t x2, int32_t y2) { GfxDrawLine(_dpi, { { x1, y1 }, { x2, y2 } }, _stroke); } void rect(int32_t x, int32_t y, int32_t width, int32_t height) { if (_stroke != 0) { line(x, y, x + width, y); line(x + width - 1, y + 1, x + width - 1, y + height - 1); line(x, y + height - 1, x + width, y + height - 1); line(x, y + 1, x, y + height - 1); x++; y++; width -= 2; height -= 2; } if (_fill != 0) { GfxFillRect(_dpi, { x, y, x + width - 1, y + height - 1 }, _fill); } } void text(const std::string& text, int32_t x, int32_t y) { DrawText(_dpi, { x, y }, { _colour.value_or(0) }, text.c_str()); } }; } // namespace OpenRCT2::Scripting #endif