From 080e7e3f683b9f50e32d0ee20b9d31b1a4c60387 Mon Sep 17 00:00:00 2001 From: David Capello Date: Mon, 10 Oct 2016 23:42:47 -0300 Subject: [PATCH] Add subpixel bounds for reference layer cels Now we can move a reference layer cel in a X,Y position with floating point coordinates (i.e. in a subpixel position). --- src/app/CMakeLists.txt | 1 + src/app/cmd/set_cel_bounds.cpp | 51 ++++++++++++++ src/app/cmd/set_cel_bounds.h | 40 +++++++++++ src/app/extra_cel.cpp | 4 +- src/app/ui/editor/editor.cpp | 11 +++ src/app/ui/editor/editor.h | 1 + src/app/ui/editor/moving_cel_state.cpp | 81 ++++++++++++++------- src/app/ui/editor/moving_cel_state.h | 10 +-- src/doc/cel.cpp | 7 +- src/doc/cel.h | 2 + src/doc/cel_data.cpp | 14 +++- src/doc/cel_data.h | 31 +++++++- src/gfx/CMakeLists.txt | 1 - src/gfx/clip.cpp | 64 ----------------- src/gfx/clip.h | 84 +++++++++++++++++----- src/gfx/fwd.h | 2 + src/render/CMakeLists.txt | 2 +- src/render/projection.h | 16 +++++ src/render/render.cpp | 98 +++++++++++++------------- src/render/render.h | 15 ++-- src/she/surface.h | 4 -- 21 files changed, 354 insertions(+), 185 deletions(-) create mode 100644 src/app/cmd/set_cel_bounds.cpp create mode 100644 src/app/cmd/set_cel_bounds.h delete mode 100644 src/gfx/clip.cpp diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index d5653abd4..1ca0ea29f 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -134,6 +134,7 @@ add_library(app-lib cmd/remove_palette.cpp cmd/replace_image.cpp cmd/reselect_mask.cpp + cmd/set_cel_bounds.cpp cmd/set_cel_data.cpp cmd/set_cel_frame.cpp cmd/set_cel_opacity.cpp diff --git a/src/app/cmd/set_cel_bounds.cpp b/src/app/cmd/set_cel_bounds.cpp new file mode 100644 index 000000000..dac4c3e99 --- /dev/null +++ b/src/app/cmd/set_cel_bounds.cpp @@ -0,0 +1,51 @@ +// Aseprite +// Copyright (C) 2016 David Capello +// +// 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/cmd/set_cel_bounds.h" + +#include "app/document.h" +#include "doc/cel.h" +#include "doc/document_event.h" + +namespace app { +namespace cmd { + +using namespace doc; + +SetCelBoundsF::SetCelBoundsF(Cel* cel, const gfx::RectF& bounds) + : WithCel(cel) + , m_oldBounds(cel->boundsF()) + , m_newBounds(bounds) +{ +} + +void SetCelBoundsF::onExecute() +{ + cel()->setBoundsF(m_newBounds); + cel()->incrementVersion(); +} + +void SetCelBoundsF::onUndo() +{ + cel()->setBoundsF(m_oldBounds); + cel()->incrementVersion(); +} + +void SetCelBoundsF::onFireNotifications() +{ + Cel* cel = this->cel(); + DocumentEvent ev(cel->document()); + ev.sprite(cel->sprite()); + ev.cel(cel); + cel->document()->notify_observers(&DocumentObserver::onCelPositionChanged, ev); +} + +} // namespace cmd +} // namespace app diff --git a/src/app/cmd/set_cel_bounds.h b/src/app/cmd/set_cel_bounds.h new file mode 100644 index 000000000..be467ebfc --- /dev/null +++ b/src/app/cmd/set_cel_bounds.h @@ -0,0 +1,40 @@ +// Aseprite +// Copyright (C) 2016 David Capello +// +// This program is distributed under the terms of +// the End-User License Agreement for Aseprite. + +#ifndef APP_CMD_SET_CEL_BOUNDS_H_INCLUDED +#define APP_CMD_SET_CEL_BOUNDS_H_INCLUDED +#pragma once + +#include "app/cmd.h" +#include "app/cmd/with_cel.h" +#include "gfx/rect.h" + +namespace app { +namespace cmd { + using namespace doc; + + class SetCelBoundsF : public Cmd + , public WithCel { + public: + SetCelBoundsF(Cel* cel, const gfx::RectF& bounds); + + protected: + void onExecute() override; + void onUndo() override; + void onFireNotifications() override; + size_t onMemSize() const override { + return sizeof(*this); + } + + private: + gfx::RectF m_oldBounds; + gfx::RectF m_newBounds; + }; + +} // namespace cmd +} // namespace app + +#endif diff --git a/src/app/extra_cel.cpp b/src/app/extra_cel.cpp index 28e895855..9892e91b7 100644 --- a/src/app/extra_cel.cpp +++ b/src/app/extra_cel.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -44,7 +44,7 @@ void ExtraCel::create(doc::Sprite* sprite, m_cel.reset(new doc::Cel(doc::frame_t(0), doc::ImageRef(nullptr))); } - m_cel->setPosition(bounds.origin()); + m_cel->setBounds(bounds); m_cel->setOpacity(opacity); m_cel->setFrame(frame); } diff --git a/src/app/ui/editor/editor.cpp b/src/app/ui/editor/editor.cpp index aadc40da5..8025e434e 100644 --- a/src/app/ui/editor/editor.cpp +++ b/src/app/ui/editor/editor.cpp @@ -1028,6 +1028,17 @@ gfx::Point Editor::screenToEditor(const gfx::Point& pt) m_proj.removeY(pt.y - vp.y + scroll.y - m_padding.y)); } +gfx::PointF Editor::screenToEditorF(const gfx::Point& pt) +{ + View* view = View::getView(this); + Rect vp = view->viewportBounds(); + Point scroll = view->viewScroll(); + + return gfx::PointF( + m_proj.removeX(pt.x - vp.x + scroll.x - m_padding.x), + m_proj.removeY(pt.y - vp.y + scroll.y - m_padding.y)); +} + Point Editor::editorToScreen(const gfx::Point& pt) { View* view = View::getView(this); diff --git a/src/app/ui/editor/editor.h b/src/app/ui/editor/editor.h index 2fc9068cc..49706c9c1 100644 --- a/src/app/ui/editor/editor.h +++ b/src/app/ui/editor/editor.h @@ -150,6 +150,7 @@ namespace app { void flashCurrentLayer(); gfx::Point screenToEditor(const gfx::Point& pt); + gfx::PointF screenToEditorF(const gfx::Point& pt); gfx::Point editorToScreen(const gfx::Point& pt); gfx::Rect screenToEditor(const gfx::Rect& rc); gfx::Rect editorToScreen(const gfx::Rect& rc); diff --git a/src/app/ui/editor/moving_cel_state.cpp b/src/app/ui/editor/moving_cel_state.cpp index c11bfb61d..234a97c53 100644 --- a/src/app/ui/editor/moving_cel_state.cpp +++ b/src/app/ui/editor/moving_cel_state.cpp @@ -11,16 +11,17 @@ #include "app/ui/editor/moving_cel_state.h" #include "app/app.h" +#include "app/cmd/set_cel_bounds.h" #include "app/context_access.h" #include "app/document_api.h" #include "app/document_range.h" +#include "app/transaction.h" #include "app/ui/editor/editor.h" #include "app/ui/editor/editor_customization_delegate.h" #include "app/ui/main_window.h" #include "app/ui/status_bar.h" #include "app/ui/timeline.h" #include "app/ui_context.h" -#include "app/transaction.h" #include "app/util/range_utils.h" #include "doc/cel.h" #include "doc/layer.h" @@ -35,6 +36,7 @@ using namespace ui; MovingCelState::MovingCelState(Editor* editor, MouseMessage* msg) : m_reader(UIContext::instance(), 500) , m_canceled(false) + , m_hasReference(false) { ContextWriter writer(m_reader); Document* document = editor->document(); @@ -55,12 +57,18 @@ MovingCelState::MovingCelState(Editor* editor, MouseMessage* msg) if (layer && layer->isMovable() && !layer->isBackground()) { m_celList.push_back(cel); - m_celStarts.push_back(cel->position()); + + if (cel->layer()->isReference()) { + m_celStarts.push_back(cel->boundsF()); + m_hasReference = true; + } + else + m_celStarts.push_back(cel->bounds()); } } - m_cursorStart = editor->screenToEditor(msg->position()); - m_celOffset = gfx::Point(0, 0); + m_cursorStart = editor->screenToEditorF(msg->position()); + m_celOffset = gfx::PointF(0, 0); editor->captureMouse(); // Hide the mask (temporarily, until mouse-up event) @@ -71,23 +79,23 @@ MovingCelState::MovingCelState(Editor* editor, MouseMessage* msg) } } -MovingCelState::~MovingCelState() -{ -} - bool MovingCelState::onMouseUp(Editor* editor, MouseMessage* msg) { Document* document = editor->document(); // Here we put back the cel into its original coordinate (so we can // add an undoer before). - if (m_celOffset != gfx::Point(0, 0)) { + if ((m_hasReference && m_celOffset != gfx::PointF(0, 0)) || + (!m_hasReference && gfx::Point(m_celOffset) != gfx::Point(0, 0))) { // Put the cels in the original position. for (size_t i=0; isetPosition(celStart); + if (cel->layer()->isReference()) + cel->setBoundsF(celStart); + else + cel->setBounds(gfx::Rect(celStart)); } // If the user didn't cancel the operation... @@ -98,9 +106,18 @@ bool MovingCelState::onMouseUp(Editor* editor, MouseMessage* msg) // And now we move the cel (or all selected range) to the new position. for (Cel* cel : m_celList) { - api.setCelPosition(writer.sprite(), cel, - cel->x() + m_celOffset.x, - cel->y() + m_celOffset.y); + // Change reference layer with subpixel precision + if (cel->layer()->isReference()) { + gfx::RectF celBounds = cel->boundsF(); + celBounds.x += m_celOffset.x; + celBounds.y += m_celOffset.y; + transaction.execute(new cmd::SetCelBoundsF(cel, celBounds)); + } + else { + api.setCelPosition(writer.sprite(), cel, + cel->x() + m_celOffset.x, + cel->y() + m_celOffset.y); + } } // Move selection if it was visible @@ -131,7 +148,7 @@ bool MovingCelState::onMouseUp(Editor* editor, MouseMessage* msg) bool MovingCelState::onMouseMove(Editor* editor, MouseMessage* msg) { - gfx::Point newCursorPos = editor->screenToEditor(msg->position()); + gfx::PointF newCursorPos = editor->screenToEditorF(msg->position()); m_celOffset = newCursorPos - m_cursorStart; @@ -147,9 +164,14 @@ bool MovingCelState::onMouseMove(Editor* editor, MouseMessage* msg) for (size_t i=0; isetPosition(celStart + m_celOffset); + if (cel->layer()->isReference()) + cel->setBoundsF(celBounds); + else + cel->setBounds(gfx::Rect(celBounds)); } // Redraw the new cel position. @@ -161,13 +183,24 @@ bool MovingCelState::onMouseMove(Editor* editor, MouseMessage* msg) bool MovingCelState::onUpdateStatusBar(Editor* editor) { - StatusBar::instance()->setStatusText - (0, - ":pos: %3d %3d :offset: %3d %3d", - (int)m_cursorStart.x, - (int)m_cursorStart.y, - (int)m_celOffset.x, - (int)m_celOffset.y); + if (m_hasReference) { + StatusBar::instance()->setStatusText + (0, + ":pos: %.2f %.2f :offset: %.2f %.2f", + m_cursorStart.x, + m_cursorStart.y, + m_celOffset.x, + m_celOffset.y); + } + else { + StatusBar::instance()->setStatusText + (0, + ":pos: %3d %3d :offset: %3d %3d", + int(m_cursorStart.x), + int(m_cursorStart.y), + int(m_celOffset.x), + int(m_celOffset.y)); + } return true; } diff --git a/src/app/ui/editor/moving_cel_state.h b/src/app/ui/editor/moving_cel_state.h index cbb54be68..d8df83b2a 100644 --- a/src/app/ui/editor/moving_cel_state.h +++ b/src/app/ui/editor/moving_cel_state.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -25,7 +25,6 @@ namespace app { class MovingCelState : public StandbyState { public: MovingCelState(Editor* editor, ui::MouseMessage* msg); - virtual ~MovingCelState(); virtual bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override; virtual bool onMouseMove(Editor* editor, ui::MouseMessage* msg) override; @@ -36,11 +35,12 @@ namespace app { private: ContextReader m_reader; CelList m_celList; - std::vector m_celStarts; - gfx::Point m_celOffset; - gfx::Point m_cursorStart; + std::vector m_celStarts; + gfx::PointF m_cursorStart; + gfx::PointF m_celOffset; bool m_canceled; bool m_maskVisible; + bool m_hasReference; }; } // namespace app diff --git a/src/doc/cel.cpp b/src/doc/cel.cpp index ed44dbf34..bffd5d723 100644 --- a/src/doc/cel.cpp +++ b/src/doc/cel.cpp @@ -1,5 +1,5 @@ // Aseprite Document Library -// Copyright (c) 2001-2015 David Capello +// Copyright (c) 2001-2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -77,6 +77,11 @@ void Cel::setBounds(const gfx::Rect& bounds) m_data->setBounds(bounds); } +void Cel::setBoundsF(const gfx::RectF& bounds) +{ + m_data->setBoundsF(bounds); +} + void Cel::setOpacity(int opacity) { m_data->setOpacity(opacity); diff --git a/src/doc/cel.h b/src/doc/cel.h index aacd1c688..4688fdcf4 100644 --- a/src/doc/cel.h +++ b/src/doc/cel.h @@ -35,6 +35,7 @@ namespace doc { int y() const { return m_data->position().y; } gfx::Point position() const { return m_data->position(); } const gfx::Rect& bounds() const { return m_data->bounds(); } + const gfx::RectF& boundsF() const { return m_data->boundsF(); } int opacity() const { return m_data->opacity(); } LayerImage* layer() const { return m_layer; } @@ -55,6 +56,7 @@ namespace doc { void setPosition(int x, int y); void setPosition(const gfx::Point& pos); void setBounds(const gfx::Rect& bounds); + void setBoundsF(const gfx::RectF& bounds); void setOpacity(int opacity); virtual int getMemSize() const override { diff --git a/src/doc/cel_data.cpp b/src/doc/cel_data.cpp index 0bddecbbb..b83b83883 100644 --- a/src/doc/cel_data.cpp +++ b/src/doc/cel_data.cpp @@ -1,5 +1,5 @@ // Aseprite Document Library -// Copyright (c) 2001-2015 David Capello +// Copyright (c) 2001-2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -20,21 +20,29 @@ namespace doc { CelData::CelData(const ImageRef& image) : WithUserData(ObjectType::CelData) , m_image(image) + , m_opacity(255) , m_bounds(0, 0, image ? image->width(): 0, image ? image->height(): 0) - , m_opacity(255) + , m_boundsF(nullptr) { } CelData::CelData(const CelData& celData) : WithUserData(ObjectType::CelData) , m_image(celData.m_image) - , m_bounds(celData.m_bounds) , m_opacity(celData.m_opacity) + , m_bounds(celData.m_bounds) + , m_boundsF(celData.m_boundsF ? new gfx::RectF(*celData.m_boundsF): + nullptr) { } +CelData::~CelData() +{ + delete m_boundsF; +} + void CelData::setImage(const ImageRef& image) { ASSERT(image.get()); diff --git a/src/doc/cel_data.h b/src/doc/cel_data.h index 3fc2fbf6a..362b867d5 100644 --- a/src/doc/cel_data.h +++ b/src/doc/cel_data.h @@ -1,5 +1,5 @@ // Aseprite Document Library -// Copyright (c) 2001-2015 David Capello +// Copyright (c) 2001-2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -20,6 +20,7 @@ namespace doc { public: CelData(const ImageRef& image); CelData(const CelData& celData); + ~CelData(); gfx::Point position() const { return m_bounds.origin(); } const gfx::Rect& bounds() const { return m_bounds; } @@ -29,9 +30,29 @@ namespace doc { void setImage(const ImageRef& image); void setPosition(const gfx::Point& pos) { m_bounds.setOrigin(pos); } - void setBounds(const gfx::Rect& bounds) { m_bounds = bounds; } void setOpacity(int opacity) { m_opacity = opacity; } + void setBounds(const gfx::Rect& bounds) { + m_bounds = bounds; + if (m_boundsF) + *m_boundsF = gfx::RectF(bounds); + } + + void setBoundsF(const gfx::RectF& boundsF) { + if (m_boundsF) + *m_boundsF = boundsF; + else + m_boundsF = new gfx::RectF(boundsF); + + m_bounds = gfx::Rect(boundsF); + } + + const gfx::RectF& boundsF() const { + if (!m_boundsF) + m_boundsF = new gfx::RectF(m_bounds); + return *m_boundsF; + } + virtual int getMemSize() const override { ASSERT(m_image); return sizeof(CelData) + m_image->getMemSize(); @@ -39,8 +60,12 @@ namespace doc { private: ImageRef m_image; - gfx::Rect m_bounds; int m_opacity; + gfx::Rect m_bounds; + + // Special bounds for reference layers that can have subpixel + // position. + mutable gfx::RectF* m_boundsF; }; typedef base::SharedPtr CelDataRef; diff --git a/src/gfx/CMakeLists.txt b/src/gfx/CMakeLists.txt index 7a92f18df..f3111b736 100644 --- a/src/gfx/CMakeLists.txt +++ b/src/gfx/CMakeLists.txt @@ -2,7 +2,6 @@ # Copyright (C) 2001-2016 David Capello add_library(gfx-lib - clip.cpp hsv.cpp packing_rects.cpp region.cpp diff --git a/src/gfx/clip.cpp b/src/gfx/clip.cpp deleted file mode 100644 index 3bf84533b..000000000 --- a/src/gfx/clip.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// Aseprite Gfx Library -// Copyright (c) 2001-2014 David Capello -// -// This file is released under the terms of the MIT license. -// Read LICENSE.txt for more information. - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gfx/clip.h" - -namespace gfx { - -bool Clip::clip( - int avail_dst_w, - int avail_dst_h, - int avail_src_w, - int avail_src_h) -{ - // Clip srcBounds - - if (src.x < 0) { - size.w += src.x; - dst.x -= src.x; - src.x = 0; - } - - if (src.y < 0) { - size.h += src.y; - dst.y -= src.y; - src.y = 0; - } - - if (src.x + size.w > avail_src_w) - size.w -= src.x + size.w - avail_src_w; - - if (src.y + size.h > avail_src_h) - size.h -= src.y + size.h - avail_src_h; - - // Clip dstBounds - - if (dst.x < 0) { - size.w += dst.x; - src.x -= dst.x; - dst.x = 0; - } - - if (dst.y < 0) { - size.h += dst.y; - src.y -= dst.y; - dst.y = 0; - } - - if (dst.x + size.w > avail_dst_w) - size.w -= dst.x + size.w - avail_dst_w; - - if (dst.y + size.h > avail_dst_h) - size.h -= dst.y + size.h - avail_dst_h; - - return (size.w > 0 && size.h > 0); -} - -} // namespace gfx diff --git a/src/gfx/clip.h b/src/gfx/clip.h index 2bab34163..a8ad02f8a 100644 --- a/src/gfx/clip.h +++ b/src/gfx/clip.h @@ -1,5 +1,5 @@ // Aseprite Gfx Library -// Copyright (c) 2001-2014 David Capello +// Copyright (c) 2001-2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -14,58 +14,59 @@ namespace gfx { - class Clip { + template + class ClipT { public: - Point dst; - Point src; - Size size; + PointT dst; + PointT src; + SizeT size; - Clip() + ClipT() : dst(0, 0) , src(0, 0) , size(0, 0) { } - Clip(int w, int h) + ClipT(T w, T h) : dst(0, 0) , src(0, 0) , size(w, h) { } - Clip(int dst_x, int dst_y, int src_x, int src_y, int w, int h) + ClipT(T dst_x, T dst_y, T src_x, T src_y, T w, T h) : dst(dst_x, dst_y) , src(src_x, src_y) , size(w, h) { } - Clip(int dst_x, int dst_y, const Rect& srcBounds) + ClipT(T dst_x, T dst_y, const RectT& srcBounds) : dst(dst_x, dst_y) , src(srcBounds.x, srcBounds.y) , size(srcBounds.w, srcBounds.h) { } - Clip(const Point& dst, const Point& src, const Size& size) + ClipT(const PointT& dst, const PointT& src, const SizeT& size) : dst(dst) , src(src) , size(size) { } - Clip(const Point& dst, const Rect& srcBounds) + ClipT(const PointT& dst, const RectT& srcBounds) : dst(dst) , src(srcBounds.x, srcBounds.y) , size(srcBounds.w, srcBounds.h) { } - Clip(const Rect& bounds) + ClipT(const RectT& bounds) : dst(bounds.x, bounds.y) , src(bounds.x, bounds.y) , size(bounds.w, bounds.h) { } - Rect dstBounds() const { return Rect(dst, size); } - Rect srcBounds() const { return Rect(src, size); } + RectT dstBounds() const { return RectT(dst, size); } + RectT srcBounds() const { return RectT(src, size); } - bool operator==(const Clip& other) const { + bool operator==(const ClipT& other) const { return (dst == other.dst && src == other.src && size == other.size); @@ -73,13 +74,58 @@ namespace gfx { bool clip( // Available area - int avail_dst_w, - int avail_dst_h, - int avail_src_w, - int avail_src_h); + T avail_dst_w, + T avail_dst_h, + T avail_src_w, + T avail_src_h) { + // Clip srcBounds + + if (src.x < T(0)) { + size.w += src.x; + dst.x -= src.x; + src.x = T(0); + } + + if (src.y < T(0)) { + size.h += src.y; + dst.y -= src.y; + src.y = T(0); + } + + if (src.x + size.w > avail_src_w) + size.w -= src.x + size.w - avail_src_w; + + if (src.y + size.h > avail_src_h) + size.h -= src.y + size.h - avail_src_h; + + // Clip dstBounds + + if (dst.x < T(0)) { + size.w += dst.x; + src.x -= dst.x; + dst.x = T(0); + } + + if (dst.y < T(0)) { + size.h += dst.y; + src.y -= dst.y; + dst.y = T(0); + } + + if (dst.x + size.w > avail_dst_w) + size.w -= dst.x + size.w - avail_dst_w; + + if (dst.y + size.h > avail_dst_h) + size.h -= dst.y + size.h - avail_dst_h; + + return (size.w > T(0) && size.h > T(0)); + } }; + typedef ClipT Clip; + typedef ClipT ClipF; + } // namespace gfx #endif diff --git a/src/gfx/fwd.h b/src/gfx/fwd.h index 44ae4d9d3..2b1ba5a7f 100644 --- a/src/gfx/fwd.h +++ b/src/gfx/fwd.h @@ -11,11 +11,13 @@ namespace gfx { template class BorderT; +template class ClipT; template class PointT; template class RectT; template class SizeT; typedef BorderT Border; +typedef ClipT Clip; typedef PointT Point; typedef RectT Rect; typedef SizeT Size; diff --git a/src/render/CMakeLists.txt b/src/render/CMakeLists.txt index 9a97e5d4d..edd940ab1 100644 --- a/src/render/CMakeLists.txt +++ b/src/render/CMakeLists.txt @@ -1,5 +1,5 @@ # Aseprite Render Library -# Copyright (C) 2001-2015 David Capello +# Copyright (C) 2001-2016 David Capello add_library(render-lib get_sprite_pixel.cpp diff --git a/src/render/projection.h b/src/render/projection.h index a6f460e03..d8e479269 100644 --- a/src/render/projection.h +++ b/src/render/projection.h @@ -55,6 +55,14 @@ namespace render { applyY(r.y+r.h) - v); } + gfx::RectF apply(const gfx::RectF& r) const { + double u = applyX(r.x); + double v = applyY(r.y); + return gfx::RectF(u, v, + applyX(r.x+r.w) - u, + applyY(r.y+r.h) - v); + } + gfx::Rect remove(const gfx::Rect& r) const { int u = removeX(r.x); int v = removeY(r.y); @@ -63,6 +71,14 @@ namespace render { removeY(r.y+r.h) - v); } + gfx::RectF remove(const gfx::RectF& r) const { + double u = removeX(r.x); + double v = removeY(r.y); + return gfx::RectF(u, v, + removeX(r.x+r.w) - u, + removeY(r.y+r.h) - v); + } + private: doc::PixelRatio m_pixelRatio; Zoom m_zoom; diff --git a/src/render/render.cpp b/src/render/render.cpp index bab761567..de477a5b2 100644 --- a/src/render/render.cpp +++ b/src/render/render.cpp @@ -446,33 +446,33 @@ void composite_image_scale_down_non_square_pixel_ratio( template void composite_image_general( Image* dst, const Image* src, const Palette* pal, - const gfx::Clip& _area, + const gfx::ClipF& _area, const int opacity, const BlendMode blendMode, - const Projection& proj) + const double sx, + const double sy) { ASSERT(dst); ASSERT(src); ASSERT(DstTraits::pixel_format == dst->pixelFormat()); ASSERT(SrcTraits::pixel_format == src->pixelFormat()); - gfx::Clip area = _area; + gfx::ClipF area = _area; if (!area.clip(dst->width(), dst->height(), - proj.applyX(src->width()), - proj.applyY(src->height()))) + sx*src->width(), sy*src->height())) return; BlenderHelper blender(src, pal, blendMode); - gfx::Rect dstBounds = area.dstBounds(); - gfx::Rect srcBounds = area.srcBounds(); + gfx::RectF dstBounds = area.dstBounds(); + gfx::RectF srcBounds = area.srcBounds(); - for (int y=0; y= 0 && srcX < src->width() && srcY >= 0 && srcY < src->height() && @@ -775,8 +775,9 @@ void Render::renderSprite( dstImage, m_previewImage, m_sprite->palette(frame), - m_previewPos.x, - m_previewPos.y, + gfx::Rect(m_previewPos.x, m_previewPos.y, + m_previewImage->width(), + m_previewImage->height()), area, compositeImage, 255, @@ -899,19 +900,21 @@ void Render::renderImage( const int opacity, const BlendMode blendMode) { - CompositeImageFunc compositeImage = get_image_composition( - dst_image->pixelFormat(), - src_image->pixelFormat(), m_proj); + CompositeImageFunc compositeImage = + get_image_composition( + dst_image->pixelFormat(), + src_image->pixelFormat(), m_proj); if (!compositeImage) return; compositeImage( dst_image, src_image, pal, - gfx::Clip(x, y, 0, 0, - m_proj.applyX(src_image->width()), - m_proj.applyY(src_image->height())), + gfx::ClipF(x, y, 0, 0, + m_proj.applyX(src_image->width()), + m_proj.applyY(src_image->height())), opacity, blendMode, - m_proj); + m_proj.scaleX(), + m_proj.scaleY()); } void Render::renderLayer( @@ -960,21 +963,27 @@ void Render::renderLayer( if (cel) { Palette* pal = m_sprite->palette(frame); const Image* celImage; - gfx::Point celPos; + gfx::RectF celBounds; // Is the 'm_previewImage' set to be used with this layer? if ((m_previewImage) && (m_selectedLayer == layer) && (m_selectedFrame == frame)) { celImage = m_previewImage; - celPos = m_previewPos; + celBounds = gfx::RectF(m_previewPos.x, + m_previewPos.y, + m_previewImage->width(), + m_previewImage->height()); ASSERT(celImage->pixelFormat() == cel->image()->pixelFormat()); } // If not, we use the original cel-image from the images' stock else { celImage = cel->image(); - celPos = cel->position(); + if (cel->layer()->isReference()) + celBounds = cel->boundsF(); + else + celBounds = cel->bounds(); } if (celImage) { @@ -1005,7 +1014,7 @@ void Render::renderLayer( for (auto rc : originalAreas) { renderCel( - image, celImage, pal, celPos, + image, celImage, pal, celBounds, gfx::Clip(area.dst.x+rc.x-area.src.x, area.dst.y+rc.y-area.src.y, rc), compositeImage, opacity, layerBlendMode); @@ -1015,7 +1024,7 @@ void Render::renderLayer( else { renderCel( image, celImage, pal, - celPos, area, compositeImage, + celBounds, area, compositeImage, opacity, layerBlendMode); } } @@ -1044,7 +1053,7 @@ void Render::renderLayer( renderCel( image, m_extraImage, m_sprite->palette(frame), - m_extraCel->position(), + m_extraCel->bounds(), gfx::Clip(area.dst.x+extraArea.x-area.src.x, area.dst.y+extraArea.y-area.src.y, extraArea), @@ -1059,7 +1068,7 @@ void Render::renderCel( Image* dst_image, const Image* cel_image, const Palette* pal, - const gfx::Point& celPos, + const gfx::RectF& celBounds, const gfx::Clip& area, const CompositeImageFunc compositeImage, const int opacity, @@ -1068,8 +1077,7 @@ void Render::renderCel( renderImage(dst_image, cel_image, pal, - celPos.x, - celPos.y, + celBounds, area, compositeImage, opacity, @@ -1080,38 +1088,30 @@ void Render::renderImage( Image* dst_image, const Image* cel_image, const Palette* pal, - const int x, - const int y, + const gfx::RectF& celBounds, const gfx::Clip& area, const CompositeImageFunc compositeImage, const int opacity, const BlendMode blendMode) { - int cel_x = m_proj.applyX(x); - int cel_y = m_proj.applyY(y); - - gfx::Rect srcBounds = - area.srcBounds().createIntersection( - gfx::Rect( - cel_x, - cel_y, - m_proj.applyX(cel_image->width()), - m_proj.applyY(cel_image->height()))); + gfx::RectF scaledBounds = m_proj.apply(celBounds); + gfx::RectF srcBounds = gfx::RectF(area.srcBounds()).createIntersection(scaledBounds); if (srcBounds.isEmpty()) return; compositeImage( dst_image, cel_image, pal, - gfx::Clip( - area.dst.x + srcBounds.x - area.src.x, - area.dst.y + srcBounds.y - area.src.y, - srcBounds.x - cel_x, - srcBounds.y - cel_y, + gfx::ClipF( + double(area.dst.x) + srcBounds.x - double(area.src.x), + double(area.dst.y) + srcBounds.y - double(area.src.y), + srcBounds.x - scaledBounds.x, + srcBounds.y - scaledBounds.y, srcBounds.w, srcBounds.h), opacity, blendMode, - m_proj); + m_proj.scaleX() * double(cel_image->width()) / celBounds.w, + m_proj.scaleY() * double(cel_image->height()) / celBounds.h); } void composite_image(Image* dst, diff --git a/src/render/render.h b/src/render/render.h index c1f945ba5..23b8893b9 100644 --- a/src/render/render.h +++ b/src/render/render.h @@ -13,16 +13,13 @@ #include "doc/color.h" #include "doc/frame.h" #include "doc/pixel_format.h" +#include "gfx/clip.h" #include "gfx/point.h" #include "gfx/size.h" #include "render/extra_type.h" #include "render/onionskin_position.h" #include "render/projection.h" -namespace gfx { - class Clip; -} - namespace doc { class Cel; class FrameTag; @@ -93,10 +90,11 @@ namespace render { Image* dst, const Image* src, const Palette* pal, - const gfx::Clip& area, + const gfx::ClipF& area, const int opacity, const BlendMode blendMode, - const Projection& proj); + const double sx, + const double sy); class Render { public: @@ -194,7 +192,7 @@ namespace render { Image* dst_image, const Image* cel_image, const Palette* pal, - const gfx::Point& celPos, + const gfx::RectF& celBounds, const gfx::Clip& area, const CompositeImageFunc compositeImage, const int opacity, @@ -204,8 +202,7 @@ namespace render { Image* dst_image, const Image* cel_image, const Palette* pal, - const int x, - const int y, + const gfx::RectF& celBounds, const gfx::Clip& area, const CompositeImageFunc compositeImage, const int opacity, diff --git a/src/she/surface.h b/src/she/surface.h index 173903165..c11057a0a 100644 --- a/src/she/surface.h +++ b/src/she/surface.h @@ -14,10 +14,6 @@ #include -namespace gfx { - class Clip; -} - namespace she { class Font;