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