Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-core / tags / synfig_0_61_06 / src / synfig / target_scanline.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file target_scanline.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
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.
14 **
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.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include "target_scanline.h"
33 #include "string.h"
34 #include "surface.h"
35 #include "render.h"
36 #include "canvas.h"
37 #include "context.h"
38
39 #endif
40
41 /* === U S I N G =========================================================== */
42
43 using namespace std;
44 using namespace etl;
45 using namespace synfig;
46
47 /* === M A C R O S ========================================================= */
48
49 #define SYNFIG_OPTIMIZE_LAYER_TREE 1
50
51 #define PIXEL_RENDERING_LIMIT 1500000
52
53 #define USE_PIXELRENDERING_LIMIT 1
54
55 /* === G L O B A L S ======================================================= */
56
57 /* === P R O C E D U R E S ================================================= */
58
59 /* === M E T H O D S ======================================================= */
60
61 Target_Scanline::Target_Scanline():
62         threads_(2)
63 {
64         curr_frame_=0;
65 }
66
67 int
68 Target_Scanline::next_frame(Time& time)
69 {
70         int
71                 total_frames(1),
72                 frame_start(0),
73                 frame_end(0);
74         Time
75                 time_start(0),
76                 time_end(0);
77
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);
83
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();
88
89         // Calculate the number of frames
90         total_frames=frame_end-frame_start;
91         if(total_frames<=0)total_frames=1;
92
93         //RendDesc rend_desc=desc;
94         //rend_desc.set_gamma(1);
95
96 //      int total_tiles(total_tiles());
97         time=(time_end-time_start)*curr_frame_/total_frames+time_start;
98         curr_frame_++;
99
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());
104 */
105 //      synfig::info("time: %s",time.get_string().c_str());
106
107         return total_frames- curr_frame_+1;
108 }
109 bool
110 synfig::Target_Scanline::render(ProgressCallback *cb)
111 {
112         SuperCallback super_cb;
113         int
114 //              i=0,
115                 total_frames,
116                 quality=get_quality(),
117                 frame_start,
118                 frame_end;
119         Time
120                 t=0,
121                 time_start,
122                 time_end;
123
124         assert(canvas);
125         curr_frame_=0;
126
127         if( !init() ){
128                 if(cb) cb->error(_("Target initialisation failure"));
129                 return false;
130         }
131
132         // If the description's end frame is equal to
133         // the start frame, then it is assumed that we
134         // are rendering only one frame. Correct it.
135         if(desc.get_frame_end()==desc.get_frame_start())
136                 desc.set_frame_end(desc.get_frame_start()+1);
137
138         frame_start=desc.get_frame_start();
139         frame_end=desc.get_frame_end();
140         time_start=desc.get_time_start();
141         time_end=desc.get_time_end();
142
143         // Calculate the number of frames
144         total_frames=frame_end-frame_start;
145
146
147         //RendDesc rend_desc=desc;
148
149         try {
150         // Grab the time
151         int i=next_frame(t);
152
153         //synfig::info("1time_set_to %s",t.get_string().c_str());
154
155         if(i>1)
156         do{
157
158         //if(total_frames>1)
159         //for(i=0,t=time_start;i<total_frames;i++)
160         //{
161                 //t=((time_end-time_start)*((Real)i/(Real)total_frames)).round(desc.get_frame_rate())+time_start;
162
163                 // If we have a callback, and it returns
164                 // false, go ahead and bail. (it may be a user cancel)
165                 if(cb && !cb->amount_complete(total_frames-(i-1),total_frames))
166                         return false;
167
168                 // Set the time that we wish to render
169                 if(!get_avoid_time_sync() || canvas->get_time()!=t)
170                         canvas->set_time(t);
171
172                 Context context;
173
174                 #ifdef SYNFIG_OPTIMIZE_LAYER_TREE
175                 Canvas::Handle op_canvas(Canvas::create());
176                 optimize_layers(canvas->get_context(), op_canvas);
177                 context=op_canvas->get_context();
178                 #else
179                 context=canvas->get_context();
180                 #endif
181
182                 // If the quality is set to zero, then we
183                 // use the parametric scanline-renderer.
184                 if(quality==0)
185                 {
186                         if(threads_<=0)
187                         {
188                                 if(!synfig::render(context,this,desc,0))
189                                         return false;
190                         }
191                         else
192                         {
193                                 if(!synfig::render_threaded(context,this,desc,0,threads_))
194                                         return false;
195                         }
196                 }
197                 else // If quality is set otherwise, then we use the accelerated renderer
198                 {
199                         #if USE_PIXELRENDERING_LIMIT
200                         if(desc.get_w()*desc.get_h() > PIXEL_RENDERING_LIMIT)
201                         {
202                                 synfig::info("Render BROKEN UP! (%d pixels)", desc.get_w()*desc.get_h());
203
204                                 Surface surface;
205                                 int rowheight = PIXEL_RENDERING_LIMIT/desc.get_w();
206                                 if (!rowheight) rowheight = 1; // TODO: render partial lines to stay within the limit?
207                                 int rows = desc.get_h()/rowheight;
208                                 int lastrowheight = desc.get_h() - rows*rowheight;
209
210                                 rows++;
211
212                                 synfig::info("\t blockh=%d,remh=%d,totrows=%d", rowheight,lastrowheight,rows);
213
214                                 // loop through all the full rows
215                                 if(!start_frame())
216                                 {
217                                         throw(string("add_frame(): target panic on start_frame()"));
218                                         return false;
219                                 }
220
221                                 for(int i=0; i < rows; ++i)
222                                 {
223                                         RendDesc        blockrd = desc;
224
225                                         //render the strip at the normal size unless it's the last one...
226                                         if(i == rows-1)
227                                         {
228                                                 if(!lastrowheight) break;
229                                                 blockrd.set_subwindow(0,i*rowheight,desc.get_w(),lastrowheight);
230                                         }
231                                         else
232                                         {
233                                                 blockrd.set_subwindow(0,i*rowheight,desc.get_w(),rowheight);
234                                         }
235
236                                         if(!context.accelerated_render(&surface,quality,blockrd,0))
237                                         {
238                                                 if(cb)cb->error(_("Accelerated Renderer Failure"));
239                                                 return false;
240                                         }else
241                                         {
242                                                 int y;
243                                                 int rowspan=sizeof(Color)*surface.get_w();
244                                                 Surface::pen pen = surface.begin();
245
246                                                 int yoff = i*rowheight;
247
248                                                 for(y = 0; y < blockrd.get_h(); y++, pen.inc_y())
249                                                 {
250                                                         Color *colordata= start_scanline(y + yoff);
251                                                         if(!colordata)
252                                                         {
253                                                                 throw(string("add_frame(): call to start_scanline(y) returned NULL"));
254                                                                 return false;
255                                                         }
256
257                                                         if(get_remove_alpha())
258                                                         {
259                                                                 for(int i = 0; i < surface.get_w(); i++)
260                                                                         colordata[i] = Color::blend(surface[y][i],desc.get_bg_color(),1.0f);
261                                                         }
262                                                         else
263                                                                 memcpy(colordata,surface[y],rowspan);
264
265                                                         if(!end_scanline())
266                                                         {
267                                                                 throw(string("add_frame(): target panic on end_scanline()"));
268                                                                 return false;
269                                                         }
270                                                 }
271                                         }
272                                 }
273
274                                 end_frame();
275
276                         }else //use normal rendering...
277                         {
278                         #endif
279                                 Surface surface;
280
281                                 if(!context.accelerated_render(&surface,quality,desc,0))
282                                 {
283                                         // For some reason, the accelerated renderer failed.
284                                         if(cb)cb->error(_("Accelerated Renderer Failure"));
285                                         return false;
286                                 }
287                                 else
288                                 {
289                                         // Put the surface we renderer
290                                         // onto the target.
291                                         if(!add_frame(&surface))
292                                         {
293                                                 if(cb)cb->error(_("Unable to put surface on target"));
294                                                 return false;
295                                         }
296                                 }
297                         #if USE_PIXELRENDERING_LIMIT
298                         }
299                         #endif
300                 }
301         }while((i=next_frame(t)));
302     else
303     {
304                 // Set the time that we wish to render
305                 if(!get_avoid_time_sync() || canvas->get_time()!=t)
306                         canvas->set_time(t);
307                 Context context;
308
309                 #ifdef SYNFIG_OPTIMIZE_LAYER_TREE
310                 Canvas::Handle op_canvas(Canvas::create());
311                 optimize_layers(canvas->get_context(), op_canvas);
312                 context=op_canvas->get_context();
313                 #else
314                 context=canvas->get_context();
315                 #endif
316
317                 // If the quality is set to zero, then we
318                 // use the parametric scanline-renderer.
319                 if(quality==0)
320                 {
321                         if(threads_<=0)
322                         {
323                                 if(!synfig::render(context,this,desc,cb))
324                                         return false;
325                         }
326                         else
327                         {
328                                 if(!synfig::render_threaded(context,this,desc,cb,threads_))
329                                         return false;
330                         }
331                 }
332                 else // If quality is set otherwise, then we use the accelerated renderer
333                 {
334                         #if USE_PIXELRENDERING_LIMIT
335                         if(desc.get_w()*desc.get_h() > PIXEL_RENDERING_LIMIT)
336                         {
337                                 synfig::info("Render BROKEN UP! (%d pixels)", desc.get_w()*desc.get_h());
338
339                                 Surface surface;
340                                 int totalheight = desc.get_h();
341                                 int rowheight = PIXEL_RENDERING_LIMIT/desc.get_w();
342                                 if (!rowheight) rowheight = 1; // TODO: render partial lines to stay within the limit?
343                                 int rows = desc.get_h()/rowheight;
344                                 int lastrowheight = desc.get_h() - rows*rowheight;
345
346                                 rows++;
347
348                                 synfig::info("\t blockh=%d,remh=%d,totrows=%d", rowheight,lastrowheight,rows);
349
350                                 // loop through all the full rows
351                                 if(!start_frame())
352                                 {
353                                         throw(string("add_frame(): target panic on start_frame()"));
354                                         return false;
355                                 }
356
357                                 for(int i=0; i < rows; ++i)
358                                 {
359                                         RendDesc        blockrd = desc;
360
361                                         //render the strip at the normal size unless it's the last one...
362                                         if(i == rows-1)
363                                         {
364                                                 if(!lastrowheight) break;
365                                                 blockrd.set_subwindow(0,i*rowheight,desc.get_w(),lastrowheight);
366                                         }
367                                         else
368                                         {
369                                                 blockrd.set_subwindow(0,i*rowheight,desc.get_w(),rowheight);
370                                         }
371
372                                         SuperCallback   sc(cb, i*rowheight, (i+1)*rowheight, totalheight);
373
374                                         if(!context.accelerated_render(&surface,quality,blockrd,&sc))
375                                         {
376                                                 if(cb)cb->error(_("Accelerated Renderer Failure"));
377                                                 return false;
378                                         }else
379                                         {
380                                                 int y;
381                                                 int rowspan=sizeof(Color)*surface.get_w();
382                                                 Surface::pen pen = surface.begin();
383
384                                                 int yoff = i*rowheight;
385
386                                                 for(y = 0; y < blockrd.get_h(); y++, pen.inc_y())
387                                                 {
388                                                         Color *colordata= start_scanline(y + yoff);
389                                                         if(!colordata)
390                                                         {
391                                                                 throw(string("add_frame(): call to start_scanline(y) returned NULL"));
392                                                                 return false;
393                                                         }
394
395                                                         if(get_remove_alpha())
396                                                         {
397                                                                 for(int i = 0; i < surface.get_w(); i++)
398                                                                         colordata[i] = Color::blend(surface[y][i],desc.get_bg_color(),1.0f);
399                                                         }
400                                                         else
401                                                                 memcpy(colordata,surface[y],rowspan);
402
403                                                         if(!end_scanline())
404                                                         {
405                                                                 throw(string("add_frame(): target panic on end_scanline()"));
406                                                                 return false;
407                                                         }
408                                                 }
409                                         }
410
411                                         //I'm done with this part
412                                         sc.amount_complete(100,100);
413                                 }
414
415                                 end_frame();
416
417                         }else
418                         {
419                         #endif
420                                 Surface surface;
421
422                                 if(!context.accelerated_render(&surface,quality,desc,cb))
423                                 {
424                                         if(cb)cb->error(_("Accelerated Renderer Failure"));
425                                         return false;
426                                 }
427                                 else
428                                 {
429                                         // Put the surface we renderer
430                                         // onto the target.
431                                         if(!add_frame(&surface))
432                                         {
433                                                 if(cb)cb->error(_("Unable to put surface on target"));
434                                                 return false;
435                                         }
436                                 }
437                         #if USE_PIXELRENDERING_LIMIT
438                         }
439                         #endif
440                 }
441         }
442
443         }
444         catch(String str)
445         {
446                 if(cb)cb->error(_("Caught string :")+str);
447                 return false;
448         }
449         catch(std::bad_alloc)
450         {
451                 if(cb)cb->error(_("Ran out of memory (Probably a bug)"));
452                 return false;
453         }
454         catch(...)
455         {
456                 if(cb)cb->error(_("Caught unknown error, rethrowing..."));
457                 throw;
458         }
459         return true;
460 }
461
462 bool
463 Target_Scanline::add_frame(const Surface *surface)
464 {
465         assert(surface);
466
467
468         int y;
469         int rowspan=sizeof(Color)*surface->get_w();
470         Surface::const_pen pen=surface->begin();
471
472         if(!start_frame())
473         {
474                 throw(string("add_frame(): target panic on start_frame()"));
475                 return false;
476         }
477
478         for(y=0;y<surface->get_h();y++,pen.inc_y())
479         {
480                 Color *colordata= start_scanline(y);
481                 if(!colordata)
482                 {
483                         throw(string("add_frame(): call to start_scanline(y) returned NULL"));
484                         return false;
485                 }
486
487                 if(get_remove_alpha())
488                 {
489                         for(int i=0;i<surface->get_w();i++)
490                                 colordata[i]=Color::blend((*surface)[y][i],desc.get_bg_color(),1.0f);
491                 }
492                 else
493                         memcpy(colordata,(*surface)[y],rowspan);
494
495                 if(!end_scanline())
496                 {
497                         throw(string("add_frame(): target panic on end_scanline()"));
498                         return false;
499                 }
500         }
501
502         end_frame();
503
504         return true;
505 }