moreupdates
[synfig.git] / synfig-core / trunk / src / modules / example / metaballs.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file metaballs.cpp
3 **      \brief Implements metaballs
4 **
5 **      $Id: metaballs.cpp,v 1.1.1.1 2005/01/04 01:23:09 darco Exp $
6 **
7 **      \legal
8 **      Copyright (c) 2002 Robert B. Quattlebaum Jr.
9 **
10 **      This software and associated documentation
11 **      are CONFIDENTIAL and PROPRIETARY property of
12 **      the above-mentioned copyright holder.
13 **
14 **      You may not copy, print, publish, or in any
15 **      other way distribute this software without
16 **      a prior written agreement with
17 **      the copyright holder.
18 **      \endlegal
19 */
20 /* ========================================================================= */
21
22 /* === H E A D E R S ======================================================= */
23
24 #ifdef USING_PCH
25 #       include "pch.h"
26 #else
27 #ifdef HAVE_CONFIG_H
28 #       include <config.h>
29 #endif
30
31 #include <synfig/string.h>
32 #include <synfig/time.h>
33 #include <synfig/context.h>
34 #include <synfig/paramdesc.h>
35 #include <synfig/renddesc.h>
36 #include <synfig/surface.h>
37 #include <synfig/value.h>
38 #include <synfig/valuenode.h>
39 #include <ETL/pen>
40
41 #include "metaballs.h"
42
43 #endif
44
45 /* === U S I N G =========================================================== */
46
47 using namespace etl;
48 using namespace std;
49 using namespace synfig;
50
51 /* === G L O B A L S ======================================================= */
52
53 SYNFIG_LAYER_INIT(Metaballs);
54 SYNFIG_LAYER_SET_NAME(Metaballs,"metaballs");
55 SYNFIG_LAYER_SET_LOCAL_NAME(Metaballs,_("Metaballs"));
56 SYNFIG_LAYER_SET_CATEGORY(Metaballs,_("Default"));
57 SYNFIG_LAYER_SET_VERSION(Metaballs,"0.1");
58 SYNFIG_LAYER_SET_CVS_ID(Metaballs,"$Id: metaballs.cpp,v 1.1.1.1 2005/01/04 01:23:09 darco Exp $");
59
60 /* === P R O C E D U R E S ================================================= */
61
62 /* === M E T H O D S ======================================================= */
63
64 /* === E N T R Y P O I N T ================================================= */
65
66 Metaballs::Metaballs():
67         Layer_Composite(1.0,Color::BLEND_STRAIGHT),
68         color(Color::black())
69 {
70 }
71         
72 bool
73 Metaballs::set_param(const String & param, const ValueBase &value)
74 {
75         if(     param=="centers" && value.same_as(centers))
76         {
77                 centers = value;
78                 return true;
79         }
80         
81         if(     param=="weights" && value.same_as(weights))
82         {
83                 weights = value;
84                 return true;
85         }
86         
87         if(     param=="radii" && value.same_as(radii))
88         {
89                 radii = value;
90                 return true;
91         }
92         
93         IMPORT(color);
94         IMPORT(threshold);
95         
96         return Layer_Composite::set_param(param,value);
97 }
98
99 ValueBase
100 Metaballs::get_param(const String &param)const
101 {
102         EXPORT(color);
103         
104         EXPORT(radii);
105         EXPORT(weights);        
106         EXPORT(centers);
107         EXPORT(threshold);
108
109         EXPORT_NAME();
110         EXPORT_VERSION();
111                 
112         return Layer_Composite::get_param(param);       
113 }
114
115 Layer::Vocab
116 Metaballs::get_param_vocab()const
117 {
118         Layer::Vocab ret(Layer_Composite::get_param_vocab());
119         
120         ret.push_back(ParamDesc("color")
121                 .set_local_name(_("Color"))
122         );
123
124         ret.push_back(ParamDesc("centers")
125                 .set_local_name(_("Points"))
126         );
127         
128         ret.push_back(ParamDesc("radii")
129                 .set_local_name(_("Radii"))
130         );
131         
132         ret.push_back(ParamDesc("weights")
133                 .set_local_name(_("Weights"))
134         );
135         
136         ret.push_back(ParamDesc("threshold")
137                 .set_local_name(_("Threshold"))
138         );
139         
140         return ret;
141 }
142
143 static inline Real densityfunc(const synfig::Point &p, const synfig::Point &c, Real R)
144 {
145         const Real dx = p[0] - c[0];
146         const Real dy = p[1] - c[1];
147         
148         const Real n = (1 - (dx*dx + dy*dy)/(R*R));
149         return (n*n*n);
150
151         /*
152         f(d) = (1 - d^2)^3
153         f'(d) = -6d * (1 - d^2)^2
154         
155         could use this too...
156         f(d) = (1 - d^2)^2
157         f'(d) = -6d * (1 - d^2)
158         */
159 }
160
161 Real
162 Metaballs::totaldensity(const Point &pos) const
163 {
164         Real density = 0;
165         
166         //sum up weighted functions
167         for(unsigned int i=0;i<centers.size();i++)
168         {
169                 density += weights[i] * densityfunc(pos,centers[i], radii[i]);
170         }
171         
172         return density;
173 }
174
175 Color
176 Metaballs::get_color(Context context, const Point &pos)const
177 {
178         Real dens = totaldensity(pos);
179         
180         if(dens >= threshold) 
181                 return color;
182         else
183                 return context.get_color(pos);
184 }
185
186 bool
187 Metaballs::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
188 {       
189         // Width and Height of a pixel
190         const Point br(renddesc.get_br()), 
191                                 tl(renddesc.get_tl());
192         
193         const int       w = renddesc.get_w(), 
194                                 h = renddesc.get_h();
195         
196         Real    pw = renddesc.get_pw();
197         Real    ph = renddesc.get_ph();
198                 
199         SuperCallback supercb(cb,0,9000,10000);
200         
201         if(!context.accelerated_render(surface,quality,renddesc,&supercb))
202         {
203                 if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
204                 return false;
205         }
206                 
207         Point pos(tl[0],tl[1]);
208         
209         Real    dens;
210         
211         if(!context.accelerated_render(surface,quality,renddesc,&supercb))
212         {
213                 if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
214                 return false;
215         }
216         
217         for(int y = 0; y < h; y++, pos[1] += ph)
218         {
219                 pos[0] = tl[0];
220                 for(int x = 0; x < w; x++, pos[0] += pw)
221                 {
222                         dens = totaldensity(pos);
223                         
224                         if(dens >= threshold)
225                         {
226                                 (*surface)[y][x] = Color::blend(color,(*surface)[y][x],get_amount(),get_blend_method());
227                         }
228                 }               
229         }
230
231         // Mark our progress as finished
232         if(cb && !cb->amount_complete(10000,10000))
233                 return false;
234
235         return true;
236 }