1 /* === S Y N F I G ========================================================= */
2 /*! \file synfig/renddesc.cpp
3 ** \brief Class that defines the parameters needed by the Renderer to
4 * render a context to a surface.
5 **
6 ** $Id$
7 **
8 ** \legal
9 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
10 ** Copyright (c) 2008 Chris Moore
11 **
12 ** This package is free software; you can redistribute it and/or
13 ** modify it under the terms of the GNU General Public License as
14 ** published by the Free Software Foundation; either version 2 of
15 ** the License, or (at your option) any later version.
16 **
17 ** This package is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ** General Public License for more details.
21 ** \endlegal
22 */
23 /* ========================================================================= */
24
25 /* === H E A D E R S ======================================================= */
26
27 #ifdef USING_PCH
28 # include "pch.h"
29 #else
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33
34 #include "renddesc.h"
35 #include <ETL/misc>
36
37 #endif
38
39 /* === U S I N G =========================================================== */
40
41 using namespace std;
42 using namespace etl;
43 using namespace synfig;
44
45 /* === M A C R O S ========================================================= */
46
47 #undef FLAGS
48 #define FLAGS(x,y) (((x)&(y))==(y))
49
50 /* === G L O B A L S ======================================================= */
51
52 /* === M E T H O D S ======================================================= */
53
54 RendDesc &
apply(const RendDesc & x)55 RendDesc::apply(const RendDesc &x)
56 {
57 operator=(x);
58 return *this;
59 }
60
61 const Color &
get_bg_color() const62 RendDesc::get_bg_color()const
63 {
64 return background;
65 }
66
67 RendDesc &
set_bg_color(const Color & bg)68 RendDesc::set_bg_color(const Color &bg)
69 {
70 background=bg; return *this;
71 }
72
73 Real
get_physical_w() const74 RendDesc::get_physical_w()const
75 {
76 return (Real)get_w()/get_x_res();
77 }
78
79 Real
get_physical_h() const80 RendDesc::get_physical_h()const
81 {
82 return (Real)get_h()/get_y_res();
83 }
84
85 RendDesc&
set_physical_w(Real w)86 RendDesc::set_physical_w(Real w)
87 {
88 set_w(round_to_int(w*get_x_res()));
89 return *this;
90 }
91
92 RendDesc&
set_physical_h(Real h)93 RendDesc::set_physical_h(Real h)
94 {
95 set_h(round_to_int(h*get_y_res()));
96 return *this;
97 }
98
99 int
get_w() const100 RendDesc::get_w()const
101 {
102 return w_;
103 }
104
105 RendDesc &
set_w(int x)106 RendDesc::set_w(int x)
107 {
108 if(FLAGS(flags,LINK_IM_ASPECT)) // "Width and Height ratio"
109 {
110 double new_h = h_ratio_*x/w_ratio_;
111 if(FLAGS(flags,PX_ASPECT))
112 {
113 br_[1]-=focus[1];
114 br_[1]=br_[1]/h_*new_h;
115 br_[1]+=focus[1];
116 tl_[1]-=focus[1];
117 tl_[1]=tl_[1]/h_*new_h;
118 tl_[1]+=focus[1];
119
120 br_[0]-=focus[0];
121 br_[0]=br_[0]/w_*x;
122 br_[0]+=focus[0];
123 tl_[0]-=focus[0];
124 tl_[0]=tl_[0]/w_*x;
125 tl_[0]+=focus[0];
126 }
127 h_=new_h;
128 w_=x;
129
130 return *this;
131 }
132
133 if(FLAGS(flags,LINK_PX_ASPECT)) // never set
134 {
135 h_=h_*x/w_;
136 w_=x;
137 }
138 else if(FLAGS(flags,LINK_PX_AREA)) // never set
139 {
140 //! \writeme
141 w_=x;
142 }
143 else if(FLAGS(flags,PX_ASPECT)) // "Pixel Aspect"
144 {
145 Vector d=br_-tl_;
146 float old_span=get_span();
147
148 // If we should preserve image width
149 if( FLAGS(flags,IM_W) // "Image Width"
150 || (FLAGS(flags,IM_ZOOMIN) && d[1]>d[1]/x*w_) // never set
151 || (FLAGS(flags,IM_ZOOMOUT) && d[1]<d[1]/x*w_)) // never set
152 {
153 br_[1]-=focus[1];
154 br_[1]=br_[1]/x*w_;
155 br_[1]+=focus[1];
156 tl_[1]-=focus[1];
157 tl_[1]=tl_[1]/x*w_;
158 tl_[1]+=focus[1];
159 } else
160 {
161 br_[0]-=focus[0];
162 br_[0]=br_[0]/w_*x;
163 br_[0]+=focus[0];
164 tl_[0]-=focus[0];
165 tl_[0]=tl_[0]/w_*x;
166 tl_[0]+=focus[0];
167 }
168
169 w_=x;
170
171 if(FLAGS(flags,IM_SPAN)) // "Image Span"
172 set_span(old_span);
173 }
174 else if(FLAGS(flags,PX_AREA)) // never set
175 {
176 //! \writeme
177 w_=x;
178 }
179 else
180 w_=x;
181
182 return *this;
183 }
184
185 int
get_h() const186 RendDesc::get_h()const
187 {
188 return h_;
189 }
190
191 RendDesc &
set_h(int y)192 RendDesc::set_h(int y)
193 {
194 if(FLAGS(flags,LINK_IM_ASPECT)) // "Width and Height ratio"
195 {
196 double new_w = w_ratio_*y/h_ratio_;
197 if(FLAGS(flags,PX_ASPECT))
198 {
199 br_[0]-=focus[0];
200 br_[0]=br_[0]/w_*new_w;
201 br_[0]+=focus[0];
202 tl_[0]-=focus[0];
203 tl_[0]=tl_[0]/w_*new_w;
204 tl_[0]+=focus[0];
205
206 br_[1]-=focus[1];
207 br_[1]=br_[1]/h_*y;
208 br_[1]+=focus[1];
209 tl_[1]-=focus[1];
210 tl_[1]=tl_[1]/h_*y;
211 tl_[1]+=focus[1];
212 }
213 w_=new_w;
214 h_=y;
215
216 return *this;
217 }
218
219 if(FLAGS(flags,LINK_PX_ASPECT)) // never set
220 {
221 w_=w_*y/h_;
222 h_=y;
223 }
224 else if(FLAGS(flags,LINK_PX_AREA)) // never set
225 {
226 //! \writeme
227 h_=y;
228 }
229 else if(FLAGS(flags,PX_ASPECT)) // "Pixel Aspect"
230 {
231 Vector d=br_-tl_;
232 float old_span=get_span();
233
234 // If we should preserve image width
235 if( FLAGS(flags,IM_W) // "Image Width"
236 || (FLAGS(flags,IM_ZOOMIN) && d[0]>d[0]/y*h_) // never set
237 || (FLAGS(flags,IM_ZOOMOUT) && d[0]<d[0]/y*h_)) // never set
238 {
239 br_[0]-=focus[0];
240 br_[0]=br_[0]/y*h_;
241 br_[0]+=focus[0];
242 tl_[0]-=focus[0];
243 tl_[0]=tl_[0]/y*h_;
244 tl_[0]+=focus[0];
245 } else
246 {
247 br_[1]-=focus[1];
248 br_[1]=br_[1]/h_*y;
249 br_[1]+=focus[1];
250 tl_[1]-=focus[1];
251 tl_[1]=tl_[1]/h_*y;
252 tl_[1]+=focus[1];
253 }
254
255 h_=y;
256
257 if(FLAGS(flags,IM_SPAN)) // "Image Span"
258 set_span(old_span);
259 }
260 else if(FLAGS(flags,PX_AREA)) // never set
261 {
262 //! \writeme
263 h_=y;
264 }
265 else
266 h_=y;
267
268 return *this;
269 }
270
271 RendDesc &
set_wh(int x,int y)272 RendDesc::set_wh(int x, int y)
273 {
274 // FIXME: This is a working hack...
275 set_w(x);
276 set_h(y);
277
278 return *this;
279 }
280
281 Real
get_x_res() const282 RendDesc::get_x_res()const
283 {
284 return x_res;
285 }
286
287 RendDesc &
set_x_res(Real x)288 RendDesc::set_x_res(Real x)
289 {
290 if(FLAGS(flags,LINK_RES)) // "Resolution ratio"
291 {
292 y_res = y_res_ratio_*x/x_res_ratio_;
293 }
294
295 x_res=x; return *this;
296 }
297
298 Real
get_y_res() const299 RendDesc::get_y_res()const
300 {
301 return y_res;
302 }
303
304 RendDesc &
set_y_res(Real y)305 RendDesc::set_y_res(Real y)
306 {
307 if(FLAGS(flags,LINK_RES)) // "Resolution ratio"
308 {
309 x_res = x_res_ratio_*y/y_res_ratio_;
310 }
311
312 y_res=y; return *this;
313 }
314
315 int
get_frame_start() const316 RendDesc::get_frame_start()const
317 {
318 return round_to_int(time_begin*frame_rate);
319 }
320
321 RendDesc &
set_frame_start(int x)322 RendDesc::set_frame_start(int x)
323 {
324 return set_time_start(Time(x)/frame_rate);
325 }
326
327 int
get_frame_end() const328 RendDesc::get_frame_end()const
329 {
330 return round_to_int(time_end*frame_rate);
331 }
332
333 RendDesc &
set_frame_end(int x)334 RendDesc::set_frame_end(int x)
335 {
336 return set_time_end(Time(x)/frame_rate);
337 }
338
339
340 const Time
get_time_start() const341 RendDesc::get_time_start()const
342 {
343 return time_begin;
344 }
345
346 RendDesc &
set_time_start(Time x)347 RendDesc::set_time_start(Time x)
348 {
349 if(x>time_end)
350 time_begin=time_end=x;
351 else
352 time_begin=x;
353 return *this;
354 }
355
356
357 const Time
get_time_end() const358 RendDesc::get_time_end()const
359 {
360 return time_end;
361 }
362
363 RendDesc &
set_time_end(Time x)364 RendDesc::set_time_end(Time x)
365 {
366 if(x<time_begin)
367 time_end=time_begin=x;
368 else
369 time_end=x;
370 return *this;
371 }
372
373 RendDesc &
set_time(Time x)374 RendDesc::set_time(Time x)
375 {
376 time_end=time_begin=x;
377 return *this;
378 }
379
380 RendDesc &
set_frame(int x)381 RendDesc::set_frame(int x)
382 {
383 return set_time(Time(x)/frame_rate);
384 }
385
386 const float &
get_frame_rate() const387 RendDesc::get_frame_rate()const
388 {
389 return frame_rate;
390 }
391
392 RendDesc &
set_frame_rate(float x)393 RendDesc::set_frame_rate(float x)
394 {
395 frame_rate=x;
396 return *this;
397 }
398
399 const bool &
get_interlaced() const400 RendDesc::get_interlaced()const
401 {
402 return interlaced;
403 }
404
405 RendDesc &
set_interlaced(bool x)406 RendDesc::set_interlaced(bool x)
407 { interlaced=x; return *this; }
408
409 //! Return the status of the clamp flag
410 const bool &
get_clamp() const411 RendDesc::get_clamp()const
412 { return clamp; }
413
414 //! Set the clamp flag
415 RendDesc &
set_clamp(bool x)416 RendDesc::set_clamp(bool x)
417 { clamp=x; return *this; }
418
419 //! Return the status of the render_excluded_contexts flag
420 const bool &
get_render_excluded_contexts() const421 RendDesc::get_render_excluded_contexts()const
422 { return render_excluded_contexts; }
423
424 //! Set the render_excluded_contexts flag
425 RendDesc &
set_render_excluded_contexts(bool x)426 RendDesc::set_render_excluded_contexts(bool x)
427 { render_excluded_contexts=x; return *this; }
428
429 //! Set constraint flags
430 RendDesc &
set_flags(const int & x)431 RendDesc::set_flags(const int &x)
432 { flags=x; return *this; }
433
434 //! Clear constraint flags
435 RendDesc &
clear_flags()436 RendDesc::clear_flags()
437 { flags=0; return *this; }
438
439 int
get_flags() const440 RendDesc::get_flags()const
441 { return flags; }
442
443
444 //! Return the aspect ratio of a single pixel
445 Real
get_pixel_aspect() const446 RendDesc::get_pixel_aspect()const
447 {
448 Vector tmp=br_-tl_;
449 tmp[0]/=w_;
450 tmp[1]/=h_;
451 tmp[0]/=tmp[1];
452 if(tmp[0]<0.0)
453 return -tmp[0];
454 return tmp[0];
455 }
456
457 //! Return the aspect ratio of the entire image
458 Real
get_image_aspect() const459 RendDesc::get_image_aspect()const
460 {
461 Point tmp=br_-tl_;
462 tmp[0]/=tmp[1];
463 if(tmp[0]<0.0)
464 return -tmp[0];
465 return tmp[0];
466 }
467
468
469 //! Affect the pixel ratio for LINK_IM_ASPECT flag
470 void
set_pixel_ratio(const int & x,const int & y)471 RendDesc::set_pixel_ratio(const int &x, const int &y)
472 {
473 w_ratio_ = x;
474 h_ratio_ = y;
475 }
476
477 //! Get the reduced pixel ratio (based on euclide reduction)
478 void
get_pixel_ratio_reduced(int & w_ratio_reduced,int & h_ratio_reduced)479 RendDesc::get_pixel_ratio_reduced(int &w_ratio_reduced, int &h_ratio_reduced)
480 {
481 int w = w_;
482 int h = h_;
483 int last_rem = h_;
484 int bigger_commun_div;
485
486 div_t dv;
487
488 if(!w_ || !h_)
489 {
490 w_ratio_reduced = h_ratio_reduced = 0;
491 return;
492 }
493
494 if(w_ == h_)
495 {
496 w_ratio_reduced = h_ratio_reduced = 1;
497 return;
498 }
499
500 while (last_rem != 0)
501 {
502 dv = div(w, h);
503 w = h;
504 bigger_commun_div = last_rem;
505 last_rem = h = dv.rem;
506 }
507
508 w_ratio_reduced = w_ / bigger_commun_div;
509 h_ratio_reduced = h_ / bigger_commun_div;
510 }
511
512 //! Affect the resolution ratio for LINK_RES flag
513 void
set_res_ratio(const Real & x,const Real & y)514 RendDesc::set_res_ratio(const Real &x, const Real &y)
515 {
516 x_res_ratio_ = x;
517 y_res_ratio_ = y;
518 }
519
520 //! Return the antialias amount
521 const int &
get_antialias() const522 RendDesc::get_antialias()const
523 { return a; }
524
525 //! Set the antialias amount
526 RendDesc &
set_antialias(const int & x)527 RendDesc::set_antialias(const int &x)
528 { a=x; return *this; }
529
530
531 //! Return the distance from the bottom-right to the top-left
532 Real
get_span() const533 RendDesc::get_span()const
534 {
535 return (br_-tl_).mag();
536 }
537
538 //! Set the span distance
539 RendDesc &
set_span(const Real & x)540 RendDesc::set_span(const Real &x)
541 {
542 Vector::value_type ratio=x/get_span();
543
544 //! \todo this looks wrong. I suspect the intention was to check
545 // "(not IM_W) AND (not IM_H)", ie "not(IM_W OR IM_H)" but
546 // this check does "not(IM_W AND IM_H)"
547 if(!FLAGS(flags,IM_W|IM_H) || FLAGS(flags,IM_ASPECT)) // (not "Image Width") or (not "Image Height") or "Image Aspect"
548 {
549 br_-=focus;
550 br_=br_*ratio;
551 br_+=focus;
552 tl_-=focus;
553 tl_=tl_*ratio;
554 tl_+=focus;
555 }
556 else if(FLAGS(flags,IM_W)) // "Image Width"
557 {
558 //! \writeme or fix me
559 br_-=focus;
560 br_=br_*ratio;
561 br_+=focus;
562 tl_-=focus;
563 tl_=tl_*ratio;
564 tl_+=focus;
565 }else // IM_H // "Image Height"
566 {
567 //! \writeme or fix me
568 br_-=focus;
569 br_=br_*ratio;
570 br_+=focus;
571 tl_-=focus;
572 tl_=tl_*ratio;
573 tl_+=focus;
574 }
575
576 return *this;
577 }
578
579
580 const Point &
get_focus() const581 RendDesc::get_focus()const
582 { return focus; }
583
584 RendDesc &
set_focus(const Point & x)585 RendDesc::set_focus(const Point &x)
586 { focus=x; return *this; }
587
588
589 const Point &
get_tl() const590 RendDesc::get_tl()const
591 { return tl_; }
592
593 const Point &
get_br() const594 RendDesc::get_br()const
595 { return br_; }
596
597 RendDesc &
set_tl(const Point & x)598 RendDesc::set_tl(const Point &x)
599 {
600 if(FLAGS(flags,PX_ASPECT)) // "Pixel Aspect"
601 {
602 Vector new_size(x-br_);
603 new_size[0]=abs(new_size[0]);
604 new_size[1]=abs(new_size[1]);
605
606 Vector old_size(tl_-br_);
607 old_size[0]=abs(old_size[0]);
608 old_size[1]=abs(old_size[1]);
609
610 if(new_size[0]!=old_size[0])
611 w_=round_to_int(new_size[0]*w_/old_size[0]);
612
613 if(new_size[1]!=old_size[1])
614 h_=round_to_int(new_size[1]*h_/old_size[1]);
615 }
616
617 tl_=x; return *this;
618 }
619
620 RendDesc &
set_br(const Point & x)621 RendDesc::set_br(const Point &x)
622 {
623 if(FLAGS(flags,PX_ASPECT)) // "Pixel Aspect"
624 {
625 Vector new_size(x-tl_);
626 new_size[0]=abs(new_size[0]);
627 new_size[1]=abs(new_size[1]);
628
629 Vector old_size(tl_-br_);
630 old_size[0]=abs(old_size[0]);
631 old_size[1]=abs(old_size[1]);
632
633 if(new_size[0]!=old_size[0])
634 w_=round_to_int(new_size[0]*w_/old_size[0]);
635
636 if(new_size[1]!=old_size[1])
637 h_=round_to_int(new_size[1]*h_/old_size[1]);
638 }
639 br_=x; return *this;
640 }
641
642 RendDesc &
set_tl_br(const Point & x,const Point & y)643 RendDesc::set_tl_br(const Point &x, const Point &y)
644 {
645 if(FLAGS(flags, PX_ASPECT))
646 {
647 Vector new_size(y-x);
648 new_size[0]=abs(new_size[0]);
649 new_size[1]=abs(new_size[1]);
650
651 Vector old_size(tl_-br_);
652 old_size[0]=abs(old_size[0]);
653 old_size[1]=abs(old_size[1]);
654
655 if(new_size[0]!=old_size[0])
656 w_=round_to_int(new_size[0]*w_/old_size[0]);
657
658 if(new_size[1]!=old_size[1])
659 h_=round_to_int(new_size[1]*h_/old_size[1]);
660 }
661 tl_=x;
662 br_=y;
663 return *this;
664 }
665
666
667 RendDesc &
set_viewport(const Point & __tl,const Point & __br)668 RendDesc::set_viewport(const Point &__tl, const Point &__br)
669 { tl_=__tl; br_=__br; return *this; }
670
671 RendDesc &
set_viewport(Vector::value_type a,Vector::value_type b,Vector::value_type c,Vector::value_type d)672 RendDesc::set_viewport(Vector::value_type a, Vector::value_type b, Vector::value_type c, Vector::value_type d)
673 { tl_=Point(a,b); br_=Point(c,d); return *this; }
674
675 Real
get_pw() const676 RendDesc::get_pw()const
677 {
678 return (br_[0] - tl_[0]) / w_;
679 }
680
681 Real
get_ph() const682 RendDesc::get_ph()const
683 {
684 return (br_[1] - tl_[1]) / h_;
685 }
686
687 RendDesc &
set_subwindow(int x,int y,int w,int h)688 RendDesc::set_subwindow(int x, int y, int w, int h)
689 {
690 const Real pw(get_pw());
691 const Real ph(get_ph());
692
693 tl_[0]+=pw*x;
694 tl_[1]+=ph*y;
695
696 br_[0]-=pw*(w_-(x+w));
697 br_[1]-=ph*(h_-(y+h));
698
699 w_=w;
700 h_=h;
701
702 return *this;
703 }
704
705 RendDesc &
set_duration(Time duration)706 RendDesc::set_duration(Time duration)
707 {
708 if(get_frame_rate())
709 {
710 if(duration > Time(0.0))
711 set_time_end(get_time_start() + duration - Time(1/get_frame_rate()));
712 else
713 set_time_end(get_time_start());
714 }
715
716 return *this;
717 }
718
719 const Time
get_duration()720 RendDesc::get_duration()
721 {
722 if(get_frame_rate())
723 return (get_time_end() - get_time_start() + Time(1/get_frame_rate()));
724 return Time(0.0);
725 }
726