1 /* === S Y N F I G ========================================================= */
2 /*! \file target_scanline.cpp
3 ** \brief Template File
5 ** $Id: target_scanline.cpp,v 1.1.1.1 2005/01/04 01:23:15 darco Exp $
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
10 ** This package is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU General Public License as
12 ** published by the Free Software Foundation; either version 2 of
13 ** the License, or (at your option) any later version.
15 ** This package is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ** General Public License for more details.
21 /* ========================================================================= */
23 /* === H E A D E R S ======================================================= */
32 #include "target_scanline.h"
41 /* === U S I N G =========================================================== */
45 using namespace synfig;
47 /* === M A C R O S ========================================================= */
49 #define SYNFIG_OPTIMIZE_LAYER_TREE 1
51 #define PIXEL_RENDERING_LIMIT 1500000
53 #define USE_PIXELRENDERING_LIMIT 0
55 /* === G L O B A L S ======================================================= */
57 /* === P R O C E D U R E S ================================================= */
59 /* === M E T H O D S ======================================================= */
61 Target_Scanline::Target_Scanline():
68 Target_Scanline::next_frame(Time& time)
78 // If the description's end frame is equal to
79 // the start frame, then it is assumed that we
80 // are rendering only one frame. Correct it.
81 if(desc.get_frame_end()==desc.get_frame_start())
82 desc.set_frame_end(desc.get_frame_start()+1);
84 frame_start=desc.get_frame_start();
85 frame_end=desc.get_frame_end();
86 time_start=desc.get_time_start();
87 time_end=desc.get_time_end();
89 // Calculate the number of frames
90 total_frames=frame_end-frame_start;
91 if(total_frames<=0)total_frames=1;
93 //RendDesc rend_desc=desc;
94 //rend_desc.set_gamma(1);
96 // int total_tiles(total_tiles());
97 time=(time_end-time_start)*curr_frame_/total_frames+time_start;
100 /* synfig::info("curr_frame_: %d",curr_frame_);
101 synfig::info("total_frames: %d",total_frames);
102 synfig::info("time_end: %s",time_end.get_string().c_str());
103 synfig::info("time_start: %s",time_start.get_string().c_str());
105 // synfig::info("time: %s",time.get_string().c_str());
107 return total_frames- curr_frame_+1;
110 synfig::Target_Scanline::render(ProgressCallback *cb)
112 SuperCallback super_cb;
116 quality=get_quality(),
129 // If the description's end frame is equal to
130 // the start frame, then it is assumed that we
131 // are rendering only one frame. Correct it.
132 if(desc.get_frame_end()==desc.get_frame_start())
133 desc.set_frame_end(desc.get_frame_start()+1);
135 frame_start=desc.get_frame_start();
136 frame_end=desc.get_frame_end();
137 time_start=desc.get_time_start();
138 time_end=desc.get_time_end();
140 // Calculate the number of frames
141 total_frames=frame_end-frame_start;
144 //RendDesc rend_desc=desc;
150 //synfig::info("1time_set_to %s",t.get_string().c_str());
156 //for(i=0,t=time_start;i<total_frames;i++)
158 //t=((time_end-time_start)*((Real)i/(Real)total_frames)).round(desc.get_frame_rate())+time_start;
160 // If we have a callback, and it returns
161 // false, go ahead and bail. (it may be a user cancel)
162 if(cb && !cb->amount_complete(total_frames-(i-1),total_frames))
165 // Set the time that we wish to render
166 if(!get_avoid_time_sync() || canvas->get_time()!=t)
171 #ifdef SYNFIG_OPTIMIZE_LAYER_TREE
172 Canvas::Handle op_canvas(Canvas::create());
173 optimize_layers(canvas->get_context(), op_canvas);
174 context=op_canvas->get_context();
176 context=canvas->get_context();
179 // If the quality is set to zero, then we
180 // use the parametric scanline-renderer.
185 if(!synfig::render(context,this,desc,0))
190 if(!synfig::render_threaded(context,this,desc,0,threads_))
194 else // If quality is set otherwise, then we use the accelerated renderer
196 #if USE_PIXELRENDERING_LIMIT
197 if(desc.get_w()*desc.get_h() > PIXEL_RENDERING_LIMIT)
199 synfig::info("Render BROKEN UP! (%d pixels)", desc.get_w()*desc.get_h());
202 int rowheight = PIXEL_RENDERING_LIMIT/desc.get_w();
203 int rows = desc.get_h()/rowheight;
204 int lastrowheight = desc.get_h() - rows*rowheight;
208 synfig::info("\t blockh=%d,remh=%d,totrows=%d", rowheight,lastrowheight,rows);
210 // loop through all the full rows
213 throw(string("add_frame(): target panic on start_frame()"));
217 for(int i=0; i < rows; ++i)
219 RendDesc blockrd = desc;
221 //render the strip at the normal size unless it's the last one...
224 if(!lastrowheight) break;
225 blockrd.set_subwindow(0,i*rowheight,desc.get_w(),lastrowheight);
229 blockrd.set_subwindow(0,i*rowheight,desc.get_w(),rowheight);
232 if(!context.accelerated_render(&surface,quality,blockrd,0))
234 if(cb)cb->error(_("Accelerated Renderer Failure"));
239 int rowspan=sizeof(Color)*surface.get_w();
240 Surface::pen pen = surface.begin();
242 int yoff = i*rowheight;
244 for(y = 0; y < blockrd.get_h(); y++, pen.inc_y())
246 Color *colordata= start_scanline(y + yoff);
249 throw(string("add_frame(): call to start_scanline(y) returned NULL"));
253 if(get_remove_alpha())
255 for(int i = 0; i < surface.get_w(); i++)
256 colordata[i] = Color::blend(surface[y][i],desc.get_bg_color(),1.0f);
259 memcpy(colordata,surface[y],rowspan);
263 throw(string("add_frame(): target panic on end_scanline()"));
272 }else //use normal rendering...
277 if(!context.accelerated_render(&surface,quality,desc,0))
279 // For some reason, the accelerated renderer failed.
280 if(cb)cb->error(_("Accelerated Renderer Failure"));
285 // Put the surface we renderer
287 if(!add_frame(&surface))
289 if(cb)cb->error(_("Unable to put surface on target"));
293 #if USE_PIXELRENDERING_LIMIT
297 }while((i=next_frame(t)));
300 // Set the time that we wish to render
301 if(!get_avoid_time_sync() || canvas->get_time()!=t)
305 #ifdef SYNFIG_OPTIMIZE_LAYER_TREE
306 Canvas::Handle op_canvas(Canvas::create());
307 optimize_layers(canvas->get_context(), op_canvas);
308 context=op_canvas->get_context();
310 context=canvas->get_context();
313 // If the quality is set to zero, then we
314 // use the parametric scanline-renderer.
319 if(!synfig::render(context,this,desc,cb))
324 if(!synfig::render_threaded(context,this,desc,cb,threads_))
328 else // If quality is set otherwise, then we use the accelerated renderer
330 #if USE_PIXELRENDERING_LIMIT
331 if(desc.get_w()*desc.get_h() > PIXEL_RENDERING_LIMIT)
333 synfig::info("Render BROKEN UP! (%d pixels)", desc.get_w()*desc.get_h());
336 int totalheight = desc.get_h();
337 int rowheight = PIXEL_RENDERING_LIMIT/desc.get_w();
338 int rows = desc.get_h()/rowheight;
339 int lastrowheight = desc.get_h() - rows*rowheight;
343 synfig::info("\t blockh=%d,remh=%d,totrows=%d", rowheight,lastrowheight,rows);
345 // loop through all the full rows
348 throw(string("add_frame(): target panic on start_frame()"));
352 for(int i=0; i < rows; ++i)
354 RendDesc blockrd = desc;
356 //render the strip at the normal size unless it's the last one...
359 if(!lastrowheight) break;
360 blockrd.set_subwindow(0,i*rowheight,desc.get_w(),lastrowheight);
364 blockrd.set_subwindow(0,i*rowheight,desc.get_w(),rowheight);
367 SuperCallback sc(cb, i*rowheight, (i+1)*rowheight, totalheight);
369 if(!context.accelerated_render(&surface,quality,blockrd,&sc))
371 if(cb)cb->error(_("Accelerated Renderer Failure"));
376 int rowspan=sizeof(Color)*surface.get_w();
377 Surface::pen pen = surface.begin();
379 int yoff = i*rowheight;
381 for(y = 0; y < blockrd.get_h(); y++, pen.inc_y())
383 Color *colordata= start_scanline(y + yoff);
386 throw(string("add_frame(): call to start_scanline(y) returned NULL"));
390 if(get_remove_alpha())
392 for(int i = 0; i < surface.get_w(); i++)
393 colordata[i] = Color::blend(surface[y][i],desc.get_bg_color(),1.0f);
396 memcpy(colordata,surface[y],rowspan);
400 throw(string("add_frame(): target panic on end_scanline()"));
406 //I'm done with this part
407 sc.amount_complete(100,100);
417 if(!context.accelerated_render(&surface,quality,desc,cb))
419 if(cb)cb->error(_("Accelerated Renderer Failure"));
424 // Put the surface we renderer
426 if(!add_frame(&surface))
428 if(cb)cb->error(_("Unable to put surface on target"));
432 #if USE_PIXELRENDERING_LIMIT
441 if(cb)cb->error(_("Caught string :")+str);
444 catch(std::bad_alloc)
446 if(cb)cb->error(_("Ran out of memory (Probably a bug)"));
451 if(cb)cb->error(_("Caught unknown error, rethrowing..."));
458 Target_Scanline::add_frame(const Surface *surface)
464 int rowspan=sizeof(Color)*surface->get_w();
465 Surface::const_pen pen=surface->begin();
469 throw(string("add_frame(): target panic on start_frame()"));
473 for(y=0;y<surface->get_h();y++,pen.inc_y())
475 Color *colordata= start_scanline(y);
478 throw(string("add_frame(): call to start_scanline(y) returned NULL"));
482 if(get_remove_alpha())
484 for(int i=0;i<surface->get_w();i++)
485 colordata[i]=Color::blend((*surface)[y][i],desc.get_bg_color(),1.0f);
488 memcpy(colordata,(*surface)[y],rowspan);
492 throw(string("add_frame(): target panic on end_scanline()"));