|
|
9e9ccd |
/* === S Y N F I G ========================================================= */
|
|
|
9e9ccd |
/*! \file layerpaint.cpp
|
|
|
9e9ccd |
** \brief Template File
|
|
|
9e9ccd |
**
|
|
|
9e9ccd |
** $Id$
|
|
|
9e9ccd |
**
|
|
|
9e9ccd |
** \legal
|
|
|
9e9ccd |
** ......... ... 2014 Ivan Mahonin
|
|
|
9e9ccd |
**
|
|
|
9e9ccd |
** This package is free software; you can redistribute it and/or
|
|
|
9e9ccd |
** modify it under the terms of the GNU General Public License as
|
|
|
9e9ccd |
** published by the Free Software Foundation; either version 2 of
|
|
|
9e9ccd |
** the License, or (at your option) any later version.
|
|
|
9e9ccd |
**
|
|
|
9e9ccd |
** This package is distributed in the hope that it will be useful,
|
|
|
9e9ccd |
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
9e9ccd |
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
9e9ccd |
** General Public License for more details.
|
|
|
9e9ccd |
** \endlegal
|
|
|
9e9ccd |
*/
|
|
|
9e9ccd |
/* ========================================================================= */
|
|
|
9e9ccd |
|
|
|
9e9ccd |
/* === H E A D E R S ======================================================= */
|
|
|
9e9ccd |
|
|
|
9e9ccd |
#ifdef USING_PCH
|
|
|
9e9ccd |
# include "pch.h"
|
|
|
9e9ccd |
#else
|
|
|
9e9ccd |
#ifdef HAVE_CONFIG_H
|
|
|
9e9ccd |
# include <config.h></config.h>
|
|
|
9e9ccd |
#endif
|
|
|
9e9ccd |
|
|
bw |
94d8a6 |
#include <synfig general.h=""></synfig>
|
|
bw |
94d8a6 |
|
|
|
9e9ccd |
#include "layerpaint.h"
|
|
|
9e9ccd |
#include <synfigapp canvasinterface.h=""></synfigapp>
|
|
|
abdbf2 |
#include <synfigapp localization.h=""></synfigapp>
|
|
|
b8e8c2 |
#include <synfigapp instance.h=""></synfigapp>
|
|
|
a6c0f7 |
|
|
Diego Barrios Romero |
dcc14d |
#include <synfig layer_pastecanvas.h="" layers=""></synfig>
|
|
Diego Barrios Romero |
07d34c |
#include <synfig valuenode_composite.h="" valuenodes=""></synfig>
|
|
|
a6c0f7 |
#include <synfig rendering="" software="" surfacesw.h=""></synfig>
|
|
|
9e9ccd |
|
|
|
9e9ccd |
#endif
|
|
|
9e9ccd |
|
|
|
9e9ccd |
using namespace std;
|
|
|
9e9ccd |
using namespace etl;
|
|
|
9e9ccd |
using namespace synfig;
|
|
|
9e9ccd |
using namespace synfigapp;
|
|
|
9e9ccd |
using namespace Action;
|
|
|
9e9ccd |
|
|
|
9e9ccd |
/* === M A C R O S ========================================================= */
|
|
|
9e9ccd |
|
|
|
9e9ccd |
ACTION_INIT(Action::LayerPaint);
|
|
|
9e9ccd |
ACTION_SET_NAME(Action::LayerPaint,"LayerPaint");
|
|
|
9e9ccd |
ACTION_SET_LOCAL_NAME(Action::LayerPaint,N_("Paint"));
|
|
|
9e9ccd |
ACTION_SET_TASK(Action::LayerPaint,"paint");
|
|
|
9e9ccd |
ACTION_SET_CATEGORY(Action::LayerPaint,Action::CATEGORY_NONE);
|
|
|
9e9ccd |
ACTION_SET_PRIORITY(Action::LayerPaint,0);
|
|
|
9e9ccd |
ACTION_SET_VERSION(Action::LayerPaint,"0.0");
|
|
|
9e9ccd |
ACTION_SET_CVS_ID(Action::LayerPaint,"$Id$");
|
|
|
9e9ccd |
|
|
|
9e9ccd |
/* === G L O B A L S ======================================================= */
|
|
|
9e9ccd |
|
|
|
f5e87b |
Action::LayerPaint::PaintStroke* Action::LayerPaint::PaintStroke::first = NULL;
|
|
|
f5e87b |
Action::LayerPaint::PaintStroke* Action::LayerPaint::PaintStroke::last = NULL;
|
|
|
f5e87b |
|
|
|
9e9ccd |
/* === P R O C E D U R E S ================================================= */
|
|
|
9e9ccd |
|
|
|
9e9ccd |
/* === M E T H O D S ======================================================= */
|
|
|
9e9ccd |
|
|
|
f5e87b |
Action::LayerPaint::PaintStroke::PaintStroke():
|
|
|
f5e87b |
prev(NULL),
|
|
|
f5e87b |
next(NULL),
|
|
|
f5e87b |
prevSameLayer(NULL),
|
|
|
f5e87b |
nextSameLayer(NULL),
|
|
|
f5e87b |
prepared(false),
|
|
|
9e9ccd |
applied(false)
|
|
|
9e9ccd |
{
|
|
|
9e9ccd |
}
|
|
|
9e9ccd |
|
|
|
f5e87b |
Action::LayerPaint::PaintStroke::~PaintStroke()
|
|
|
f5e87b |
{
|
|
|
f5e87b |
if (prepared)
|
|
|
f5e87b |
{
|
|
|
f5e87b |
if (nextSameLayer != NULL)
|
|
|
f5e87b |
{
|
|
|
f5e87b |
if (prevSameLayer == NULL)
|
|
|
f5e87b |
paint_self(nextSameLayer->surface);
|
|
|
f5e87b |
else
|
|
|
f5e87b |
nextSameLayer->points.insert(nextSameLayer->points.begin(), points.begin(), points.end());
|
|
|
f5e87b |
nextSameLayer->prevSameLayer = prevSameLayer;
|
|
|
f5e87b |
}
|
|
|
f5e87b |
if (prevSameLayer != NULL) prevSameLayer->nextSameLayer = nextSameLayer;
|
|
|
f5e87b |
if (prev == NULL) first = next; else prev->next = next;
|
|
|
f5e87b |
if (next == NULL) last = prev; else next->prev = prev;
|
|
|
f5e87b |
}
|
|
|
f5e87b |
}
|
|
|
f5e87b |
|
|
|
f5e87b |
void
|
|
|
f5e87b |
Action::LayerPaint::PaintStroke::paint_prev(synfig::Surface &surface)
|
|
|
f5e87b |
{
|
|
|
f5e87b |
if (prevSameLayer == NULL) {
|
|
|
f5e87b |
surface = this->surface;
|
|
|
f5e87b |
return;
|
|
|
f5e87b |
}
|
|
|
f5e87b |
prevSameLayer->paint_self(surface);
|
|
|
f5e87b |
}
|
|
|
f5e87b |
|
|
|
f5e87b |
void
|
|
|
f5e87b |
Action::LayerPaint::PaintStroke::paint_self(synfig::Surface &surface)
|
|
|
f5e87b |
{
|
|
|
f5e87b |
paint_prev(surface);
|
|
|
f5e87b |
brushlib::SurfaceWrapper wrapper(&surface);
|
|
|
901e9f |
if (!points.empty()) reset(points.front());
|
|
|
f5e87b |
for(std::vector<paintpoint>::const_iterator i = points.begin(); i != points.end(); i++)</paintpoint>
|
|
|
f5e87b |
{
|
|
|
f5e87b |
brush_.stroke_to(&wrapper, i->x, i->y, i->pressure, 0.f, 0.f, i->dtime);
|
|
|
f5e87b |
wrapper.offset_x = 0;
|
|
|
f5e87b |
wrapper.offset_y = 0;
|
|
|
f5e87b |
}
|
|
|
f5e87b |
}
|
|
|
f5e87b |
|
|
|
901e9f |
void Action::LayerPaint::PaintStroke::reset(const PaintPoint &point)
|
|
|
901e9f |
{
|
|
|
901e9f |
for (int i=0; i
|
|
|
901e9f |
brush_.set_state(i, 0);
|
|
|
901e9f |
brush_.set_state(STATE_X, point.x);
|
|
|
901e9f |
brush_.set_state(STATE_Y, point.y);
|
|
|
901e9f |
brush_.set_state(STATE_PRESSURE, point.pressure);
|
|
|
901e9f |
brush_.set_state(STATE_ACTUAL_X, brush_.get_state(STATE_X));
|
|
|
901e9f |
brush_.set_state(STATE_ACTUAL_Y, brush_.get_state(STATE_Y));
|
|
|
901e9f |
brush_.set_state(STATE_STROKE, 1.0); // start in a state as if the stroke was long finished
|
|
|
901e9f |
}
|
|
|
901e9f |
|
|
|
f5e87b |
void
|
|
|
f5e87b |
Action::LayerPaint::PaintStroke::add_point_and_apply(const PaintPoint &point)
|
|
|
f5e87b |
{
|
|
|
f5e87b |
assert(prepared);
|
|
|
f5e87b |
assert(applied || points.empty());
|
|
|
f5e87b |
assert(prevSameLayer == NULL || prevSameLayer->applied);
|
|
|
f5e87b |
assert(nextSameLayer == NULL);
|
|
|
f5e87b |
|
|
|
901e9f |
if (points.empty()) reset(point);
|
|
|
f5e87b |
points.push_back(point);
|
|
|
f5e87b |
applied = true;
|
|
|
f5e87b |
|
|
|
20e596 |
Surface *surface = new Surface();
|
|
|
20e596 |
{
|
|
|
20e596 |
rendering::SurfaceResource::LockRead<rendering::surfacesw> lock(layer->rendering_surface);</rendering::surfacesw>
|
|
|
20e596 |
if (lock) surface->copy( lock->get_surface() );
|
|
|
20e596 |
}
|
|
|
20e596 |
|
|
|
20e596 |
brushlib::SurfaceWrapper wrapper(surface);
|
|
|
f5e87b |
int w = wrapper.surface->get_w();
|
|
|
f5e87b |
int h = wrapper.surface->get_h();
|
|
|
f5e87b |
{
|
|
Rodolfo Ribeiro Gomes |
cfe072 |
std::lock_guard<std::mutex> lock(layer->mutex);</std::mutex>
|
|
|
f5e87b |
brush_.stroke_to(&wrapper, point.x, point.y, point.pressure, 0.f, 0.f, point.dtime);
|
|
|
a2d16b |
|
|
|
a2d16b |
// fix state in case of surface resized
|
|
|
a2d16b |
float x = brush_.get_state(STATE_X) + wrapper.offset_x;
|
|
|
a2d16b |
float y = brush_.get_state(STATE_Y) + wrapper.offset_y;
|
|
|
a2d16b |
brush_.set_state(STATE_X, x);
|
|
|
a2d16b |
brush_.set_state(STATE_Y, y);
|
|
|
a2d16b |
brush_.set_state(STATE_ACTUAL_X, x);
|
|
|
a2d16b |
brush_.set_state(STATE_ACTUAL_Y, y);
|
|
|
a2d16b |
|
|
|
20e596 |
layer->rendering_surface = new rendering::SurfaceResource(
|
|
|
20e596 |
new rendering::SurfaceSW(*surface, true) );
|
|
|
f5e87b |
}
|
|
|
f5e87b |
|
|
|
f5e87b |
if (wrapper.extra_left > 0 || wrapper.extra_top > 0) {
|
|
|
f5e87b |
new_tl -= Point(
|
|
|
f5e87b |
(Real)wrapper.extra_left/(Real)w*(new_br[0] - new_tl[0]),
|
|
|
f5e87b |
(Real)wrapper.extra_top/(Real)h*(new_br[1] - new_tl[1]) );
|
|
|
f5e87b |
layer->set_param("tl", ValueBase(new_tl));
|
|
|
f5e87b |
}
|
|
|
f5e87b |
if (wrapper.extra_right > 0 || wrapper.extra_bottom > 0) {
|
|
|
f5e87b |
new_br += Point(
|
|
|
f5e87b |
(Real)wrapper.extra_right/(Real)w*(new_br[0] - new_tl[0]),
|
|
|
f5e87b |
(Real)wrapper.extra_bottom/(Real)h*(new_br[1] - new_tl[1]) );
|
|
|
f5e87b |
layer->set_param("br", ValueBase(new_br));
|
|
|
f5e87b |
}
|
|
|
f5e87b |
layer->changed();
|
|
|
f5e87b |
}
|
|
|
f5e87b |
|
|
|
f5e87b |
void
|
|
|
f5e87b |
Action::LayerPaint::PaintStroke::prepare()
|
|
|
f5e87b |
{
|
|
|
f5e87b |
assert(layer);
|
|
|
f5e87b |
assert(!prepared);
|
|
|
f5e87b |
|
|
|
f5e87b |
prev = last; last = this;
|
|
|
f5e87b |
if (prev == NULL) first = this; else prev->next = this;
|
|
|
f5e87b |
|
|
|
f5e87b |
for(PaintStroke *p = prev; p != NULL; p = p->prev)
|
|
|
f5e87b |
if (p->layer == layer)
|
|
|
f5e87b |
{
|
|
|
f5e87b |
assert(p->nextSameLayer == NULL);
|
|
|
f5e87b |
prevSameLayer = p;
|
|
|
f5e87b |
p->nextSameLayer = this;
|
|
|
f5e87b |
break;
|
|
|
f5e87b |
}
|
|
|
f5e87b |
|
|
|
62f661 |
if (prevSameLayer == NULL) {
|
|
|
62f661 |
rendering::SurfaceResource::LockRead<rendering::surfacesw> lock(layer->rendering_surface);</rendering::surfacesw>
|
|
|
62f661 |
if (lock) surface = lock->get_surface();
|
|
|
62f661 |
}
|
|
|
f5e87b |
new_tl = tl = layer->get_param("tl").get(Point());
|
|
|
f5e87b |
new_br = br = layer->get_param("br").get(Point());
|
|
|
f5e87b |
|
|
|
f5e87b |
prepared = true;
|
|
|
f5e87b |
}
|
|
|
f5e87b |
|
|
|
f5e87b |
|
|
|
f5e87b |
void
|
|
|
f5e87b |
Action::LayerPaint::PaintStroke::undo()
|
|
|
f5e87b |
{
|
|
|
f5e87b |
assert(prepared);
|
|
|
f5e87b |
if (!applied) return;
|
|
|
f5e87b |
{
|
|
Rodolfo Ribeiro Gomes |
cfe072 |
std::lock_guard<std::mutex> lock(layer->mutex);</std::mutex>
|
|
|
20e596 |
Surface *surface = new Surface();
|
|
|
20e596 |
paint_prev(*surface);
|
|
|
20e596 |
layer->rendering_surface = new rendering::SurfaceResource(
|
|
|
20e596 |
new rendering::SurfaceSW(*surface, true) );
|
|
|
f5e87b |
}
|
|
|
f5e87b |
applied = false;
|
|
|
f5e87b |
layer->set_param("tl", ValueBase(tl));
|
|
|
f5e87b |
layer->set_param("br", ValueBase(br));
|
|
|
f5e87b |
layer->changed();
|
|
|
f5e87b |
}
|
|
|
f5e87b |
|
|
|
f5e87b |
void
|
|
|
f5e87b |
Action::LayerPaint::PaintStroke::apply()
|
|
|
f5e87b |
{
|
|
|
f5e87b |
assert(prepared);
|
|
|
f5e87b |
if (applied) return;
|
|
|
f5e87b |
{
|
|
Rodolfo Ribeiro Gomes |
cfe072 |
std::lock_guard<std::mutex> lock(layer->mutex);</std::mutex>
|
|
|
20e596 |
Surface *surface = new Surface();
|
|
|
20e596 |
paint_self(*surface);
|
|
|
20e596 |
layer->rendering_surface = new rendering::SurfaceResource(
|
|
|
20e596 |
new rendering::SurfaceSW(*surface, true) );
|
|
|
f5e87b |
}
|
|
|
f5e87b |
applied = true;
|
|
|
f5e87b |
layer->set_param("tl", ValueBase(new_tl));
|
|
|
f5e87b |
layer->set_param("br", ValueBase(new_br));
|
|
|
f5e87b |
layer->changed();
|
|
|
f5e87b |
}
|
|
|
f5e87b |
|
|
|
f5e87b |
|
|
|
f5e87b |
|
|
|
0dde72 |
Action::LayerPaint::LayerPaint():
|
|
|
0dde72 |
applied(false)
|
|
|
0dde72 |
{ }
|
|
|
f5e87b |
|
|
|
9e9ccd |
Action::ParamVocab
|
|
|
9e9ccd |
Action::LayerPaint::get_param_vocab()
|
|
|
9e9ccd |
{
|
|
|
9e9ccd |
ParamVocab ret(Action::CanvasSpecific::get_param_vocab());
|
|
|
9e9ccd |
return ret;
|
|
|
9e9ccd |
}
|
|
|
9e9ccd |
|
|
|
9e9ccd |
bool
|
|
|
f5e87b |
Action::LayerPaint::is_candidate(const ParamList & /* x */)
|
|
|
9e9ccd |
{
|
|
|
9e9ccd |
return false;
|
|
|
9e9ccd |
}
|
|
|
9e9ccd |
|
|
|
9e9ccd |
bool
|
|
|
9e9ccd |
Action::LayerPaint::set_param(const synfig::String& name, const Action::Param ¶m)
|
|
|
9e9ccd |
{
|
|
|
9e9ccd |
return Action::CanvasSpecific::set_param(name,param);
|
|
|
9e9ccd |
}
|
|
|
9e9ccd |
|
|
|
9e9ccd |
bool
|
|
|
9e9ccd |
Action::LayerPaint::is_ready()const
|
|
|
9e9ccd |
{
|
|
|
f5e87b |
if(!stroke.is_prepared())
|
|
|
9e9ccd |
return false;
|
|
|
9e9ccd |
return Action::CanvasSpecific::is_ready();
|
|
|
9e9ccd |
}
|
|
|
9e9ccd |
|
|
|
9e9ccd |
void
|
|
|
9e9ccd |
Action::LayerPaint::perform()
|
|
|
9e9ccd |
{
|
|
|
0dde72 |
assert(!applied);
|
|
|
f5e87b |
stroke.apply();
|
|
|
0dde72 |
if (!applied) stroke.get_layer()->add_surface_modification_id(id);
|
|
|
0dde72 |
applied = !applied;
|
|
|
9e9ccd |
}
|
|
|
9e9ccd |
|
|
|
9e9ccd |
void
|
|
|
9e9ccd |
Action::LayerPaint::undo()
|
|
|
9e9ccd |
{
|
|
|
0dde72 |
assert(applied);
|
|
|
f5e87b |
stroke.undo();
|
|
|
0dde72 |
if (applied) stroke.get_layer()->add_surface_modification_id(id);
|
|
|
0dde72 |
applied = !applied;
|
|
|
9e9ccd |
}
|