mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-22 06:23:04 +01:00
Improve graphics plugin API
This commit is contained in:
33
distribution/openrct2.d.ts
vendored
33
distribution/openrct2.d.ts
vendored
@@ -70,6 +70,14 @@ declare global {
|
||||
y: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the width and height in pixels.
|
||||
*/
|
||||
interface ScreenSize {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A coordinate within the game.
|
||||
* Each in-game tile is a size of 32x32.
|
||||
@@ -2207,19 +2215,40 @@ declare global {
|
||||
* API for drawing graphics.
|
||||
*/
|
||||
interface GraphicsContext {
|
||||
colour: number;
|
||||
colour: number | undefined;
|
||||
secondaryColour: number | undefined;
|
||||
ternaryColour: number | undefined;
|
||||
stroke: number;
|
||||
fill: number;
|
||||
paletteId: number | undefined;
|
||||
readonly width: number;
|
||||
readonly height: number;
|
||||
|
||||
getImage(id: number): ImageInfo | undefined;
|
||||
measureText(text: string): ScreenSize;
|
||||
|
||||
clear(): void;
|
||||
clip(x: number, y: number, width: number, height: number): void;
|
||||
box(x: number, y: number, width: number, height: number): void;
|
||||
image(image: number, x: number, y: number): void;
|
||||
image(id: number, x: number, y: number): void;
|
||||
line(x1: number, y1: number, x2: number, y2: number): void;
|
||||
rect(x: number, y: number, width: number, height: number): void;
|
||||
text(text: string, x: number, y: number): void;
|
||||
well(x: number, y: number, width: number, height: number): void;
|
||||
}
|
||||
|
||||
interface ImageInfo {
|
||||
readonly id: number;
|
||||
readonly offset: ScreenCoordsXY;
|
||||
readonly width: number;
|
||||
readonly height: number;
|
||||
readonly isBMP: boolean;
|
||||
readonly isRLE: boolean;
|
||||
readonly isPalette: boolean;
|
||||
readonly noZoom: boolean;
|
||||
readonly nextZoomId: number | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for incoming connections.
|
||||
* Based on node.js net.Server, see https://nodejs.org/api/net.html for more information.
|
||||
|
||||
@@ -22,7 +22,10 @@ namespace OpenRCT2::Scripting
|
||||
duk_context* _ctx{};
|
||||
rct_drawpixelinfo _dpi{};
|
||||
|
||||
colour_t _colour{};
|
||||
std::optional<colour_t> _colour{};
|
||||
std::optional<colour_t> _secondaryColour{};
|
||||
std::optional<colour_t> _ternaryColour{};
|
||||
std::optional<uint8_t> _paletteId{};
|
||||
uint8_t _stroke{};
|
||||
uint8_t _fill{};
|
||||
|
||||
@@ -36,25 +39,80 @@ namespace OpenRCT2::Scripting
|
||||
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::ternaryColour_get, &ScGraphicsContext::ternaryColour_set, "ternaryColour");
|
||||
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:
|
||||
colour_t colour_get() const
|
||||
DukValue colour_get() const
|
||||
{
|
||||
return _colour;
|
||||
return ToDuk(_ctx, _colour);
|
||||
}
|
||||
|
||||
void colour_set(colour_t value)
|
||||
void colour_set(DukValue value)
|
||||
{
|
||||
_colour = value;
|
||||
if (value.type() == DukValue::NUMBER)
|
||||
_colour = static_cast<colour_t>(value.as_int());
|
||||
else
|
||||
_colour = {};
|
||||
}
|
||||
|
||||
DukValue secondaryColour_get() const
|
||||
{
|
||||
return ToDuk(_ctx, _secondaryColour);
|
||||
}
|
||||
|
||||
void secondaryColour_set(DukValue value)
|
||||
{
|
||||
if (value.type() == DukValue::NUMBER)
|
||||
_secondaryColour = static_cast<colour_t>(value.as_int());
|
||||
else
|
||||
_secondaryColour = {};
|
||||
}
|
||||
|
||||
DukValue ternaryColour_get() const
|
||||
{
|
||||
return ToDuk(_ctx, _ternaryColour);
|
||||
}
|
||||
|
||||
void ternaryColour_set(DukValue value)
|
||||
{
|
||||
if (value.type() == DukValue::NUMBER)
|
||||
_ternaryColour = static_cast<colour_t>(value.as_int());
|
||||
else
|
||||
_ternaryColour = {};
|
||||
}
|
||||
|
||||
DukValue paletteId_get() const
|
||||
{
|
||||
return ToDuk(_ctx, _paletteId);
|
||||
}
|
||||
|
||||
void paletteId_set(DukValue value)
|
||||
{
|
||||
if (value.type() == DukValue::NUMBER)
|
||||
_paletteId = static_cast<uint8_t>(value.as_int());
|
||||
else
|
||||
_paletteId = {};
|
||||
}
|
||||
|
||||
uint8_t fill_get() const
|
||||
@@ -77,14 +135,66 @@ namespace OpenRCT2::Scripting
|
||||
_stroke = value;
|
||||
}
|
||||
|
||||
int32_t width_get() const
|
||||
{
|
||||
return _dpi.width;
|
||||
}
|
||||
|
||||
int32_t height_get() const
|
||||
{
|
||||
return _dpi.height;
|
||||
}
|
||||
|
||||
DukValue getImage(uint32_t id)
|
||||
{
|
||||
auto* g1 = gfx_get_g1_element(id);
|
||||
if (g1 == nullptr)
|
||||
{
|
||||
return ToDuk(_ctx, undefined);
|
||||
}
|
||||
else
|
||||
{
|
||||
DukObject obj(_ctx);
|
||||
obj.Set("id", id);
|
||||
obj.Set("offset", ToDuk<ScreenCoordsXY>(_ctx, { g1->x_offset, g1->y_offset }));
|
||||
obj.Set("width", g1->width);
|
||||
obj.Set("height", g1->height);
|
||||
|
||||
obj.Set("isBMP", (g1->flags & G1_FLAG_BMP) != 0);
|
||||
obj.Set("isRLE", (g1->flags & G1_FLAG_RLE_COMPRESSION) != 0);
|
||||
obj.Set("isPalette", (g1->flags & G1_FLAG_PALETTE) != 0);
|
||||
obj.Set("noZoom", (g1->flags & G1_FLAG_NO_ZOOM_DRAW) != 0);
|
||||
|
||||
if (g1->flags & G1_FLAG_HAS_ZOOM_SPRITE)
|
||||
{
|
||||
obj.Set("nextZoomId", id - g1->zoomed_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.Set("nextZoomId", undefined);
|
||||
}
|
||||
return obj.Take();
|
||||
}
|
||||
}
|
||||
|
||||
DukValue measureText(const std::string& text)
|
||||
{
|
||||
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
|
||||
auto width = gfx_get_string_width(text);
|
||||
auto height = string_get_height_raw(text.c_str());
|
||||
return ToDuk<ScreenSize>(_ctx, { width, height });
|
||||
}
|
||||
|
||||
void box(int32_t x, int32_t y, int32_t width, int32_t height)
|
||||
{
|
||||
gfx_fill_rect_inset(&_dpi, { x, y, x + width - 1, y + height - 1 }, _colour, 0);
|
||||
gfx_fill_rect_inset(&_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)
|
||||
{
|
||||
gfx_fill_rect_inset(&_dpi, { x, y, x + width - 1, y + height - 1 }, _colour, INSET_RECT_FLAG_BORDER_INSET | INSET_RECT_FLAG_FILL_DONT_LIGHTEN);
|
||||
gfx_fill_rect_inset(
|
||||
&_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()
|
||||
@@ -99,6 +209,28 @@ namespace OpenRCT2::Scripting
|
||||
_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);
|
||||
}
|
||||
}
|
||||
gfx_draw_sprite(&_dpi, static_cast<int32_t>(img.ToUInt32()), { x, y }, _ternaryColour.value_or(0));
|
||||
}
|
||||
|
||||
void line(int32_t x1, int32_t y1, int32_t x2, int32_t y2)
|
||||
{
|
||||
gfx_draw_line(&_dpi, { { x1, y1 }, { x2, y2 } }, _stroke);
|
||||
@@ -106,7 +238,28 @@ namespace OpenRCT2::Scripting
|
||||
|
||||
void rect(int32_t x, int32_t y, int32_t width, int32_t height)
|
||||
{
|
||||
gfx_fill_rect(&_dpi, { x, y, x + width - 1, y + height - 1 }, _fill);
|
||||
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)
|
||||
{
|
||||
gfx_fill_rect(&_dpi, { x, y, x + width - 1, y + height - 1 }, _fill);
|
||||
}
|
||||
}
|
||||
|
||||
void text(const std::string& text, int32_t x, int32_t y)
|
||||
{
|
||||
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
|
||||
gfx_draw_string(&_dpi, text.c_str(), _colour.value_or(0), { x, y });
|
||||
}
|
||||
};
|
||||
} // namespace OpenRCT2::Scripting
|
||||
|
||||
@@ -356,7 +356,7 @@ void draw_string_centred_raw(rct_drawpixelinfo* dpi, const ScreenCoordsXY& coord
|
||||
}
|
||||
}
|
||||
|
||||
int32_t string_get_height_raw(char* buffer)
|
||||
int32_t string_get_height_raw(std::string_view text)
|
||||
{
|
||||
uint16_t fontBase = gCurrentFontSpriteBase;
|
||||
|
||||
@@ -366,7 +366,7 @@ int32_t string_get_height_raw(char* buffer)
|
||||
else if (fontBase == FONT_SPRITE_BASE_TINY)
|
||||
height += 6;
|
||||
|
||||
FmtString fmt(buffer);
|
||||
FmtString fmt(text);
|
||||
for (const auto& token : fmt)
|
||||
{
|
||||
switch (token.kind)
|
||||
|
||||
@@ -459,6 +459,13 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr ImageId WithRemap(uint8_t paletteId)
|
||||
{
|
||||
ImageId result = *this;
|
||||
result._value = (_value & ~MASK_REMAP) | ((paletteId << SHIFT_REMAP) & MASK_REMAP) | FLAG_PRIMARY;
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr ImageId WithPrimary(colour_t colour)
|
||||
{
|
||||
ImageId result = *this;
|
||||
@@ -757,7 +764,7 @@ int32_t gfx_wrap_string(char* buffer, int32_t width, int32_t* num_lines, int32_t
|
||||
int32_t gfx_get_string_width(std::string_view text);
|
||||
int32_t gfx_get_string_width_new_lined(std::string_view text);
|
||||
int32_t gfx_get_string_width_no_formatting(std::string_view text);
|
||||
int32_t string_get_height_raw(char* buffer);
|
||||
int32_t string_get_height_raw(std::string_view text);
|
||||
int32_t gfx_clip_string(char* buffer, int32_t width);
|
||||
void shorten_path(utf8* buffer, size_t bufferSize, const utf8* path, int32_t availableWidth);
|
||||
void ttf_draw_string(
|
||||
|
||||
@@ -50,6 +50,11 @@ namespace OpenRCT2::Scripting
|
||||
return value.type() == DukValue::BOOLEAN ? value.as_bool() : defaultValue;
|
||||
}
|
||||
|
||||
enum class DukUndefined
|
||||
{
|
||||
};
|
||||
constexpr DukUndefined undefined{};
|
||||
|
||||
/**
|
||||
* Allows creation of an object on the duktape stack and setting properties on it before
|
||||
* retrieving the DukValue instance of it.
|
||||
@@ -88,6 +93,13 @@ namespace OpenRCT2::Scripting
|
||||
duk_put_prop_string(_ctx, _idx, name);
|
||||
}
|
||||
|
||||
void Set(const char* name, DukUndefined)
|
||||
{
|
||||
EnsureObjectPushed();
|
||||
duk_push_undefined(_ctx);
|
||||
duk_put_prop_string(_ctx, _idx, name);
|
||||
}
|
||||
|
||||
void Set(const char* name, bool value)
|
||||
{
|
||||
EnsureObjectPushed();
|
||||
@@ -277,12 +289,24 @@ namespace OpenRCT2::Scripting
|
||||
return DukValue::take_from_stack(ctx);
|
||||
}
|
||||
|
||||
template<> inline DukValue ToDuk(duk_context* ctx, const DukUndefined&)
|
||||
{
|
||||
duk_push_undefined(ctx);
|
||||
return DukValue::take_from_stack(ctx);
|
||||
}
|
||||
|
||||
template<> inline DukValue ToDuk(duk_context* ctx, const bool& value)
|
||||
{
|
||||
duk_push_boolean(ctx, value);
|
||||
return DukValue::take_from_stack(ctx);
|
||||
}
|
||||
|
||||
template<> inline DukValue ToDuk(duk_context* ctx, const uint8_t& value)
|
||||
{
|
||||
duk_push_int(ctx, value);
|
||||
return DukValue::take_from_stack(ctx);
|
||||
}
|
||||
|
||||
template<> inline DukValue ToDuk(duk_context* ctx, const int32_t& value)
|
||||
{
|
||||
duk_push_int(ctx, value);
|
||||
@@ -401,6 +425,14 @@ namespace OpenRCT2::Scripting
|
||||
return result;
|
||||
}
|
||||
|
||||
template<> inline DukValue ToDuk(duk_context* ctx, const ScreenSize& value)
|
||||
{
|
||||
DukObject dukCoords(ctx);
|
||||
dukCoords.Set("width", value.width);
|
||||
dukCoords.Set("height", value.height);
|
||||
return dukCoords.Take();
|
||||
}
|
||||
|
||||
} // namespace OpenRCT2::Scripting
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user