Blame synfig-studio/src/brushlib.h

4a0d4f
/* === S Y N F I G ========================================================= */
f5e87b
/*!	\file brushlib.h
4a0d4f
**	\brief Helper file to integrte brushlib into synfig
4a0d4f
**
4a0d4f
**	$Id$
4a0d4f
**
4a0d4f
**	\legal
4a0d4f
**	......... ... 2014 Ivan Mahonin
4a0d4f
**
4a0d4f
**	This package is free software; you can redistribute it and/or
4a0d4f
**	modify it under the terms of the GNU General Public License as
4a0d4f
**	published by the Free Software Foundation; either version 2 of
4a0d4f
**	the License, or (at your option) any later version.
4a0d4f
**
4a0d4f
**	This package is distributed in the hope that it will be useful,
4a0d4f
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
4a0d4f
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4a0d4f
**	General Public License for more details.
4a0d4f
**	\endlegal
4a0d4f
*/
4a0d4f
/* ========================================================================= */
4a0d4f
4a0d4f
/* === S T A R T =========================================================== */
4a0d4f
4a0d4f
#ifndef __SYNFIG_BRUSH_H
4a0d4f
#define __SYNFIG_BRUSH_H
4a0d4f
4a0d4f
/* === H E A D E R S ======================================================= */
4a0d4f
4a0d4f
#include <synfig surface.h=""></synfig>
4a0d4f
#include <etl angle=""> // we need PI</etl>
4a0d4f
#include "brushlib/brushlib.hpp"
4a0d4f
4a0d4f
/* === M A C R O S ========================================================= */
4a0d4f
4a0d4f
/* === T Y P E D E F S ===================================================== */
4a0d4f
4a0d4f
/* === C L A S S E S & S T R U C T S ======================================= */
4a0d4f
f5e87b
namespace brushlib {
4a0d4f
	class ActiveSurface: public Surface {
4a0d4f
	public:
4a0d4f
		virtual bool draw_dab(
4a0d4f
			float /* x */, float /* y */,
4a0d4f
			float /* radius */,
4a0d4f
			float /* color_r */, float /* color_g */, float /* color_b */,
4a0d4f
			float /* opaque */, float /* hardness */ = 0.5,
4a0d4f
			float /* alpha_eraser */ = 1.0,
4a0d4f
			float /* aspect_ratio */ = 1.0, float /* angle */ = 0.0,
4a0d4f
			float /* lock_alpha */ = 0.0
4a0d4f
		) { return false; };
4a0d4f
4a0d4f
		virtual void get_color(
4a0d4f
			float /* x */, float /* y */,
4a0d4f
			float /* radius */,
4a0d4f
			float * color_r, float * color_g, float * color_b, float * color_a
4a0d4f
		) { *color_r = 0.f; *color_g = 0.f; *color_b = 0.f; *color_a = 0.f; };
4a0d4f
	};
4a0d4f
4a0d4f
	class SurfaceWrapper: public ActiveSurface {
4a0d4f
	public:
4a0d4f
		typedef synfig::Surface surface_type;
4a0d4f
		surface_type *surface;
7cf47e
		int extra_left;
7cf47e
		int extra_right;
7cf47e
		int extra_top;
7cf47e
		int extra_bottom;
7cf47e
		int offset_x;
7cf47e
		int offset_y;
7cf47e
7cf47e
		explicit SurfaceWrapper(surface_type *surface = NULL):
7cf47e
			surface(surface),
7cf47e
			extra_left(0), extra_right(0),
7cf47e
			extra_top(0), extra_bottom(0),
7cf47e
			offset_x(0), offset_y(0) { }
7cf47e
7cf47e
		void reset() {
7cf47e
			extra_left = 0;
7cf47e
			extra_right = 0;
7cf47e
			extra_top = 0;
7cf47e
			extra_bottom = 0;
7cf47e
			offset_x = 0;
7cf47e
			offset_y = 0;
7cf47e
		}
4a0d4f
4a0d4f
		virtual bool draw_dab(
4a0d4f
			float x, float y,
4a0d4f
			float radius,
4a0d4f
			float color_r, float color_g, float color_b,
4a0d4f
			float opaque, float hardness = 0.5,
86e662
			float alpha_eraser = 1.0,
4a0d4f
			float aspect_ratio = 1.0, float angle = 0.0,
2b4e2c
			float /* lock_alpha */ = 0.0
4a0d4f
		) {
4a0d4f
			if (surface == NULL) return false;
4a0d4f
7cf47e
			x += (float)offset_x;
7cf47e
			y += (float)offset_y;
7cf47e
4a0d4f
			float cs = cosf(angle/180.f*(float)PI);
4a0d4f
			float sn = sinf(angle/180.f*(float)PI);
4a0d4f
4a0d4f
			// calculate bounds
374475
			if (aspect_ratio < 1.0) aspect_ratio = 1.0;
374475
			if (hardness > 1.0) hardness = 1.0;
374475
			if (hardness < 0.0) hardness = 0.0;
374475
			float maxr = fabsf(radius);
4a0d4f
			int x0 = (int)(x - maxr - 1.f);
4a0d4f
			int x1 = (int)(x + maxr + 1.f);
4a0d4f
			int y0 = (int)(y - maxr - 1.f);
4a0d4f
			int y1 = (int)(y + maxr + 1.f);
4a0d4f
7cf47e
			if (x0 < 0
7cf47e
			 || y0 < 0
7cf47e
			 || x1+1 > surface->get_w()
7cf47e
			 || y1+1 > surface->get_h() )
7cf47e
			{
7cf47e
				int l = x0 < 0 ? x0 : 0;
7cf47e
				int t = y0 < 0 ? y0 : 0;
7cf47e
				int r = x1+1 > surface->get_w() ? x1+1 : surface->get_w();
7cf47e
				int b = y1+1 > surface->get_h() ? y1+1 : surface->get_h();
7cf47e
7cf47e
				extra_left   -= l; // increase because l and t is negative
7cf47e
				extra_top    -= t;
7cf47e
				extra_right  += r - surface->get_w();
7cf47e
				extra_bottom += b - surface->get_h();
7cf47e
f5e87b
				synfig::Surface tmp;
f5e87b
				tmp = *surface;
7cf47e
				surface->set_wh(r-l, b-t);
7cf47e
				surface->clear();
7cf47e
				synfig::Surface::pen p(surface->get_pen(-l, -t));
7cf47e
				tmp.blit_to(p);
7cf47e
7cf47e
				offset_x -= l;
7cf47e
				offset_y -= t;
7cf47e
				x -= (float)l; y -= (float)t;
7cf47e
				x0 -= l; y0 -= t;
7cf47e
				x1 -= l; y1 -= t;
7cf47e
			}
4a0d4f
86e662
			bool erase = alpha_eraser < 1.0;
4a0d4f
			for(int py = y0; py <= y1; py++)
4a0d4f
			{
4a0d4f
				for(int px = x0; px <= x1; px++)
4a0d4f
				{
4a0d4f
					float dx = (float)px - x;
4a0d4f
					float dy = (float)py - y;
4a0d4f
					float dyr = (dy*cs-dx*sn)*aspect_ratio;
4a0d4f
					float dxr = (dy*sn+dx*cs);
4a0d4f
					float dd = (dyr*dyr + dxr*dxr) / (radius*radius);
374475
					if (dd <= 1.f)
374475
					{
374475
						float opa = dd < hardness
374475
								  ? dd + 1-(dd/hardness)
374475
								  : hardness/(1-hardness)*(1-dd);
86e662
						opa *= opaque;
86e662
						synfig::Color &c = (*surface)[py][px];
86e662
						if (erase)
86e662
						{
86e662
							c.set_a(c.get_a()*(1.0 - (1.0 - alpha_eraser)*opa));
86e662
						}
86e662
						else
86e662
						{
86e662
							float sum_alpha = opa + c.get_a();
86e662
							if (sum_alpha > 1.0) sum_alpha = 1.0;
86e662
							float inv_opa = sum_alpha - opa;
86e662
							c.set_r(c.get_r()*inv_opa + color_r*opa);
86e662
							c.set_g(c.get_g()*inv_opa + color_g*opa);
86e662
							c.set_b(c.get_b()*inv_opa + color_b*opa);
86e662
							c.set_a(sum_alpha);
86e662
						}
374475
					}
4a0d4f
				}
4a0d4f
			}
4a0d4f
4a0d4f
			return true;
4a0d4f
		};
4a0d4f
4a0d4f
		virtual void get_color(
4a0d4f
			float x, float y,
2b4e2c
			float /* radius */,
4a0d4f
			float * color_r, float * color_g, float * color_b, float * color_a
4a0d4f
		) {
4a0d4f
			if (surface == NULL) {
4a0d4f
				*color_r = 0.f; *color_g = 0.f; *color_b = 0.f; *color_a = 0.f;
4a0d4f
				return;
4a0d4f
			}
4a0d4f
7cf47e
			x += (float)offset_x;
7cf47e
			y += (float)offset_y;
7cf47e
4a0d4f
			synfig::Color c = surface->cubic_sample(x, y);
4a0d4f
			*color_r = c.get_r();
4a0d4f
			*color_g = c.get_g();
4a0d4f
			*color_b = c.get_b();
4a0d4f
			*color_a = c.get_a();
4a0d4f
		};
4a0d4f
	};
4a0d4f
4a0d4f
}; // END of namespace brush
4a0d4f
4a0d4f
/* === E N D =============================================================== */
4a0d4f
4a0d4f
#endif