Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-core / tags / synfig_0_61_03 / synfig-core / src / modules / mod_filter / halftone3.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file halftone3.cpp
3 **      \brief blehh
4 **
5 **      $Id: halftone3.cpp,v 1.1.1.1 2005/01/04 01:23:10 darco Exp $
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 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include "halftone3.h"
33 #include "halftone.h"
34
35 #include <synfig/string.h>
36 #include <synfig/time.h>
37 #include <synfig/context.h>
38 #include <synfig/paramdesc.h>
39 #include <synfig/renddesc.h>
40 #include <synfig/surface.h>
41 #include <synfig/value.h>
42 #include <synfig/valuenode.h>
43
44 #endif
45
46 /* === M A C R O S ========================================================= */
47
48 using namespace synfig;
49 using namespace std;
50 using namespace etl;
51
52 /* === G L O B A L S ======================================================= */
53
54 SYNFIG_LAYER_INIT(Halftone3);
55 SYNFIG_LAYER_SET_NAME(Halftone3,"halftone3");
56 SYNFIG_LAYER_SET_LOCAL_NAME(Halftone3,_("Halftone3"));
57 SYNFIG_LAYER_SET_CATEGORY(Halftone3,_("Filters"));
58 SYNFIG_LAYER_SET_VERSION(Halftone3,"0.0");
59 SYNFIG_LAYER_SET_CVS_ID(Halftone3,"$Id: halftone3.cpp,v 1.1.1.1 2005/01/04 01:23:10 darco Exp $");
60
61 /* === P R O C E D U R E S ================================================= */
62
63 #define HALFSQRT2       (0.7)
64 #define SQRT2   (1.414213562f)
65
66 /* === M E T H O D S ======================================================= */
67
68 Halftone3::Halftone3()
69 {
70         size=(synfig::Vector(0.25,0.25));
71         type=TYPE_SYMMETRIC;
72
73         for(int i=0;i<3;i++)
74         {
75                 tone[i].size=size;
76                 tone[i].type=type;
77                 tone[i].offset=(synfig::Point(0,0));
78                 tone[i].angle=Angle::deg(30.0)*(float)i;
79         }
80
81         subtractive=true;
82
83         if(subtractive)
84         {
85                 color[0]=Color::cyan();
86                 color[1]=Color::magenta();
87                 color[2]=Color::yellow();
88         }
89         else
90         {
91                 color[0]=Color::red();
92                 color[1]=Color::green();
93                 color[2]=Color::blue();
94         }
95                 
96         set_blend_method(Color::BLEND_STRAIGHT);
97
98         for(int i=0;i<3;i++)
99                 for(int j=0;j<3;j++)
100                         inverse_matrix[i][j]=(j==i)?1.0f:0.0f;
101
102         sync();
103 }
104
105 void
106 Halftone3::sync()
107 {
108         for(int i=0;i<3;i++)
109         {
110                 tone[i].size=size;
111                 tone[i].type=type;
112         }
113         
114 #define matrix inverse_matrix
115         //float matrix[3][3];
116         
117         if(subtractive)
118         {
119                 for(int i=0;i<3;i++)
120                 {
121                         matrix[i][0]=1.0f-(color[i].get_r());
122                         matrix[i][1]=1.0f-(color[i].get_g());
123                         matrix[i][2]=1.0f-(color[i].get_b());
124                         float mult=sqrt(matrix[i][0]*matrix[i][0]+matrix[i][1]*matrix[i][1]+matrix[i][2]*matrix[i][2]);
125                         if(mult)
126                         {
127                                 matrix[i][0]/=mult;
128                                 matrix[i][1]/=mult;
129                                 matrix[i][2]/=mult;
130                                 matrix[i][0]/=mult;
131                                 matrix[i][1]/=mult;
132                                 matrix[i][2]/=mult;
133                         }
134                 }
135         }
136         else
137         {
138                 for(int i=0;i<3;i++)
139                 {
140                         matrix[i][0]=color[i].get_r();
141                         matrix[i][1]=color[i].get_g();
142                         matrix[i][2]=color[i].get_b();
143                         float mult=sqrt(matrix[i][0]*matrix[i][0]+matrix[i][1]*matrix[i][1]+matrix[i][2]*matrix[i][2]);
144                         if(mult)
145                         {
146                                 matrix[i][0]/=mult;
147                                 matrix[i][1]/=mult;
148                                 matrix[i][2]/=mult;
149                                 matrix[i][0]/=mult;
150                                 matrix[i][1]/=mult;
151                                 matrix[i][2]/=mult;
152                         }
153                 }
154         }
155 #undef matrix
156
157         
158         
159 #if 0
160         // Insert guass-jordan elimination code here
161         int k=0,i=0,j=0,z_size=3;
162 #define A inverse_matrix
163         
164         for (k=0;k<z_size;k++)   
165   // the pivot element 
166     { A[k][k]= -1/A[k][k];   
167  
168   //the pivot column
169      for (i=0;i<z_size;i++)             
170          if (i!=k) A[i][k]*=A[k][k];
171
172  //elements not in a pivot row or column
173      for (i=0;i<z_size;i++)
174         if (i!=k) 
175             for (j=0;j<z_size;j++)
176                       if (j!=k)
177                           A[i][j]+=A[i][k]*A[k][j];
178
179  //elements in a pivot row
180     for (i=0;i<z_size;i++)
181        if (i!=k) 
182             A[k][i]*=A[k][k];
183    }
184
185  //change sign
186    for (i=0;i<z_size;i++)        /*reverse sign*/
187      for (j=0;j<z_size;j++)
188         A[i][j]=-A[i][j];       
189 #undef A
190 #endif
191 }
192
193 inline Color
194 Halftone3::color_func(const Point &point, float supersample,const Color& in_color)const
195 {
196         Color halfcolor;
197
198         float chan[3];
199         
200         
201         if(subtractive)
202         {
203                 chan[0]=inverse_matrix[0][0]*(1.0f-in_color.get_r())+inverse_matrix[0][1]*(1.0f-in_color.get_g())+inverse_matrix[0][2]*(1.0f-in_color.get_b());
204                 chan[1]=inverse_matrix[1][0]*(1.0f-in_color.get_r())+inverse_matrix[1][1]*(1.0f-in_color.get_g())+inverse_matrix[1][2]*(1.0f-in_color.get_b());
205                 chan[2]=inverse_matrix[2][0]*(1.0f-in_color.get_r())+inverse_matrix[2][1]*(1.0f-in_color.get_g())+inverse_matrix[2][2]*(1.0f-in_color.get_b());
206
207                 halfcolor=Color::white();
208                 halfcolor-=(~color[0])*tone[0](point,chan[0],supersample);
209                 halfcolor-=(~color[1])*tone[1](point,chan[1],supersample);
210                 halfcolor-=(~color[2])*tone[2](point,chan[2],supersample);
211         
212                 halfcolor.set_a(in_color.get_a());
213         }
214         else
215         {
216                 chan[0]=inverse_matrix[0][0]*in_color.get_r()+inverse_matrix[0][1]*in_color.get_g()+inverse_matrix[0][2]*in_color.get_b();
217                 chan[1]=inverse_matrix[1][0]*in_color.get_r()+inverse_matrix[1][1]*in_color.get_g()+inverse_matrix[1][2]*in_color.get_b();
218                 chan[2]=inverse_matrix[2][0]*in_color.get_r()+inverse_matrix[2][1]*in_color.get_g()+inverse_matrix[2][2]*in_color.get_b();
219
220                 halfcolor=Color::black();
221                 halfcolor+=color[0]*tone[0](point,chan[0],supersample);
222                 halfcolor+=color[1]*tone[1](point,chan[1],supersample);
223                 halfcolor+=color[2]*tone[2](point,chan[2],supersample);
224         
225                 halfcolor.set_a(in_color.get_a());
226         }
227
228         return halfcolor;
229 }
230
231 inline float
232 Halftone3::calc_supersample(const synfig::Point &x, float pw,float ph)const
233 {
234         return abs(pw/(tone[0].size).mag());
235 }
236
237 synfig::Layer::Handle
238 Halftone3::hit_check(synfig::Context context, const synfig::Point &point)const
239 {
240         return const_cast<Halftone3*>(this);
241 }
242
243 bool
244 Halftone3::set_param(const String & param, const ValueBase &value)
245 {
246         IMPORT_PLUS(size, {tone[0].size=size; tone[1].size=size; tone[2].size=size;});
247         IMPORT_PLUS(type, {tone[0].type=type; tone[1].type=type; tone[2].type=type;});
248
249         IMPORT_PLUS(color[0],sync());
250         IMPORT_PLUS(color[1],sync());
251         IMPORT_PLUS(color[2],sync());
252         
253         IMPORT_PLUS(subtractive,sync());
254         
255         IMPORT(tone[0].angle);
256         IMPORT(tone[0].offset);
257
258         IMPORT(tone[1].angle);
259         IMPORT(tone[1].offset);
260
261         IMPORT(tone[2].angle);
262         IMPORT(tone[2].offset);
263         
264         return Layer_Composite::set_param(param,value); 
265 }
266
267 ValueBase
268 Halftone3::get_param(const String & param)const
269 {
270         EXPORT(size);
271         EXPORT(type);
272
273         EXPORT(color[0]);
274         EXPORT(color[1]);
275         EXPORT(color[2]);
276
277         EXPORT(subtractive);
278         
279         EXPORT(tone[0].angle);
280         EXPORT(tone[0].offset);
281
282         EXPORT(tone[1].angle);
283         EXPORT(tone[1].offset);
284
285         EXPORT(tone[2].angle);
286         EXPORT(tone[2].offset);
287
288         EXPORT_NAME();
289         EXPORT_VERSION();
290                 
291         return Layer_Composite::get_param(param);       
292 }
293
294 Layer::Vocab
295 Halftone3::get_param_vocab()const
296 {
297         Layer::Vocab ret(Layer_Composite::get_param_vocab());
298
299         ret.push_back(ParamDesc("size")
300                 .set_local_name(_("Mask Size"))
301         );
302         ret.push_back(ParamDesc("type")
303                 .set_local_name(_(" Type"))
304                 .set_hint("enum")
305                 .add_enum_value(TYPE_SYMMETRIC,"symmetric",_("Symmetric"))
306                 .add_enum_value(TYPE_LIGHTONDARK,"lightondark",_("Light On Dark"))
307                 //.add_enum_value(TYPE_DARKONLIGHT,"darkonlight",_("Dark on Light"))
308                 .add_enum_value(TYPE_DIAMOND,"diamond",_("Diamond"))
309                 .add_enum_value(TYPE_STRIPE,"stripe",_("Stripe"))
310         );
311         ret.push_back(ParamDesc("subtractive")
312                 .set_local_name(_("Subtractive Flag"))
313         );
314         
315         for(int i=0;i<3;i++)
316         {
317                 String chan_name(strprintf("Chan%d",i));
318                 
319                 ret.push_back(ParamDesc(strprintf("color[%d]",i))
320                         .set_local_name(chan_name+_(" Color"))
321                 );
322
323                 ret.push_back(ParamDesc(strprintf("tone[%d].offset",i))
324                         .set_local_name(chan_name+_(" Mask Offset"))
325                         .set_is_distance()
326                 );
327                 ret.push_back(ParamDesc(strprintf("tone[%d].angle",i))
328                         .set_local_name(chan_name+_(" Mask Angle"))
329                         .set_origin(strprintf("tone[%d].offset",i))
330                 );
331         }
332         
333         return ret;
334 }
335
336 Color
337 Halftone3::get_color(Context context, const Point &point)const
338 {
339         const Color undercolor(context.get_color(point));
340         const Color color(color_func(point,0,undercolor));
341
342         if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
343                 return color;
344         else
345                 return Color::blend(color,undercolor,get_amount(),get_blend_method());
346 }
347
348 bool
349 Halftone3::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
350 {
351         SuperCallback supercb(cb,0,9500,10000);
352
353         if(!context.accelerated_render(surface,quality,renddesc,&supercb))
354                 return false;
355         if(get_amount()==0)
356                 return true;
357                 
358         const Real pw(renddesc.get_pw()),ph(renddesc.get_ph());
359         const Point tl(renddesc.get_tl());
360         const int w(surface->get_w());
361         const int h(surface->get_h());
362         const float supersample_size(abs(pw/(tone[0].size).mag()));
363
364         Surface::pen pen(surface->begin());
365         Point pos;
366         int x,y;
367         
368         if(is_solid_color())
369         {
370                 for(y=0,pos[1]=tl[1];y<h;y++,pen.inc_y(),pen.dec_x(x),pos[1]+=ph)
371                         for(x=0,pos[0]=tl[0];x<w;x++,pen.inc_x(),pos[0]+=pw)
372                                 pen.put_value(
373                                         color_func(
374                                                 pos,
375                                                 supersample_size,
376                                                 pen.get_value()
377                                         )
378                                 );
379         }
380         else
381         {
382                 for(y=0,pos[1]=tl[1];y<h;y++,pen.inc_y(),pen.dec_x(x),pos[1]+=ph)
383                         for(x=0,pos[0]=tl[0];x<w;x++,pen.inc_x(),pos[0]+=pw)
384                                 pen.put_value(
385                                         Color::blend(
386                                                 color_func(
387                                                         pos,
388                                                         supersample_size,
389                                                         pen.get_value()
390                                                 ),
391                                                 pen.get_value(),
392                                                 get_amount(),
393                                                 get_blend_method()
394                                         )
395                                 );
396         }
397         
398         // Mark our progress as finished
399         if(cb && !cb->amount_complete(10000,10000))
400                 return false;
401
402         return true;
403 }