From 8a821c83fd602cc30d5def99ebd194eb1fb67996 Mon Sep 17 00:00:00 2001 From: David Capello Date: Thu, 18 Apr 2019 22:23:33 -0300 Subject: [PATCH] lua: Add Brush class and app.useTool{ brush } parameter --- src/app/CMakeLists.txt | 1 + src/app/script/app_object.cpp | 58 ++++++- src/app/script/brush_class.cpp | 238 +++++++++++++++++++++++++++ src/app/script/color_class.cpp | 5 +- src/app/script/engine.cpp | 19 +++ src/app/script/engine.h | 3 + src/app/ui/editor/tool_loop_impl.cpp | 11 +- src/app/ui/editor/tool_loop_impl.h | 4 +- src/doc/brush.cpp | 15 +- src/doc/brush.h | 4 +- src/doc/brush_pattern.h | 8 +- 11 files changed, 340 insertions(+), 26 deletions(-) create mode 100644 src/app/script/brush_class.cpp diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index f13b5425c..06e626b37 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -150,6 +150,7 @@ if(ENABLE_SCRIPTING) commands/cmd_run_script.cpp script/app_command_object.cpp script/app_object.cpp + script/brush_class.cpp script/cel_class.cpp script/cels_class.cpp script/color_class.cpp diff --git a/src/app/script/app_object.cpp b/src/app/script/app_object.cpp index 6fc65f3f5..d45011971 100644 --- a/src/app/script/app_object.cpp +++ b/src/app/script/app_object.cpp @@ -29,6 +29,7 @@ #include "app/tools/tool_loop.h" #include "app/tools/tool_loop_manager.h" #include "app/tx.h" +#include "app/ui/context_bar.h" #include "app/ui/doc_view.h" #include "app/ui/editor/editor.h" #include "app/ui/editor/tool_loop_impl.h" @@ -287,11 +288,25 @@ int App_useTool(lua_State* L) color = convert_args_into_color(L, -1); lua_pop(L, 1); + // Default brush is the active brush in the context bar + BrushRef brush(nullptr); +#ifdef ENABLE_UI + if (App::instance()->isGui() && + App::instance()->contextBar()) + brush = App::instance()->contextBar()->activeBrush(tool, ink); +#endif + type = lua_getfield(L, 1, "brush"); + if (type != LUA_TNIL) + brush = get_brush_from_arg(L, -1); + lua_pop(L, 1); + if (!brush) + brush.reset(new Brush(BrushType::kCircleBrushType, 1, 0)); + // Do the tool loop type = lua_getfield(L, 1, "points"); if (type == LUA_TTABLE) { std::unique_ptr loop( - create_tool_loop_for_script(ctx, site, tool, ink, color)); + create_tool_loop_for_script(ctx, site, tool, ink, color, brush)); if (!loop) return luaL_error(L, "cannot draw in the active site"); @@ -478,6 +493,27 @@ int App_get_apiVersion(lua_State* L) return 1; } +int App_get_activeTool(lua_State* L) +{ + tools::Tool* tool = App::instance()->activeToolManager()->activeTool(); + push_tool(L, tool); + return 1; +} + +int App_get_activeBrush(lua_State* L) +{ +#if ENABLE_UI + App* app = App::instance(); + if (app->isGui()) { + doc::BrushRef brush = app->contextBar()->activeBrush(); + push_brush(L, brush); + return 1; + } +#endif + push_brush(L, doc::BrushRef(new doc::Brush())); + return 1; +} + int App_set_activeSprite(lua_State* L) { auto sprite = get_docobj(L, 2); @@ -524,13 +560,6 @@ int App_set_activeImage(lua_State* L) return 0; } -int App_get_activeTool(lua_State* L) -{ - tools::Tool* tool = App::instance()->activeToolManager()->activeTool(); - push_tool(L, tool); - return 1; -} - int App_set_activeTool(lua_State* L) { if (auto tool = get_tool_from_arg(L, 2)) @@ -538,6 +567,18 @@ int App_set_activeTool(lua_State* L) return 0; } +int App_set_activeBrush(lua_State* L) +{ +#if ENABLE_UI + if (auto brush = get_brush_from_arg(L, 2)) { + App* app = App::instance(); + if (app->isGui()) + app->contextBar()->setActiveBrush(brush); + } +#endif + return 0; +} + const luaL_Reg App_methods[] = { { "open", App_open }, { "exit", App_exit }, @@ -558,6 +599,7 @@ const Property App_properties[] = { { "activeImage", App_get_activeImage, App_set_activeImage }, { "activeTag", App_get_activeTag, nullptr }, { "activeTool", App_get_activeTool, App_set_activeTool }, + { "activeBrush", App_get_activeBrush, App_set_activeBrush }, { "sprites", App_get_sprites, nullptr }, { "fgColor", App_get_fgColor, App_set_fgColor }, { "bgColor", App_get_bgColor, App_set_bgColor }, diff --git a/src/app/script/brush_class.cpp b/src/app/script/brush_class.cpp new file mode 100644 index 000000000..93c742c3f --- /dev/null +++ b/src/app/script/brush_class.cpp @@ -0,0 +1,238 @@ +// Aseprite +// Copyright (C) 2019 Igara Studio S.A. +// +// This program is distributed under the terms of +// the End-User License Agreement for Aseprite. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "app/script/engine.h" +#include "app/script/luacpp.h" +#include "doc/brush.h" +#include "doc/image.h" + +#include + +namespace app { +namespace script { + +namespace { + +using namespace doc; + +struct BrushObj { + BrushRef brush; + BrushObj(const BrushRef& brush) + : brush(brush) { + } +}; + +BrushRef Brush_new(lua_State* L, int index) +{ + BrushRef brush; + if (auto brush2 = may_get_obj(L, index)) { + ASSERT(brush2->brush); + if (brush2->brush) + brush.reset(new Brush(*brush2->brush)); + } + else if (auto image = may_get_image_from_arg(L, index)) { + if (image) { + brush.reset(new Brush(kImageBrushType, 1, 0)); + brush->setImage(image, nullptr); + brush->setPattern(BrushPattern::DEFAULT_FOR_SCRIPTS); + } + } + else if (lua_istable(L, index)) { + Image* image = nullptr; + if (lua_getfield(L, index, "image") != LUA_TNIL) { + image = may_get_image_from_arg(L, -1); + } + lua_pop(L, 1); + + BrushType type = (image ? BrushType::kImageBrushType: + BrushType::kCircleBrushType); + if (lua_getfield(L, index, "type") != LUA_TNIL) + type = (BrushType)lua_tointeger(L, -1); + lua_pop(L, 1); + + int size = 1; + if (lua_getfield(L, index, "size") != LUA_TNIL) { + size = lua_tointeger(L, -1); + size = std::max(1, size); + } + lua_pop(L, 1); + + int angle = 0; + if (lua_getfield(L, index, "angle") != LUA_TNIL) + angle = lua_tointeger(L, -1); + lua_pop(L, 1); + + brush.reset(new Brush(type, size, angle)); + if (image) + brush->setImage(image, nullptr); + + if (lua_getfield(L, index, "center") != LUA_TNIL) { + gfx::Point center = convert_args_into_point(L, -1); + brush->setCenter(center); + } + lua_pop(L, 1); + + if (lua_getfield(L, index, "pattern") != LUA_TNIL) { + BrushPattern pattern = (BrushPattern)lua_tointeger(L, -1); + brush->setPattern(pattern); + } + else { + brush->setPattern(BrushPattern::DEFAULT_FOR_SCRIPTS); + } + lua_pop(L, 1); + + if (lua_getfield(L, index, "patternOrigin") != LUA_TNIL) { + gfx::Point patternOrigin = convert_args_into_point(L, -1); + brush->setPatternOrigin(patternOrigin); + } + lua_pop(L, 1); + } + else { + int size = lua_tointeger(L, index); + size = std::max(1, size); + brush.reset(new Brush(BrushType::kCircleBrushType, size, 0)); + brush->setPattern(BrushPattern::DEFAULT_FOR_SCRIPTS); + } + return brush; +} + +int Brush_new(lua_State* L) +{ + BrushRef brush = Brush_new(L, 1); + if (brush) + push_new(L, brush); + else + lua_pushnil(L); + return 1; +} + +int Brush_gc(lua_State* L) +{ + get_obj(L, 1)->~BrushObj(); + return 0; +} + +int Brush_setFgColor(lua_State* L) +{ + auto obj = get_obj(L, 1); + if (obj->brush) { + const doc::color_t color = convert_args_into_pixel_color(L, 2); + obj->brush->setImageColor(Brush::ImageColor::MainColor, color); + } + return 0; +} + +int Brush_setBgColor(lua_State* L) +{ + auto obj = get_obj(L, 1); + if (obj->brush) { + const doc::color_t color = convert_args_into_pixel_color(L, 2); + obj->brush->setImageColor(Brush::ImageColor::BackgroundColor, color); + } + return 0; +} + +int Brush_get_type(lua_State* L) +{ + const auto obj = get_obj(L, 1); + lua_pushinteger(L, (int)obj->brush->type()); + return 1; +} + +int Brush_get_size(lua_State* L) +{ + const auto obj = get_obj(L, 1); + lua_pushinteger(L, obj->brush->size()); + return 1; +} + +int Brush_get_angle(lua_State* L) +{ + const auto obj = get_obj(L, 1); + lua_pushinteger(L, obj->brush->angle()); + return 1; +} + +int Brush_get_image(lua_State* L) +{ + const auto obj = get_obj(L, 1); + if (obj->brush->type() == BrushType::kImageBrushType) + push_image(L, Image::createCopy(obj->brush->image())); + else + lua_pushnil(L); + return 1; +} + +int Brush_get_center(lua_State* L) +{ + const auto obj = get_obj(L, 1); + push_obj(L, obj->brush->center()); + return 1; +} + +int Brush_get_pattern(lua_State* L) +{ + const auto obj = get_obj(L, 1); + lua_pushinteger(L, (int)obj->brush->pattern()); + return 1; +} + +int Brush_get_patternOrigin(lua_State* L) +{ + const auto obj = get_obj(L, 1); + push_obj(L, obj->brush->patternOrigin()); + return 1; +} + +const luaL_Reg Brush_methods[] = { + { "__gc", Brush_gc }, + { "setFgColor", Brush_setFgColor }, + { "setBgColor", Brush_setBgColor }, + { nullptr, nullptr } +}; + +const Property Brush_properties[] = { + { "type", Brush_get_type, nullptr }, + { "size", Brush_get_size, nullptr }, + { "angle", Brush_get_angle, nullptr }, + { "image", Brush_get_image, nullptr }, + { "center", Brush_get_center, nullptr }, + { "pattern", Brush_get_pattern, nullptr }, + { "patternOrigin", Brush_get_patternOrigin, nullptr }, + { nullptr, nullptr, nullptr } +}; + +} // anonymous namespace + +DEF_MTNAME(BrushObj); + +void register_brush_class(lua_State* L) +{ + using Brush = BrushObj; + REG_CLASS(L, Brush); + REG_CLASS_NEW(L, Brush); + REG_CLASS_PROPERTIES(L, Brush); +} + +void push_brush(lua_State* L, const BrushRef& brush) +{ + push_new(L, brush); +} + +BrushRef get_brush_from_arg(lua_State* L, int index) +{ + if (auto obj = may_get_obj(L, index)) + return obj->brush; + else + return Brush_new(L, index); +} + +} // namespace script +} // namespace app diff --git a/src/app/script/color_class.cpp b/src/app/script/color_class.cpp index 36b69a77c..ee0147a5d 100644 --- a/src/app/script/color_class.cpp +++ b/src/app/script/color_class.cpp @@ -1,4 +1,5 @@ // Aseprite +// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2018 David Capello // // This program is distributed under the terms of @@ -137,7 +138,7 @@ app::Color Color_new(lua_State* L, int index) } // raw color into app color else if (!lua_isnone(L, index)) { - if (lua_isinteger(L, index) && lua_isnone(L, index+1)) { + if (lua_isinteger(L, index) && (index < 0 || lua_isnone(L, index+1))) { doc::color_t docColor = lua_tointeger(L, index); switch (app_get_current_pixel_format()) { case IMAGE_RGB: @@ -155,7 +156,7 @@ app::Color Color_new(lua_State* L, int index) break; } } - else { + else if (index >= 0) { color = app::Color::fromRgb(lua_tointeger(L, index), lua_tointeger(L, index+1), lua_tointeger(L, index+2), diff --git a/src/app/script/engine.cpp b/src/app/script/engine.cpp index dd9571484..391c8fa50 100644 --- a/src/app/script/engine.cpp +++ b/src/app/script/engine.cpp @@ -136,6 +136,7 @@ void register_app_object(lua_State* L); void register_app_pixel_color_object(lua_State* L); void register_app_command_object(lua_State* L); +void register_brush_class(lua_State* L); void register_cel_class(lua_State* L); void register_cels_class(lua_State* L); void register_color_class(lua_State* L); @@ -298,7 +299,25 @@ Engine::Engine() setfield_integer(L, "JSON_ARRAY", DocExporter::JsonArrayDataFormat); lua_pop(L, 1); + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setglobal(L, "BrushType"); + setfield_integer(L, "CIRCLE", doc::kCircleBrushType); + setfield_integer(L, "SQUARE", doc::kSquareBrushType); + setfield_integer(L, "LINE", doc::kLineBrushType); + setfield_integer(L, "IMAGE", doc::kImageBrushType); + lua_pop(L, 1); + + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setglobal(L, "BrushPattern"); + setfield_integer(L, "ORIGIN", doc::BrushPattern::ALIGNED_TO_SRC); + setfield_integer(L, "TARGET", doc::BrushPattern::ALIGNED_TO_DST); + setfield_integer(L, "NONE", doc::BrushPattern::PAINT_BRUSH); + lua_pop(L, 1); + // Register classes/prototypes + register_brush_class(L); register_cel_class(L); register_cels_class(L); register_color_class(L); diff --git a/src/app/script/engine.h b/src/app/script/engine.h index cf57a7240..c0429e257 100644 --- a/src/app/script/engine.h +++ b/src/app/script/engine.h @@ -15,6 +15,7 @@ #include "app/color.h" #include "app/commands/params.h" +#include "doc/brush.h" #include "doc/frame.h" #include "doc/object_ids.h" #include "gfx/fwd.h" @@ -108,6 +109,7 @@ namespace app { }; int push_image_iterator_function(lua_State* L, const doc::Image* image, int extraArgIndex); + void push_brush(lua_State* L, const doc::BrushRef& brush); void push_cel_image(lua_State* L, doc::Cel* cel); void push_cels(lua_State* L, const doc::ObjectIds& cels); void push_cels(lua_State* L, doc::Layer* layer); @@ -143,6 +145,7 @@ namespace app { doc::frame_t get_frame_number_from_arg(lua_State* L, int index); const doc::Mask* get_mask_from_arg(lua_State* L, int index); tools::Tool* get_tool_from_arg(lua_State* L, int index); + doc::BrushRef get_brush_from_arg(lua_State* L, int index); // Used by App.open(), Sprite{ fromFile }, and Image{ fromFile } enum class LoadSpriteFromFileParam { FullAniAsSprite, diff --git a/src/app/ui/editor/tool_loop_impl.cpp b/src/app/ui/editor/tool_loop_impl.cpp index 0c97847ec..6ce0908cd 100644 --- a/src/app/ui/editor/tool_loop_impl.cpp +++ b/src/app/ui/editor/tool_loop_impl.cpp @@ -42,7 +42,6 @@ #include "app/ui/status_bar.h" #include "app/ui_context.h" #include "app/util/expand_cel_canvas.h" -#include "doc/brush.h" #include "doc/cel.h" #include "doc/image.h" #include "doc/layer.h" @@ -689,7 +688,8 @@ tools::ToolLoop* create_tool_loop_for_script( const Site& site, tools::Tool* tool, tools::Ink* ink, - const app::Color& color) + const app::Color& color, + const doc::BrushRef& brush) { ASSERT(tool); ASSERT(ink); @@ -699,13 +699,6 @@ tools::ToolLoop* create_tool_loop_for_script( try { const tools::ToolLoop::Button toolLoopButton = tools::ToolLoop::Left; tools::Controller* controller = tool->getController(toolLoopButton); - BrushRef brush(nullptr); -#ifdef ENABLE_UI - if (App::instance()->contextBar()) - brush = App::instance()->contextBar()->activeBrush(tool, ink); -#endif - if (!brush) - brush = BrushRef(new Brush(BrushType::kCircleBrushType, 1, 0)); return new ToolLoopImpl( nullptr, site, context, diff --git a/src/app/ui/editor/tool_loop_impl.h b/src/app/ui/editor/tool_loop_impl.h index 2a2a7d491..2710f8578 100644 --- a/src/app/ui/editor/tool_loop_impl.h +++ b/src/app/ui/editor/tool_loop_impl.h @@ -10,6 +10,7 @@ #pragma once #include "app/tools/pointer.h" +#include "doc/brush.h" #include "doc/image_ref.h" #include "gfx/fwd.h" @@ -40,7 +41,8 @@ namespace app { const Site& site, tools::Tool* tool, tools::Ink* ink, - const app::Color& color); + const app::Color& color, + const doc::BrushRef& brush); tools::ToolLoop* create_tool_loop_preview( Editor* editor, diff --git a/src/doc/brush.cpp b/src/doc/brush.cpp index 282d0cda0..f6a2fe127 100644 --- a/src/doc/brush.cpp +++ b/src/doc/brush.cpp @@ -1,5 +1,6 @@ // Aseprite Document Library -// Copyright (c) 2001-2016 David Capello +// Copyright (C) 2019 Igara Studio S.A. +// Copyright (C) 2001-2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -29,7 +30,7 @@ Brush::Brush() m_type = kCircleBrushType; m_size = 1; m_angle = 0; - m_pattern = BrushPattern::DEFAULT; + m_pattern = BrushPattern::DEFAULT_FOR_UI; m_gen = 0; regenerate(); @@ -40,7 +41,7 @@ Brush::Brush(BrushType type, int size, int angle) m_type = type; m_size = size; m_angle = angle; - m_pattern = BrushPattern::DEFAULT; + m_pattern = BrushPattern::DEFAULT_FOR_UI; m_gen = 0; regenerate(); @@ -279,6 +280,14 @@ void Brush::setImageColor(ImageColor imageColor, color_t color) } } +void Brush::setCenter(const gfx::Point& center) +{ + m_center = center; + m_bounds = gfx::Rect(-m_center, + gfx::Size(m_image->width(), + m_image->height())); +} + // Cleans the brush's data (image and region). void Brush::clean() { diff --git a/src/doc/brush.h b/src/doc/brush.h index 150b6b4a4..362274fc4 100644 --- a/src/doc/brush.h +++ b/src/doc/brush.h @@ -1,5 +1,6 @@ // Aseprite Document Library -// Copyright (c) 2001-2018 David Capello +// Copyright (C) 2019 Igara Studio S.A. +// Copyright (C) 2001-2018 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -57,6 +58,7 @@ namespace doc { void setPatternOrigin(const gfx::Point& patternOrigin) { m_patternOrigin = patternOrigin; } + void setCenter(const gfx::Point& center); private: void clean(); diff --git a/src/doc/brush_pattern.h b/src/doc/brush_pattern.h index 61069716b..5c3283fe4 100644 --- a/src/doc/brush_pattern.h +++ b/src/doc/brush_pattern.h @@ -1,5 +1,6 @@ // Aseprite Document Library -// Copyright (c) 2001-2015 David Capello +// Copyright (C) 2019 Igara Studio S.A. +// Copyright (C) 2001-2015 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -11,10 +12,13 @@ namespace doc { enum class BrushPattern { - DEFAULT = 0, ALIGNED_TO_SRC = 0, ALIGNED_TO_DST = 1, PAINT_BRUSH = 2, + + DEFAULT = ALIGNED_TO_SRC, // Default for preferences + DEFAULT_FOR_UI = ALIGNED_TO_SRC, + DEFAULT_FOR_SCRIPTS = PAINT_BRUSH, }; } // namespace doc