1 /* === S Y N F I G ========================================================= */
2 /*!	\file surface.h
3 **	\brief Surface and Pen Definitions
4 **
5 **	$Id$
6 **
7 **	\legal
8 **	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **	Copyright (c) 2012-2013 Carlos López
10 **
11 **	This package is free software; you can redistribute it and/or
12 **	modify it under the terms of the GNU General Public License as
13 **	published by the Free Software Foundation; either version 2 of
14 **	the License, or (at your option) any later version.
15 **
16 **	This package is distributed in the hope that it will be useful,
17 **	but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 **	General Public License for more details.
20 **	\endlegal
21 */
22 /* ========================================================================= */
23 
24 /* === S T A R T =========================================================== */
25 
26 #ifndef __SYNFIG_SURFACE_H
27 #define __SYNFIG_SURFACE_H
28 
29 /* === H E A D E R S ======================================================= */
30 
31 #include "color.h"
32 #include "renddesc.h"
33 #include <ETL/pen>
34 #include <ETL/surface>
35 #include <ETL/handle>
36 
37 #include "cairo.h"
38 
39 /* === M A C R O S ========================================================= */
40 
41 /* === T Y P E D E F S ===================================================== */
42 
43 /* === C L A S S E S & S T R U C T S ======================================= */
44 
45 namespace synfig {
46 
47 class Target;
48 class Target_Scanline;
49 class Target_Cairo;
50 class Target_Tile;
51 
52 class ColorPrep
53 {
54 public:
cook_static(Color x)55 	static ColorAccumulator cook_static(Color x)
56 	{
57 		x.set_r(x.get_r()*x.get_a());
58 		x.set_g(x.get_g()*x.get_a());
59 		x.set_b(x.get_b()*x.get_a());
60 		return x;
61 	}
uncook_static(ColorAccumulator x)62 	static Color uncook_static(ColorAccumulator x)
63 	{
64 		if(!x.get_a())
65 			return Color::alpha();
66 
67 		const float a(1.0f/x.get_a());
68 
69 		x.set_r(x.get_r()*a);
70 		x.set_g(x.get_g()*a);
71 		x.set_b(x.get_b()*a);
72 		return x;
73 	}
74 
cook(Color x)75 	ColorAccumulator cook(Color x)const
76 		{ return cook_static(x); }
uncook(ColorAccumulator x)77 	Color uncook(ColorAccumulator x)const
78 		{ return uncook_static(x); }
79 };
80 
81 class CairoColorPrep
82 {
83 public:
cook(CairoColor x)84 	CairoColor cook(CairoColor x)const
85 	{
86 		return x.premult_alpha();
87 	}
uncook(CairoColor x)88 	CairoColor uncook(CairoColor x)const
89 	{
90 		return x.demult_alpha();
91 	}
92 };
93 
94 /*!	\class Surface
95 **	\brief Bitmap Surface
96 **	\todo writeme
97 */
98 class Surface : public etl::surface<Color, ColorAccumulator, ColorPrep>
99 {
100 public:
101 	typedef Color value_type;
102 	class alpha_pen;
103 
Surface()104 	Surface() { }
105 
Surface(const size_type::value_type & w,const size_type::value_type & h)106 	Surface(const size_type::value_type &w, const size_type::value_type &h):
107 		etl::surface<Color, ColorAccumulator,ColorPrep>(w,h) { }
108 
Surface(const size_type & s)109 	Surface(const size_type &s):
110 		etl::surface<Color, ColorAccumulator,ColorPrep>(s) { }
111 
112 	template <typename _pen>
Surface(const _pen & _begin,const _pen & _end)113 	Surface(const _pen &_begin, const _pen &_end):
114 		etl::surface<Color, ColorAccumulator,ColorPrep>(_begin,_end) { }
115 
blit_to(_pen & pen)116 	template <class _pen> void blit_to(_pen &pen)
117 	{ return blit_to(pen,0,0, get_w(),get_h()); }
118 
119 	template <class _pen> void
blit_to(_pen & DEST_PEN,int x,int y,int w,int h)120 	blit_to(_pen& DEST_PEN,	int x, int y, int w, int h)
121 	{
122 		etl::surface<Color, ColorAccumulator, ColorPrep>::blit_to(DEST_PEN,x,y,w,h);
123 	}
124 
125 	void clear();
126 
127 	void blit_to(alpha_pen& DEST_PEN, int x, int y, int w, int h);
128 };	// END of class Surface
129 
130 
131 /*!	\class CairoSurface
132  **	\brief Generic Cairo backed surface. It allows to create a image surface
133  ** equivalent to the current backend for custom modifications purposes.
134  **	\todo writeme
135  */
136 class CairoSurface : public etl::surface<CairoColor, CairoColorAccumulator, CairoColorPrep>
137 {
138 	// This is the Cairo surface pointer
139 	// It is NULL if the not initialized
140 	cairo_surface_t *cs_;
141 	// This pointer is used when map and unmap the cairo_surface to a cairo_image_surface
142 	// see map_cairo_surface() unmap_cairo_surface();
143 	cairo_surface_t *cs_image_;
144 
145 public:
146 	typedef CairoColor value_type;
147 	class alpha_pen;
148 
CairoSurface()149 	CairoSurface():cs_(NULL), cs_image_(NULL) {  }
CairoSurface(cairo_surface_t * cs)150 	CairoSurface(cairo_surface_t *cs):cs_(NULL), cs_image_(NULL) { set_cairo_surface(cs); }
~CairoSurface()151 	~CairoSurface() {
152 	if(cs_!= NULL) cairo_surface_destroy(cs_);
153 	if(cs_image_!=NULL) cairo_surface_destroy(cs_image_); }
154 
155 
156 	// If cs_ is set then the set_wh does nothing
157 	// If cs_ is not set then set_wh creates a cairo_surface_image on cs_image_
158 	// of size wxh
159 	void set_wh(int w, int h, int pitch=0);
160 	// Use whits version of set_wh to directly give to the etl::surface the
161 	// pointer to data, the width, height and pitch (stride) between rows
set_wh(int w,int h,unsigned char * data,int pitch)162 	void set_wh(int w, int h, unsigned char* data, int pitch)
163 	{ etl::surface<CairoColor, CairoColorAccumulator, CairoColorPrep>::set_wh(w, h, data, pitch); }
164 	// specialization of etl::surface::blit_to that considers the possibility of
165 	// don't blend colors when blend method is straight and alpha is 1.0
166 	void blit_to(alpha_pen& DEST_PEN, int x, int y, int w, int h);
167 
168 	// Use this function to reference one given generic cairo_surface
169 	// by this surface class.
170 	// When the CairoSurface instance is destructed the reference counter of the
171 	// cairo_surface_t shoud be decreased.
172 	// It is also possible to detach the cairo surface passing NULL as argument.
173 	// If the cairo surface is mapped at the time of call this function, then
174 	// it is unmaped first.
175 	void set_cairo_surface(cairo_surface_t *cs);
176 	// Returns an increased reference pointer of the surface. The receiver is responsible
177 	// of destroy the surface once referenced.
178 	cairo_surface_t* get_cairo_surface()const;
179 	// Returns an increased reference pointer of the image surface. The receiver is responsible
180 	// of destroy the surface once referenced.
181 	cairo_surface_t* get_cairo_image_surface()const;
182 	// Maps cs_ to cs_image_ and extract the *data to etl::surface::data for further modifications
183 	// It will flush any remaining painting operation to the cs_
184 	// returns true on success or false if something failed
185 	bool map_cairo_image();
186 	// Unmap the cs_image_ to cs_ after external modification has been done via *data
187 	// It will mark cs_ as dirty
188 	void unmap_cairo_image();
189 	// Returns true if the cairo_surface_t* cs_ is mapped on cs_image_
190 	bool is_mapped()const;
191 
192 };	// END of class Surface
193 
194 
195 #ifndef DOXYGEN_SKIP
196 
197 /*! \internal Used by Pen_Alpha */
198 template <class C, typename A=Color::value_type>
199 struct _BlendFunc
200 {
201 	Color::BlendMethod blend_method;
202 
blend_method_BlendFunc203 	_BlendFunc(typename Color::BlendMethod b= Color::BLEND_COMPOSITE):blend_method(b) { }
204 
operator_BlendFunc205 	C operator()(const C &a,const C &b,const A &t)const
206 	{
207 		return C::blend(b,a,t,blend_method);
208 	}
209 };	// END of class _BlendFunc
210 
211 #endif
212 
213 /*!	\class Surface::alpha_pen
214 **	\brief Alpha-Blending Pen
215 **
216 **	This pen works like a normal alpha pen, except that it supports
217 **	a variety of blending methods. Use set_blend_method() to select
218 **	which blending method you want to use.
219 **	The default blending method is Color::BLEND_COMPOSITE.
220 **	\see Color::BlendMethod
221 */
222 class Surface::alpha_pen : public etl::alpha_pen< etl::generic_pen<Color, ColorAccumulator>, Color::value_type, _BlendFunc<Color> >
223 {
224 public:
alpha_pen()225 	alpha_pen() { }
alpha_pen(const etl::alpha_pen<etl::generic_pen<Color,ColorAccumulator>,Color::value_type,_BlendFunc<Color>> & x)226 	alpha_pen(const etl::alpha_pen< etl::generic_pen<Color, ColorAccumulator>, Color::value_type, _BlendFunc<Color> > &x):
227 		etl::alpha_pen< etl::generic_pen<Color, ColorAccumulator>, Color::value_type, _BlendFunc<Color> >(x)
228 	{ }
229 
230 	alpha_pen(const etl::generic_pen<Color, ColorAccumulator>& pen, const Color::value_type &a = 1, const _BlendFunc<Color> &func = _BlendFunc<Color>()):
231 		etl::alpha_pen< etl::generic_pen<Color, ColorAccumulator>, Color::value_type, _BlendFunc<Color> >(pen,a,func)
232 	{ }
233 
234 	//! Sets the blend method to that described by \a method
set_blend_method(Color::BlendMethod method)235 	void set_blend_method(Color::BlendMethod method) { affine_func_.blend_method=method; }
236 
237 	//! Returns the blend method being used for this pen
get_blend_method()238 	Color::BlendMethod get_blend_method()const { return affine_func_.blend_method; }
239 };	// END of class Surface::alpha_pen
240 
241 
242 
243 /*!	\class CairoSurface::alpha_pen
244  **	\brief Alpha-Blending Pen
245  **
246  **	This pen works like a normal alpha pen, except that it supports
247  **	a variety of blending methods. Use set_blend_method() to select
248  **	which blending method you want to use.
249  **	The default blending method is Color::BLEND_COMPOSITE.
250  **	\see Color::BlendMethod
251  */
252 class CairoSurface::alpha_pen : public etl::alpha_pen< etl::generic_pen<CairoColor, CairoColorAccumulator>, float, _BlendFunc<CairoColor> >
253 {
254 public:
alpha_pen()255 	alpha_pen() { }
alpha_pen(const etl::alpha_pen<etl::generic_pen<CairoColor,CairoColorAccumulator>,float,_BlendFunc<CairoColor>> & x)256 	alpha_pen(const etl::alpha_pen< etl::generic_pen<CairoColor, CairoColorAccumulator>, float, _BlendFunc<CairoColor> > &x):
257 	etl::alpha_pen< etl::generic_pen<CairoColor, CairoColorAccumulator>, float, _BlendFunc<CairoColor> >(x)
258 	{ }
259 
260 	alpha_pen(const etl::generic_pen<CairoColor, CairoColorAccumulator>& pen, const float &a = 1, const _BlendFunc<CairoColor> &func = _BlendFunc<CairoColor>()):
261 	etl::alpha_pen< etl::generic_pen<CairoColor, CairoColorAccumulator>, float, _BlendFunc<CairoColor> >(pen,a,func)
262 	{ }
263 
264 	//! Sets the blend method to that described by \a method
set_blend_method(Color::BlendMethod method)265 	void set_blend_method(Color::BlendMethod method) { affine_func_.blend_method=method; }
266 
267 	//! Returns the blend method being used for this pen
get_blend_method()268 	Color::BlendMethod get_blend_method()const { return affine_func_.blend_method; }
269 };	// END of class CairoSurface::alpha_pen
270 
271 
272 
273 //! Creates a target that will render to \a surface by specified \a renderer
274 etl::handle<Target_Tile> surface_target(Surface *surface, const String &renderer = String());
275 //! Creates a target that will render to \a surface by specified \a renderer
276 etl::handle<Target_Scanline> surface_target_scanline(Surface *surface);
277 //!Creates a target that will render to a cairo_surface_t image surface
278 etl::handle<Target_Cairo> cairo_image_target(cairo_surface_t** surface);
279 
280 }; // END of namespace synfig
281 
282 /* === E N D =============================================================== */
283 
284 #endif
285