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).
This commit is contained in:
David Capello 2016-10-10 23:42:47 -03:00
parent 4a7d601d5d
commit 080e7e3f68
21 changed files with 354 additions and 185 deletions

View File

@ -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

View File

@ -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<DocumentEvent&>(&DocumentObserver::onCelPositionChanged, ev);
}
} // namespace cmd
} // namespace app

View File

@ -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

View File

@ -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);
}

View File

@ -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<double>(pt.x - vp.x + scroll.x - m_padding.x),
m_proj.removeY<double>(pt.y - vp.y + scroll.y - m_padding.y));
}
Point Editor::editorToScreen(const gfx::Point& pt)
{
View* view = View::getView(this);

View File

@ -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);

View File

@ -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; i<m_celList.size(); ++i) {
Cel* cel = m_celList[i];
const gfx::Point& celStart = m_celStarts[i];
const gfx::RectF& celStart = m_celStarts[i];
cel->setPosition(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; i<m_celList.size(); ++i) {
Cel* cel = m_celList[i];
const gfx::Point& celStart = m_celStarts[i];
gfx::RectF celBounds = m_celStarts[i];
celBounds.x += m_celOffset.x;
celBounds.y += m_celOffset.y;
cel->setPosition(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;
}

View File

@ -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<gfx::Point> m_celStarts;
gfx::Point m_celOffset;
gfx::Point m_cursorStart;
std::vector<gfx::RectF> m_celStarts;
gfx::PointF m_cursorStart;
gfx::PointF m_celOffset;
bool m_canceled;
bool m_maskVisible;
bool m_hasReference;
};
} // namespace app

View File

@ -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);

View File

@ -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 {

View File

@ -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());

View File

@ -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<CelData> CelDataRef;

View File

@ -2,7 +2,6 @@
# Copyright (C) 2001-2016 David Capello
add_library(gfx-lib
clip.cpp
hsv.cpp
packing_rects.cpp
region.cpp

View File

@ -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

View File

@ -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<typename T>
class ClipT {
public:
Point dst;
Point src;
Size size;
PointT<T> dst;
PointT<T> src;
SizeT<T> 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<T>& 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<T>& dst, const PointT<T>& src, const SizeT<T>& size)
: dst(dst)
, src(src)
, size(size) {
}
Clip(const Point& dst, const Rect& srcBounds)
ClipT(const PointT<T>& dst, const RectT<T>& srcBounds)
: dst(dst)
, src(srcBounds.x, srcBounds.y)
, size(srcBounds.w, srcBounds.h) {
}
Clip(const Rect& bounds)
ClipT(const RectT<T>& 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<T> dstBounds() const { return RectT<T>(dst, size); }
RectT<T> srcBounds() const { return RectT<T>(src, size); }
bool operator==(const Clip& other) const {
bool operator==(const ClipT<T>& 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<int> Clip;
typedef ClipT<double> ClipF;
} // namespace gfx
#endif

View File

@ -11,11 +11,13 @@
namespace gfx {
template<typename T> class BorderT;
template<typename T> class ClipT;
template<typename T> class PointT;
template<typename T> class RectT;
template<typename T> class SizeT;
typedef BorderT<int> Border;
typedef ClipT<int> Clip;
typedef PointT<int> Point;
typedef RectT<int> Rect;
typedef SizeT<int> Size;

View File

@ -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

View File

@ -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;

View File

@ -446,33 +446,33 @@ void composite_image_scale_down_non_square_pixel_ratio(
template<class DstTraits, class SrcTraits>
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<DstTraits, SrcTraits> 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<dstBounds.h; ++y) {
for (int x=0; x<dstBounds.w; ++x) {
int dstX = dstBounds.x+x;
int dstY = dstBounds.y+y;
int srcX = proj.removeX(srcBounds.x+x);
int srcY = proj.removeY(srcBounds.y+y);
int dstY = dstBounds.y;
for (int y=0; y<dstBounds.h; ++y, ++dstY) {
int dstX = dstBounds.x;
for (int x=0; x<dstBounds.w; ++x, ++dstX) {
int srcX = (srcBounds.x+x)/sx;
int srcY = (srcBounds.y+y)/sy;
if (srcX >= 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,

View File

@ -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,

View File

@ -14,10 +14,6 @@
#include <string>
namespace gfx {
class Clip;
}
namespace she {
class Font;