Merge branch 'genete_master'
[synfig.git] / synfig-core / src / synfig / surface.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file surface.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 **
21 ** === N O T E S ===========================================================
22 **
23 ** ========================================================================= */
24
25 /* === H E A D E R S ======================================================= */
26
27 #define SYNFIG_NO_ANGLE
28
29 #ifdef USING_PCH
30 #       include "pch.h"
31 #else
32 #ifdef HAVE_CONFIG_H
33 #       include <config.h>
34 #endif
35
36 #include "canvas.h"
37 #include "surface.h"
38 #include "target_scanline.h"
39 #include "general.h"
40
41 #ifdef HAS_VIMAGE
42 #include <Accelerate/Accelerate.h>
43 #endif
44
45 #endif
46
47 using namespace synfig;
48 using namespace std;
49 using namespace etl;
50
51 /* === M A C R O S ========================================================= */
52
53 /* === G L O B A L S ======================================================= */
54
55 class target2surface : public synfig::Target_Scanline
56 {
57 public:
58         Surface *surface;
59         bool     sized;
60 public:
61         target2surface(Surface *surface);
62         virtual ~target2surface();
63
64         virtual bool set_rend_desc(synfig::RendDesc *newdesc);
65
66         virtual bool start_frame(synfig::ProgressCallback *cb);
67
68         virtual void end_frame();
69
70         virtual Color * start_scanline(int scanline);
71
72         virtual bool end_scanline();
73 };
74
75 target2surface::target2surface(Surface *surface):surface(surface)
76 {
77 }
78
79 target2surface::~target2surface()
80 {
81 }
82
83 bool
84 target2surface::set_rend_desc(synfig::RendDesc *newdesc)
85 {
86         assert(newdesc);
87         assert(surface);
88         desc=*newdesc;
89         return synfig::Target_Scanline::set_rend_desc(newdesc);
90 }
91
92 bool
93 target2surface::start_frame(synfig::ProgressCallback */*cb*/)
94 {
95         if(surface->get_w() != desc.get_w() || surface->get_h() != desc.get_h())
96         {
97                 surface->set_wh(desc.get_w(),desc.get_h());
98         }
99         return true;
100 }
101
102 void
103 target2surface::end_frame()
104 {
105         return;
106 }
107
108 Color *
109 target2surface::start_scanline(int scanline)
110 {
111         return (*surface)[scanline];
112 }
113
114 bool
115 target2surface::end_scanline()
116 {
117         return true;
118 }
119
120 /* === P R O C E D U R E S ================================================= */
121
122 /* === M E T H O D S ======================================================= */
123
124 Target_Scanline::Handle
125 synfig::surface_target(Surface *surface)
126 {
127         return Target_Scanline::Handle(new target2surface(surface));
128 }
129
130 void
131 synfig::Surface::clear()
132 {
133 #ifdef HAS_VIMAGE
134         fill(Color(0.5,0.5,0.5,0.0000001));
135 #else
136         etl::surface<Color, ColorAccumulator, ColorPrep>::clear();
137 #endif
138 }
139
140 void
141 synfig::Surface::blit_to(alpha_pen& pen, int x, int y, int w, int h)
142 {
143         static const float epsilon(0.00001);
144         const float alpha(pen.get_alpha());
145         if(     pen.get_blend_method()==Color::BLEND_STRAIGHT && fabs(alpha-1.0f)<epsilon )
146         {
147                 if(x>=get_w() || y>=get_w())
148                         return;
149
150                 //clip source origin
151                 if(x<0)
152                 {
153                         w+=x;   //decrease
154                         x=0;
155                 }
156
157                 if(y<0)
158                 {
159                         h+=y;   //decrease
160                         y=0;
161                 }
162
163                 //clip width against dest width
164                 w = min((long)w,(long)(pen.end_x()-pen.x()));
165                 h = min((long)h,(long)(pen.end_y()-pen.y()));
166
167                 //clip width against src width
168                 w = min(w,get_w()-x);
169                 h = min(h,get_h()-y);
170
171                 if(w<=0 || h<=0)
172                         return;
173
174                 for(int i=0;i<h;i++)
175                 {
176                         char* src(static_cast<char*>(static_cast<void*>(operator[](y)+x))+i*get_w()*sizeof(Color));
177                         char* dest(static_cast<char*>(static_cast<void*>(pen.x()))+i*pen.get_width()*sizeof(Color));
178                         memcpy(dest,src,w*sizeof(Color));
179                 }
180                 return;
181         }
182
183 #ifdef HAS_VIMAGE
184         if(     pen.get_blend_method()==Color::BLEND_COMPOSITE && fabs(alpha-1.0f)<epsilon )
185         {
186                 if(x>=get_w() || y>=get_w())
187                         return;
188
189                 //clip source origin
190                 if(x<0)
191                 {
192                         //u-=x; //increase
193                         w+=x;   //decrease
194                         x=0;
195                 }
196
197                 if(y<0)
198                 {
199                         //v-=y; //increase
200                         h+=y;   //decrease
201                         y=0;
202                 }
203
204                 //clip width against dest width
205                 w = min(w,pen.end_x()-pen.x());
206                 h = min(h,pen.end_y()-pen.y());
207
208                 //clip width against src width
209                 w = min(w,get_w()-x);
210                 h = min(h,get_h()-y);
211
212                 if(w<=0 || h<=0)
213                         return;
214
215
216
217                 vImage_Buffer top,bottom;
218                 vImage_Buffer& dest(bottom);
219
220                 top.data=static_cast<void*>(operator[](y)+x);
221                 top.height=h;
222                 top.width=w;
223                 //top.rowBytes=get_w()*sizeof(Color); //! \todo this should get the pitch!!
224                 top.rowBytes=get_pitch();
225
226                 bottom.data=static_cast<void*>(pen.x());
227                 bottom.height=h;
228                 bottom.width=w;
229                 //bottom.rowBytes=pen.get_width()*sizeof(Color); //! \todo this should get the pitch!!
230                 bottom.rowBytes=pen.get_pitch(); //! \todo this should get the pitch!!
231
232                 vImage_Error ret;
233                 ret=vImageAlphaBlend_ARGBFFFF(&top,&bottom,&dest,kvImageNoFlags);
234
235                 assert(ret!=kvImageNoError);
236
237                 return;
238         }
239 #endif
240         etl::surface<Color, ColorAccumulator, ColorPrep>::blit_to(pen,x,y,w,h);
241 }
242