1 /* === S Y N F I G ========================================================= */
2 /*! \file target_scanline.cpp
3 ** \brief Template File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2008 Chris Moore
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.
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.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
33 #include "target_scanline.h"
42 /* === U S I N G =========================================================== */
46 using namespace synfig;
48 /* === M A C R O S ========================================================= */
50 // note that if this isn't defined then the rendering is incorrect for
51 // the straight blend method since the optimize_layers() function in
52 // canvas.cpp which makes the straight blend method work correctly
53 // isn't called. ie. leave this defined. to see the problem, draw a
54 // small circle over a solid background. set circle to amount 0.99
55 // and blend method 'straight'. the background should vanish but doesn't
56 #define SYNFIG_OPTIMIZE_LAYER_TREE
58 #define PIXEL_RENDERING_LIMIT 1500000
60 #define USE_PIXELRENDERING_LIMIT 1
62 /* === G L O B A L S ======================================================= */
64 /* === P R O C E D U R E S ================================================= */
66 /* === M E T H O D S ======================================================= */
68 Target_Scanline::Target_Scanline():
75 Target_Scanline::next_frame(Time& time)
85 // If the description's end frame is equal to
86 // the start frame, then it is assumed that we
87 // are rendering only one frame. Correct it.
88 if(desc.get_frame_end()==desc.get_frame_start())
89 desc.set_frame_end(desc.get_frame_start()+1);
91 frame_start=desc.get_frame_start();
92 frame_end=desc.get_frame_end();
93 time_start=desc.get_time_start();
94 time_end=desc.get_time_end();
96 // Calculate the number of frames
97 total_frames=frame_end-frame_start;
98 if(total_frames<=0)total_frames=1;
100 //RendDesc rend_desc=desc;
101 //rend_desc.set_gamma(1);
103 // int total_tiles(total_tiles());
104 time=(time_end-time_start)*curr_frame_/total_frames+time_start;
107 /* synfig::info("curr_frame_: %d",curr_frame_);
108 synfig::info("total_frames: %d",total_frames);
109 synfig::info("time_end: %s",time_end.get_string().c_str());
110 synfig::info("time_start: %s",time_start.get_string().c_str());
112 // synfig::info("time: %s",time.get_string().c_str());
114 return total_frames- curr_frame_+1;
117 synfig::Target_Scanline::render(ProgressCallback *cb)
119 SuperCallback super_cb;
123 quality=get_quality(),
135 if(cb) cb->error(_("Target initialization failure"));
139 // If the description's end frame is equal to
140 // the start frame, then it is assumed that we
141 // are rendering only one frame. Correct it.
142 if(desc.get_frame_end()==desc.get_frame_start())
143 desc.set_frame_end(desc.get_frame_start()+1);
145 frame_start=desc.get_frame_start();
146 frame_end=desc.get_frame_end();
147 time_start=desc.get_time_start();
148 time_end=desc.get_time_end();
150 // Calculate the number of frames
151 total_frames=frame_end-frame_start;
154 //RendDesc rend_desc=desc;
160 //synfig::info("1time_set_to %s",t.get_string().c_str());
166 //for(i=0,t=time_start;i<total_frames;i++)
168 //t=((time_end-time_start)*((Real)i/(Real)total_frames)).round(desc.get_frame_rate())+time_start;
170 // If we have a callback, and it returns
171 // false, go ahead and bail. (it may be a user cancel)
172 if(cb && !cb->amount_complete(total_frames-(i-1),total_frames))
175 // Set the time that we wish to render
176 if(!get_avoid_time_sync() || canvas->get_time()!=t)
181 #ifdef SYNFIG_OPTIMIZE_LAYER_TREE
182 Canvas::Handle op_canvas;
183 if (!getenv("SYNFIG_DISABLE_OPTIMIZE_LAYER_TREE"))
185 op_canvas = Canvas::create();
186 op_canvas->set_file_name(canvas->get_file_name());
187 optimize_layers(canvas->get_time(), canvas->get_context(), op_canvas);
188 context=op_canvas->get_context();
191 context=canvas->get_context();
193 context=canvas->get_context();
196 // If the quality is set to zero, then we
197 // use the parametric scanline-renderer.
202 if(!synfig::render(context,this,desc,0))
207 if(!synfig::render_threaded(context,this,desc,0,threads_))
211 else // If quality is set otherwise, then we use the accelerated renderer
213 #if USE_PIXELRENDERING_LIMIT
214 if(desc.get_w()*desc.get_h() > PIXEL_RENDERING_LIMIT)
217 int rowheight = PIXEL_RENDERING_LIMIT/desc.get_w();
218 if (!rowheight) rowheight = 1; // TODO: render partial lines to stay within the limit?
219 int rows = desc.get_h()/rowheight;
220 int lastrowheight = desc.get_h() - rows*rowheight;
224 synfig::info("Render broken up into %d block%s %d pixels tall, and a final block %d pixels tall",
225 rows-1, rows==2?"":"s", rowheight, lastrowheight);
227 // loop through all the full rows
230 throw(string("add_frame(): target panic on start_frame()"));
234 for(int i=0; i < rows; ++i)
236 RendDesc blockrd = desc;
238 //render the strip at the normal size unless it's the last one...
241 if(!lastrowheight) break;
242 blockrd.set_subwindow(0,i*rowheight,desc.get_w(),lastrowheight);
246 blockrd.set_subwindow(0,i*rowheight,desc.get_w(),rowheight);
249 if(!context.accelerated_render(&surface,quality,blockrd,0))
251 if(cb)cb->error(_("Accelerated Renderer Failure"));
256 int rowspan=sizeof(Color)*surface.get_w();
257 Surface::pen pen = surface.begin();
259 int yoff = i*rowheight;
261 for(y = 0; y < blockrd.get_h(); y++, pen.inc_y())
263 Color *colordata= start_scanline(y + yoff);
266 throw(string("add_frame(): call to start_scanline(y) returned NULL"));
270 if(get_remove_alpha())
272 for(int i = 0; i < surface.get_w(); i++)
273 colordata[i] = Color::blend(surface[y][i],desc.get_bg_color(),1.0f);
276 memcpy(colordata,surface[y],rowspan);
280 throw(string("add_frame(): target panic on end_scanline()"));
289 }else //use normal rendering...
294 if(!context.accelerated_render(&surface,quality,desc,0))
296 // For some reason, the accelerated renderer failed.
297 if(cb)cb->error(_("Accelerated Renderer Failure"));
302 // Put the surface we renderer
304 if(!add_frame(&surface))
306 if(cb)cb->error(_("Unable to put surface on target"));
310 #if USE_PIXELRENDERING_LIMIT
314 }while((i=next_frame(t)));
317 // Set the time that we wish to render
318 if(!get_avoid_time_sync() || canvas->get_time()!=t)
322 #ifdef SYNFIG_OPTIMIZE_LAYER_TREE
323 Canvas::Handle op_canvas;
324 if (!getenv("SYNFIG_DISABLE_OPTIMIZE_LAYER_TREE"))
326 op_canvas = Canvas::create();
327 op_canvas->set_file_name(canvas->get_file_name());
328 optimize_layers(canvas->get_time(), canvas->get_context(), op_canvas);
329 context=op_canvas->get_context();
332 context=canvas->get_context();
334 context=canvas->get_context();
337 // If the quality is set to zero, then we
338 // use the parametric scanline-renderer.
343 if(!synfig::render(context,this,desc,cb))
348 if(!synfig::render_threaded(context,this,desc,cb,threads_))
352 else // If quality is set otherwise, then we use the accelerated renderer
354 #if USE_PIXELRENDERING_LIMIT
355 if(desc.get_w()*desc.get_h() > PIXEL_RENDERING_LIMIT)
358 int totalheight = desc.get_h();
359 int rowheight = PIXEL_RENDERING_LIMIT/desc.get_w();
360 if (!rowheight) rowheight = 1; // TODO: render partial lines to stay within the limit?
361 int rows = desc.get_h()/rowheight;
362 int lastrowheight = desc.get_h() - rows*rowheight;
366 synfig::info("Render broken up into %d block%s %d pixels tall, and a final block %d pixels tall",
367 rows-1, rows==2?"":"s", rowheight, lastrowheight);
369 // loop through all the full rows
372 throw(string("add_frame(): target panic on start_frame()"));
376 for(int i=0; i < rows; ++i)
378 RendDesc blockrd = desc;
380 //render the strip at the normal size unless it's the last one...
383 if(!lastrowheight) break;
384 blockrd.set_subwindow(0,i*rowheight,desc.get_w(),lastrowheight);
388 blockrd.set_subwindow(0,i*rowheight,desc.get_w(),rowheight);
391 SuperCallback sc(cb, i*rowheight, (i+1)*rowheight, totalheight);
393 if(!context.accelerated_render(&surface,quality,blockrd,&sc))
395 if(cb)cb->error(_("Accelerated Renderer Failure"));
400 int rowspan=sizeof(Color)*surface.get_w();
401 Surface::pen pen = surface.begin();
403 int yoff = i*rowheight;
405 for(y = 0; y < blockrd.get_h(); y++, pen.inc_y())
407 Color *colordata= start_scanline(y + yoff);
410 throw(string("add_frame(): call to start_scanline(y) returned NULL"));
414 if(get_remove_alpha())
416 for(int i = 0; i < surface.get_w(); i++)
417 colordata[i] = Color::blend(surface[y][i],desc.get_bg_color(),1.0f);
420 memcpy(colordata,surface[y],rowspan);
424 throw(string("add_frame(): target panic on end_scanline()"));
430 //I'm done with this part
431 sc.amount_complete(100,100);
441 if(!context.accelerated_render(&surface,quality,desc,cb))
443 if(cb)cb->error(_("Accelerated Renderer Failure"));
448 // Put the surface we renderer
450 if(!add_frame(&surface))
452 if(cb)cb->error(_("Unable to put surface on target"));
456 #if USE_PIXELRENDERING_LIMIT
465 if(cb)cb->error(_("Caught string :")+str);
468 catch(std::bad_alloc)
470 if(cb)cb->error(_("Ran out of memory (Probably a bug)"));
475 if(cb)cb->error(_("Caught unknown error, rethrowing..."));
482 Target_Scanline::add_frame(const Surface *surface)
488 int rowspan=sizeof(Color)*surface->get_w();
489 Surface::const_pen pen=surface->begin();
493 throw(string("add_frame(): target panic on start_frame()"));
497 for(y=0;y<surface->get_h();y++,pen.inc_y())
499 Color *colordata= start_scanline(y);
502 throw(string("add_frame(): call to start_scanline(y) returned NULL"));
506 if(get_remove_alpha())
508 for(int i=0;i<surface->get_w();i++)
509 colordata[i]=Color::blend((*surface)[y][i],desc.get_bg_color(),1.0f);
512 memcpy(colordata,(*surface)[y],rowspan);
516 throw(string("add_frame(): target panic on end_scanline()"));