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