1 /***************************************************************************** 2 * Copyright (c) 2014-2020 OpenRCT2 developers 3 * 4 * For a complete list of all authors, please refer to contributors.md 5 * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 6 * 7 * OpenRCT2 is licensed under the GNU General Public License version 3. 8 *****************************************************************************/ 9 10 #pragma once 11 12 #ifdef ENABLE_SCRIPTING 13 14 # include <openrct2/drawing/Drawing.h> 15 # include <openrct2/scripting/Duktape.hpp> 16 17 namespace OpenRCT2::Scripting 18 { 19 class ScGraphicsContext 20 { 21 private: 22 duk_context* _ctx{}; 23 rct_drawpixelinfo _dpi{}; 24 25 std::optional<colour_t> _colour{}; 26 std::optional<colour_t> _secondaryColour{}; 27 std::optional<colour_t> _ternaryColour{}; 28 std::optional<uint8_t> _paletteId{}; 29 uint8_t _stroke{}; 30 uint8_t _fill{}; 31 32 public: ScGraphicsContext(duk_context * ctx,const rct_drawpixelinfo & dpi)33 ScGraphicsContext(duk_context* ctx, const rct_drawpixelinfo& dpi) 34 : _ctx(ctx) 35 , _dpi(dpi) 36 { 37 } 38 Register(duk_context * ctx)39 static void Register(duk_context* ctx) 40 { 41 dukglue_register_property(ctx, &ScGraphicsContext::colour_get, &ScGraphicsContext::colour_set, "colour"); 42 dukglue_register_property( 43 ctx, &ScGraphicsContext::secondaryColour_get, &ScGraphicsContext::secondaryColour_set, "secondaryColour"); 44 dukglue_register_property( 45 ctx, &ScGraphicsContext::ternaryColour_get, &ScGraphicsContext::ternaryColour_set, "ternaryColour"); 46 dukglue_register_property(ctx, &ScGraphicsContext::paletteId_get, &ScGraphicsContext::paletteId_set, "paletteId"); 47 dukglue_register_property(ctx, &ScGraphicsContext::fill_get, &ScGraphicsContext::fill_set, "fill"); 48 dukglue_register_property(ctx, &ScGraphicsContext::stroke_get, &ScGraphicsContext::stroke_set, "stroke"); 49 dukglue_register_property(ctx, &ScGraphicsContext::width_get, nullptr, "width"); 50 dukglue_register_property(ctx, &ScGraphicsContext::height_get, nullptr, "height"); 51 52 dukglue_register_method(ctx, &ScGraphicsContext::getImage, "getImage"); 53 dukglue_register_method(ctx, &ScGraphicsContext::measureText, "measureText"); 54 55 dukglue_register_method(ctx, &ScGraphicsContext::box, "box"); 56 dukglue_register_method(ctx, &ScGraphicsContext::clear, "clear"); 57 dukglue_register_method(ctx, &ScGraphicsContext::clip, "clip"); 58 dukglue_register_method(ctx, &ScGraphicsContext::image, "image"); 59 dukglue_register_method(ctx, &ScGraphicsContext::line, "line"); 60 dukglue_register_method(ctx, &ScGraphicsContext::rect, "rect"); 61 dukglue_register_method(ctx, &ScGraphicsContext::text, "text"); 62 dukglue_register_method(ctx, &ScGraphicsContext::well, "well"); 63 } 64 65 private: colour_get() const66 DukValue colour_get() const 67 { 68 return ToDuk(_ctx, _colour); 69 } 70 colour_set(DukValue value)71 void colour_set(DukValue value) 72 { 73 if (value.type() == DukValue::NUMBER) 74 _colour = static_cast<colour_t>(value.as_int()); 75 else 76 _colour = {}; 77 } 78 secondaryColour_get() const79 DukValue secondaryColour_get() const 80 { 81 return ToDuk(_ctx, _secondaryColour); 82 } 83 secondaryColour_set(DukValue value)84 void secondaryColour_set(DukValue value) 85 { 86 if (value.type() == DukValue::NUMBER) 87 _secondaryColour = static_cast<colour_t>(value.as_int()); 88 else 89 _secondaryColour = {}; 90 } 91 ternaryColour_get() const92 DukValue ternaryColour_get() const 93 { 94 return ToDuk(_ctx, _ternaryColour); 95 } 96 ternaryColour_set(DukValue value)97 void ternaryColour_set(DukValue value) 98 { 99 if (value.type() == DukValue::NUMBER) 100 _ternaryColour = static_cast<colour_t>(value.as_int()); 101 else 102 _ternaryColour = {}; 103 } 104 paletteId_get() const105 DukValue paletteId_get() const 106 { 107 return ToDuk(_ctx, _paletteId); 108 } 109 paletteId_set(DukValue value)110 void paletteId_set(DukValue value) 111 { 112 if (value.type() == DukValue::NUMBER) 113 _paletteId = static_cast<uint8_t>(value.as_int()); 114 else 115 _paletteId = {}; 116 } 117 fill_get() const118 uint8_t fill_get() const 119 { 120 return _fill; 121 } 122 fill_set(uint8_t value)123 void fill_set(uint8_t value) 124 { 125 _fill = value; 126 } 127 stroke_get() const128 uint8_t stroke_get() const 129 { 130 return _stroke; 131 } 132 stroke_set(uint8_t value)133 void stroke_set(uint8_t value) 134 { 135 _stroke = value; 136 } 137 width_get() const138 int32_t width_get() const 139 { 140 return _dpi.width; 141 } 142 height_get() const143 int32_t height_get() const 144 { 145 return _dpi.height; 146 } 147 getImage(uint32_t id)148 DukValue getImage(uint32_t id) 149 { 150 auto* g1 = gfx_get_g1_element(id); 151 if (g1 == nullptr) 152 { 153 return ToDuk(_ctx, undefined); 154 } 155 156 DukObject obj(_ctx); 157 obj.Set("id", id); 158 obj.Set("offset", ToDuk<ScreenCoordsXY>(_ctx, { g1->x_offset, g1->y_offset })); 159 obj.Set("width", g1->width); 160 obj.Set("height", g1->height); 161 162 obj.Set("isBMP", (g1->flags & G1_FLAG_BMP) != 0); 163 obj.Set("isRLE", (g1->flags & G1_FLAG_RLE_COMPRESSION) != 0); 164 obj.Set("isPalette", (g1->flags & G1_FLAG_PALETTE) != 0); 165 obj.Set("noZoom", (g1->flags & G1_FLAG_NO_ZOOM_DRAW) != 0); 166 167 if (g1->flags & G1_FLAG_HAS_ZOOM_SPRITE) 168 { 169 obj.Set("nextZoomId", id - g1->zoomed_offset); 170 } 171 else 172 { 173 obj.Set("nextZoomId", undefined); 174 } 175 return obj.Take(); 176 } 177 measureText(const std::string & text)178 DukValue measureText(const std::string& text) 179 { 180 auto width = gfx_get_string_width(text, FontSpriteBase::MEDIUM); 181 auto height = string_get_height_raw(text.c_str(), FontSpriteBase::MEDIUM); 182 return ToDuk<ScreenSize>(_ctx, { width, height }); 183 } 184 box(int32_t x,int32_t y,int32_t width,int32_t height)185 void box(int32_t x, int32_t y, int32_t width, int32_t height) 186 { 187 gfx_fill_rect_inset(&_dpi, { x, y, x + width - 1, y + height - 1 }, _colour.value_or(0), 0); 188 } 189 well(int32_t x,int32_t y,int32_t width,int32_t height)190 void well(int32_t x, int32_t y, int32_t width, int32_t height) 191 { 192 gfx_fill_rect_inset( 193 &_dpi, { x, y, x + width - 1, y + height - 1 }, _colour.value_or(0), 194 INSET_RECT_FLAG_BORDER_INSET | INSET_RECT_FLAG_FILL_DONT_LIGHTEN); 195 } 196 clear()197 void clear() 198 { 199 gfx_clear(&_dpi, _fill); 200 } 201 clip(int32_t x,int32_t y,int32_t width,int32_t height)202 void clip(int32_t x, int32_t y, int32_t width, int32_t height) 203 { 204 rct_drawpixelinfo newDpi; 205 clip_drawpixelinfo(&newDpi, &_dpi, { x, y }, width, height); 206 _dpi = newDpi; 207 } 208 image(uint32_t id,int32_t x,int32_t y)209 void image(uint32_t id, int32_t x, int32_t y) 210 { 211 ImageId img; 212 img = img.WithIndex(id); 213 if (_paletteId) 214 { 215 img = img.WithRemap(*_paletteId); 216 } 217 else 218 { 219 if (_colour) 220 { 221 img = img.WithPrimary(*_colour); 222 } 223 if (_secondaryColour) 224 { 225 img = img.WithSecondary(*_secondaryColour); 226 } 227 } 228 229 gfx_draw_sprite(&_dpi, img.WithTertiary(_ternaryColour.value_or(0)), { x, y }); 230 } 231 line(int32_t x1,int32_t y1,int32_t x2,int32_t y2)232 void line(int32_t x1, int32_t y1, int32_t x2, int32_t y2) 233 { 234 gfx_draw_line(&_dpi, { { x1, y1 }, { x2, y2 } }, _stroke); 235 } 236 rect(int32_t x,int32_t y,int32_t width,int32_t height)237 void rect(int32_t x, int32_t y, int32_t width, int32_t height) 238 { 239 if (_stroke != 0) 240 { 241 line(x, y, x + width, y); 242 line(x + width - 1, y + 1, x + width - 1, y + height - 1); 243 line(x, y + height - 1, x + width, y + height - 1); 244 line(x, y + 1, x, y + height - 1); 245 246 x++; 247 y++; 248 width -= 2; 249 height -= 2; 250 } 251 if (_fill != 0) 252 { 253 gfx_fill_rect(&_dpi, { x, y, x + width - 1, y + height - 1 }, _fill); 254 } 255 } 256 text(const std::string & text,int32_t x,int32_t y)257 void text(const std::string& text, int32_t x, int32_t y) 258 { 259 gfx_draw_string(&_dpi, { x, y }, text.c_str(), { _colour.value_or(0) }); 260 } 261 }; 262 } // namespace OpenRCT2::Scripting 263 264 #endif 265