Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-core / tags / synfig_0_61_04 / synfig-core / src / synfig / target_scanline.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file target_scanline.cpp
3 **      \brief Template File
4 **
5 **      $Id: target_scanline.cpp,v 1.1.1.1 2005/01/04 01:23:15 darco Exp $
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 0
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         init();
128         
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);
134
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();
139         
140         // Calculate the number of frames
141         total_frames=frame_end-frame_start;
142         
143         
144         //RendDesc rend_desc=desc;
145                 
146         try {
147         // Grab the time
148         int i=next_frame(t);
149         
150         //synfig::info("1time_set_to %s",t.get_string().c_str());
151         
152         if(i>1)
153         do{
154         
155         //if(total_frames>1)
156         //for(i=0,t=time_start;i<total_frames;i++)
157         //{
158                 //t=((time_end-time_start)*((Real)i/(Real)total_frames)).round(desc.get_frame_rate())+time_start;
159
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))
163                         return false;
164                 
165                 // Set the time that we wish to render
166                 if(!get_avoid_time_sync() || canvas->get_time()!=t)
167                         canvas->set_time(t);
168                 
169                 Context context;
170                 
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();
175                 #else
176                 context=canvas->get_context();
177                 #endif
178                 
179                 // If the quality is set to zero, then we
180                 // use the parametric scanline-renderer.
181                 if(quality==0)
182                 {
183                         if(threads_<=0)
184                         {
185                                 if(!synfig::render(context,this,desc,0))
186                                         return false;
187                         }
188                         else
189                         {
190                                 if(!synfig::render_threaded(context,this,desc,0,threads_))
191                                         return false;
192                         }
193                 }
194                 else // If quality is set otherwise, then we use the accelerated renderer
195                 {
196                         #if USE_PIXELRENDERING_LIMIT
197                         if(desc.get_w()*desc.get_h() > PIXEL_RENDERING_LIMIT)
198                         {                                       
199                                 synfig::info("Render BROKEN UP! (%d pixels)", desc.get_w()*desc.get_h());
200                                                                 
201                                 Surface surface;                                
202                                 int rowheight = PIXEL_RENDERING_LIMIT/desc.get_w();
203                                 int rows = desc.get_h()/rowheight;
204                                 int lastrowheight = desc.get_h() - rows*rowheight;
205                                 
206                                 rows++;
207                                 
208                                 synfig::info("\t blockh=%d,remh=%d,totrows=%d", rowheight,lastrowheight,rows);                          
209                                 
210                                 // loop through all the full rows
211                                 if(!start_frame())
212                                 {
213                                         throw(string("add_frame(): target panic on start_frame()"));
214                                         return false;
215                                 }
216                                 
217                                 for(int i=0; i < rows; ++i)
218                                 {
219                                         RendDesc        blockrd = desc;
220                                         
221                                         //render the strip at the normal size unless it's the last one...
222                                         if(i == rows)
223                                         {
224                                                 if(!lastrowheight) break;
225                                                 blockrd.set_subwindow(0,i*rowheight,desc.get_w(),lastrowheight);
226                                         }
227                                         else
228                                         {
229                                                 blockrd.set_subwindow(0,i*rowheight,desc.get_w(),rowheight);
230                                         }
231                                         
232                                         if(!context.accelerated_render(&surface,quality,blockrd,0))
233                                         {
234                                                 if(cb)cb->error(_("Accelerated Renderer Failure"));
235                                                 return false;
236                                         }else
237                                         {
238                                                 int y;
239                                                 int rowspan=sizeof(Color)*surface.get_w();
240                                                 Surface::pen pen = surface.begin();
241                                                 
242                                                 int yoff = i*rowheight;
243                                                 
244                                                 for(y = 0; y < blockrd.get_h(); y++, pen.inc_y())
245                                                 {
246                                                         Color *colordata= start_scanline(y + yoff);
247                                                         if(!colordata)
248                                                         {
249                                                                 throw(string("add_frame(): call to start_scanline(y) returned NULL"));
250                                                                 return false;
251                                                         }
252                                                         
253                                                         if(get_remove_alpha())
254                                                         {
255                                                                 for(int i = 0; i < surface.get_w(); i++)
256                                                                         colordata[i] = Color::blend(surface[y][i],desc.get_bg_color(),1.0f);
257                                                         }
258                                                         else
259                                                                 memcpy(colordata,surface[y],rowspan);
260                                                 
261                                                         if(!end_scanline())
262                                                         {
263                                                                 throw(string("add_frame(): target panic on end_scanline()"));
264                                                                 return false;
265                                                         }
266                                                 }
267                                         }
268                                 }       
269
270                                 end_frame();                            
271                                 
272                         }else //use normal rendering...
273                         {
274                         #endif
275                                 Surface surface;
276                                 
277                                 if(!context.accelerated_render(&surface,quality,desc,0))
278                                 {
279                                         // For some reason, the accelerated renderer failed.
280                                         if(cb)cb->error(_("Accelerated Renderer Failure"));
281                                         return false;
282                                 }
283                                 else
284                                 {
285                                         // Put the surface we renderer
286                                         // onto the target.
287                                         if(!add_frame(&surface))
288                                         {
289                                                 if(cb)cb->error(_("Unable to put surface on target"));
290                                                 return false;
291                                         }
292                                 }
293                         #if USE_PIXELRENDERING_LIMIT
294                         }
295                         #endif
296                 }
297         }while((i=next_frame(t)));
298     else
299     {
300                 // Set the time that we wish to render
301                 if(!get_avoid_time_sync() || canvas->get_time()!=t)
302                         canvas->set_time(t);
303                 Context context;
304                 
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();
309                 #else
310                 context=canvas->get_context();
311                 #endif
312                 
313                 // If the quality is set to zero, then we
314                 // use the parametric scanline-renderer.
315                 if(quality==0)
316                 {
317                         if(threads_<=0)
318                         {
319                                 if(!synfig::render(context,this,desc,cb))
320                                         return false;
321                         }
322                         else
323                         {
324                                 if(!synfig::render_threaded(context,this,desc,cb,threads_))
325                                         return false;
326                         }
327                 }
328                 else // If quality is set otherwise, then we use the accelerated renderer
329                 {
330                         #if USE_PIXELRENDERING_LIMIT
331                         if(desc.get_w()*desc.get_h() > PIXEL_RENDERING_LIMIT)
332                         {
333                                 synfig::info("Render BROKEN UP! (%d pixels)", desc.get_w()*desc.get_h());
334                                 
335                                 Surface surface;                                
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;
340                                 
341                                 rows++;
342                                 
343                                 synfig::info("\t blockh=%d,remh=%d,totrows=%d", rowheight,lastrowheight,rows);                          
344                                 
345                                 // loop through all the full rows
346                                 if(!start_frame())
347                                 {
348                                         throw(string("add_frame(): target panic on start_frame()"));
349                                         return false;
350                                 }
351                                 
352                                 for(int i=0; i < rows; ++i)
353                                 {
354                                         RendDesc        blockrd = desc;
355                                         
356                                         //render the strip at the normal size unless it's the last one...
357                                         if(i == rows)
358                                         {
359                                                 if(!lastrowheight) break;
360                                                 blockrd.set_subwindow(0,i*rowheight,desc.get_w(),lastrowheight);
361                                         }
362                                         else
363                                         {
364                                                 blockrd.set_subwindow(0,i*rowheight,desc.get_w(),rowheight);
365                                         }
366                                         
367                                         SuperCallback   sc(cb, i*rowheight, (i+1)*rowheight, totalheight);
368                                         
369                                         if(!context.accelerated_render(&surface,quality,blockrd,&sc))
370                                         {
371                                                 if(cb)cb->error(_("Accelerated Renderer Failure"));
372                                                 return false;
373                                         }else
374                                         {
375                                                 int y;
376                                                 int rowspan=sizeof(Color)*surface.get_w();
377                                                 Surface::pen pen = surface.begin();
378                                                 
379                                                 int yoff = i*rowheight;
380                                                 
381                                                 for(y = 0; y < blockrd.get_h(); y++, pen.inc_y())
382                                                 {
383                                                         Color *colordata= start_scanline(y + yoff);
384                                                         if(!colordata)
385                                                         {
386                                                                 throw(string("add_frame(): call to start_scanline(y) returned NULL"));
387                                                                 return false;
388                                                         }
389                                                         
390                                                         if(get_remove_alpha())
391                                                         {
392                                                                 for(int i = 0; i < surface.get_w(); i++)
393                                                                         colordata[i] = Color::blend(surface[y][i],desc.get_bg_color(),1.0f);
394                                                         }
395                                                         else
396                                                                 memcpy(colordata,surface[y],rowspan);
397                                                 
398                                                         if(!end_scanline())
399                                                         {
400                                                                 throw(string("add_frame(): target panic on end_scanline()"));
401                                                                 return false;
402                                                         }
403                                                 }
404                                         }
405                                         
406                                         //I'm done with this part
407                                         sc.amount_complete(100,100);
408                                 }       
409
410                                 end_frame();                            
411                                 
412                         }else
413                         {
414                         #endif                  
415                                 Surface surface;
416                                 
417                                 if(!context.accelerated_render(&surface,quality,desc,cb))
418                                 {
419                                         if(cb)cb->error(_("Accelerated Renderer Failure"));
420                                         return false;
421                                 }
422                                 else
423                                 {
424                                         // Put the surface we renderer
425                                         // onto the target.
426                                         if(!add_frame(&surface))
427                                         {
428                                                 if(cb)cb->error(_("Unable to put surface on target"));
429                                                 return false;
430                                         }
431                                 }
432                         #if USE_PIXELRENDERING_LIMIT
433                         }
434                         #endif
435                 }
436         }
437         
438         }
439         catch(String str)
440         {
441                 if(cb)cb->error(_("Caught string :")+str);
442                 return false;
443         }
444         catch(std::bad_alloc)
445         {
446                 if(cb)cb->error(_("Ran out of memory (Probably a bug)"));
447                 return false;
448         }
449         catch(...)
450         {
451                 if(cb)cb->error(_("Caught unknown error, rethrowing..."));
452                 throw;
453         }
454         return true;
455 }
456
457 bool
458 Target_Scanline::add_frame(const Surface *surface)
459 {
460         assert(surface);
461
462
463         int y;
464         int rowspan=sizeof(Color)*surface->get_w();
465         Surface::const_pen pen=surface->begin();
466         
467         if(!start_frame())
468         {
469                 throw(string("add_frame(): target panic on start_frame()"));
470                 return false;
471         }
472                 
473         for(y=0;y<surface->get_h();y++,pen.inc_y())
474         {
475                 Color *colordata= start_scanline(y);
476                 if(!colordata)
477                 {
478                         throw(string("add_frame(): call to start_scanline(y) returned NULL"));
479                         return false;
480                 }
481                 
482                 if(get_remove_alpha())
483                 {
484                         for(int i=0;i<surface->get_w();i++)
485                                 colordata[i]=Color::blend((*surface)[y][i],desc.get_bg_color(),1.0f);
486                 }
487                 else
488                         memcpy(colordata,(*surface)[y],rowspan);
489         
490                 if(!end_scanline())
491                 {
492                         throw(string("add_frame(): target panic on end_scanline()"));
493                         return false;
494                 }
495         }
496         
497         end_frame();
498         
499         return true;
500 }