462d30e2d583c1f853d8ab602dd0482060349ad4
[synfig.git] /
1 /* === S Y N F I G ========================================================= */
2 /*!     \file region.cpp
3 **      \brief Implementation of the "Region" layer
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **      Copyright (c) 2007, 2008 Chris Moore
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 ** === N O T E S ===========================================================
23 **
24 ** ========================================================================= */
25
26 /* === H E A D E R S ======================================================= */
27
28 #ifdef USING_PCH
29 #       include "pch.h"
30 #else
31 #ifdef HAVE_CONFIG_H
32 #       include <config.h>
33 #endif
34
35 #include "region.h"
36 #include <ETL/stringf>
37 #include <ETL/bezier>
38 #include <ETL/hermite>
39
40 #include <synfig/string.h>
41 #include <synfig/time.h>
42 #include <synfig/context.h>
43 #include <synfig/paramdesc.h>
44 #include <synfig/renddesc.h>
45 #include <synfig/surface.h>
46 #include <synfig/value.h>
47 #include <synfig/valuenode.h>
48 #include <synfig/segment.h>
49 #include <synfig/valuenode_bline.h>
50
51 #endif
52
53 using namespace etl;
54
55 /* === M A C R O S ========================================================= */
56
57 #define SAMPLES         75
58
59 /* === G L O B A L S ======================================================= */
60
61 SYNFIG_LAYER_INIT(Region);
62 SYNFIG_LAYER_SET_NAME(Region,"region");
63 SYNFIG_LAYER_SET_LOCAL_NAME(Region,N_("Region"));
64 SYNFIG_LAYER_SET_CATEGORY(Region,N_("Geometry"));
65 SYNFIG_LAYER_SET_VERSION(Region,"0.1");
66 SYNFIG_LAYER_SET_CVS_ID(Region,"$Id$");
67
68 /* === P R O C E D U R E S ================================================= */
69
70 /* === M E T H O D S ======================================================= */
71
72 /* === E N T R Y P O I N T ================================================= */
73
74 Region::Region()
75 {
76         clear();
77         vector<BLinePoint> bline_point_list;
78         bline_point_list.push_back(BLinePoint());
79         bline_point_list.push_back(BLinePoint());
80         bline_point_list.push_back(BLinePoint());
81         bline_point_list[0].set_vertex(Point(0,1));
82         bline_point_list[1].set_vertex(Point(0,-1));
83         bline_point_list[2].set_vertex(Point(1,0));
84         bline_point_list[0].set_tangent(bline_point_list[1].get_vertex()-bline_point_list[2].get_vertex()*0.5f);
85         bline_point_list[1].set_tangent(bline_point_list[2].get_vertex()-bline_point_list[0].get_vertex()*0.5f);
86         bline_point_list[2].set_tangent(bline_point_list[0].get_vertex()-bline_point_list[1].get_vertex()*0.5f);
87         bline_point_list[0].set_width(1.0f);
88         bline_point_list[1].set_width(1.0f);
89         bline_point_list[2].set_width(1.0f);
90         bline=bline_point_list;
91 }
92
93 void
94 Region::sync()
95 {
96         if(bline.get_contained_type()==ValueBase::TYPE_BLINEPOINT)
97                 segment_list=convert_bline_to_segment_list(bline);
98         else if(bline.get_contained_type()==ValueBase::TYPE_SEGMENT)
99                 segment_list=vector<synfig::Segment>(bline.get_list().begin(), bline.get_list().end());
100         else
101         {
102                 synfig::warning("Region: incorrect type on bline, layer disabled");
103                 clear();
104                 return;
105         }
106
107         if(segment_list.empty())
108         {
109                 synfig::warning("Region: segment_list is empty, layer disabled");
110                 clear();
111                 return;
112         }
113
114         bool looped = bline.get_loop();
115
116         Vector::value_type n;
117         etl::hermite<Vector> curve;
118         vector<Point> vector_list;
119
120         vector<Segment>::const_iterator iter=segment_list.begin();
121         //Vector                                                        last = iter->p1;
122
123         //make sure the shape has a clean slate for writing
124         //clear();
125
126         //and start off at the first point
127         //move_to(last[0],last[1]);
128
129         for(;iter!=segment_list.end();++iter)
130         {
131                 //connect them with a line if they aren't already joined
132                 /*if(iter->p1 != last)
133                 {
134                         line_to(iter->p1[0],iter->p1[1]);
135                 }
136
137                 //curve to the next end point
138                 curve_to(iter->p1[0] + iter->t1[0]/3.0,iter->p1[1] + iter->t1[1]/3.0,
139                                  iter->p2[0] - iter->t2[0]/3.0,iter->p2[1] - iter->t2[1]/3.0,
140                                  iter->p2[0],iter->p2[1]);
141
142                 last = iter->p2;*/
143
144                 if(iter->t1.is_equal_to(Vector(0,0)) && iter->t2.is_equal_to(Vector(0,0)))
145                 {
146                         vector_list.push_back(iter->p2);
147                 }
148                 else
149                 {
150                         curve.p1()=iter->p1;
151                         curve.t1()=iter->t1;
152                         curve.p2()=iter->p2;
153                         curve.t2()=iter->t2;
154                         curve.sync();
155
156                         for(n=0.0;n<1.0;n+=1.0/SAMPLES)
157                                 vector_list.push_back(curve(n));
158                 }
159         }
160
161         //add the starting point onto the end so it actually fits the shape, so we can be extra awesome...
162         if(!looped)
163                 vector_list.push_back(segment_list[0].p1);
164
165         clear();
166         add_polygon(vector_list);
167
168         /*close();
169         endpath();*/
170 }
171
172 bool
173 Region::set_param(const String & param, const ValueBase &value)
174 {
175         if(param=="segment_list")
176         {
177                 if(dynamic_param_list().count("segment_list"))
178                 {
179                         connect_dynamic_param("bline",dynamic_param_list().find("segment_list")->second);
180                         disconnect_dynamic_param("segment_list");
181                         synfig::warning("Region::set_param(): Updated valuenode connection to use the new \"bline\" parameter.");
182                 }
183                 else
184                         synfig::warning("Region::set_param(): The parameter \"segment_list\" is deprecated. Use \"bline\" instead.");
185         }
186
187         if(     (param=="segment_list" || param=="bline") && value.get_type()==ValueBase::TYPE_LIST)
188         {
189                 //if(value.get_contained_type()!=ValueBase::TYPE_BLINEPOINT)
190                 //      return false;
191
192                 bline=value;
193
194                 return true;
195         }
196
197 /*      if(     param=="segment_list" && value.get_type()==ValueBase::TYPE_LIST)
198         {
199                 if(value.get_contained_type()==ValueBase::TYPE_BLINEPOINT)
200                         segment_list=convert_bline_to_segment_list(value);
201                 else
202                 if(value.get_contained_type()==ValueBase::TYPE_SEGMENT)
203                         segment_list=value;
204                 else
205                 if(value.empty())
206                         segment_list.clear();
207                 else
208                         return false;
209                 sync();
210                 return true;
211         }
212         */
213         return Layer_Shape::set_param(param,value);
214 }
215
216 ValueBase
217 Region::get_param(const String& param)const
218 {
219         EXPORT(bline);
220         EXPORT_NAME();
221         EXPORT_VERSION();
222
223         return Layer_Shape::get_param(param);
224 }
225
226 Layer::Vocab
227 Region::get_param_vocab()const
228 {
229         Layer::Vocab ret(Layer_Shape::get_param_vocab());
230
231         ret.push_back(ParamDesc("bline")
232                 .set_local_name(_("Vertices"))
233                 .set_origin("origin")
234         );
235
236         return ret;
237 }
238
239 void
240 Region::set_time(Context context, Time time)const
241 {
242         const_cast<Region*>(this)->sync();
243         context.set_time(time);
244 }
245
246 void
247 Region::set_time(Context context, Time time, Vector pos)const
248 {
249         const_cast<Region*>(this)->sync();
250         context.set_time(time,pos);
251 }