Blame synfig-studio/src/synfigapp/actions/layerpaint.cpp

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
}