more updates
[synfig.git] / synfig-core / trunk / src / synfig / target_tile.cpp
1 /* === S I N F G =========================================================== */
2 /*!     \file target_tile.cpp
3 **      \brief Template File
4 **
5 **      $Id: target_tile.cpp,v 1.2 2005/01/12 06:46:45 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_tile.h"
32 #include "string.h"
33 #include "surface.h"
34 #include "render.h"
35 #include "canvas.h"
36 #include "context.h"
37 #include "general.h"
38 #include <ETL/clock>
39
40 #endif
41
42 /* === U S I N G =========================================================== */
43
44 using namespace std;
45 using namespace etl;
46 using namespace sinfg;
47
48 /* === M A C R O S ========================================================= */
49 const unsigned int      DEF_TILE_WIDTH = 64;
50 const unsigned int      DEF_TILE_HEIGHT= 64;
51
52 #define SINFG_OPTIMIZE_LAYER_TREE       1
53 #ifdef _DEBUG
54 #define SINFG_DISPLAY_EFFICIENCY        1
55 #endif
56
57 /* === G L O B A L S ======================================================= */
58
59 /* === P R O C E D U R E S ================================================= */
60
61 /* === M E T H O D S ======================================================= */
62
63 Target_Tile::Target_Tile():
64         threads_(2),
65         tile_w_(DEF_TILE_WIDTH),
66         tile_h_(DEF_TILE_HEIGHT),
67         curr_tile_(0),
68         clipping_(true)
69 {
70         curr_frame_=0;
71 }
72
73 int
74 Target_Tile::next_frame(Time& time)
75 {
76         int
77                 total_frames(1),
78                 frame_start(0),
79                 frame_end(0);
80         Time
81                 time_start(0),
82                 time_end(0);
83
84         // If the description's end frame is equal to
85         // the start frame, then it is assumed that we
86         // are rendering only one frame. Correct it.
87         if(desc.get_frame_end()==desc.get_frame_start())
88                 desc.set_frame_end(desc.get_frame_start()+1);
89
90         frame_start=desc.get_frame_start();
91         frame_end=desc.get_frame_end();
92         time_start=desc.get_time_start();
93         time_end=desc.get_time_end();
94         
95         // Calculate the number of frames
96         total_frames=frame_end-frame_start;
97         if(total_frames<=0)total_frames=1;
98         
99         //RendDesc rend_desc=desc;
100         //rend_desc.set_gamma(1);
101
102 //      int total_tiles(total_tiles());
103         time=(time_end-time_start)*curr_frame_/total_frames+time_start;
104         curr_frame_++;
105
106 /*      sinfg::info("curr_frame_: %d",curr_frame_);
107         sinfg::info("total_frames: %d",total_frames);
108         sinfg::info("time_end: %s",time_end.get_string().c_str());
109         sinfg::info("time_start: %s",time_start.get_string().c_str());
110 */
111 //      sinfg::info("time: %s",time.get_string().c_str());
112
113         return total_frames- curr_frame_+1;
114 }
115
116 int
117 Target_Tile::next_tile(int& x, int& y)
118 {
119         // Width of the image(in tiles)
120         int tw(rend_desc().get_w()/tile_w_);
121         int th(rend_desc().get_h()/tile_h_);
122
123         // Add the last tiles (which will be clipped)
124         if(rend_desc().get_w()%tile_w_!=0)tw++;
125         if(rend_desc().get_h()%tile_h_!=0)th++;
126         
127         x=(curr_tile_%tw)*tile_h_;
128         y=(curr_tile_/tw)*tile_w_;
129
130         curr_tile_++;
131         return (tw*th)-curr_tile_+1;
132 }
133
134 bool
135 sinfg::Target_Tile::render_frame_(Context context,ProgressCallback *cb)
136 {
137         if(tile_w_<=0||tile_h_<=0)
138         {
139                 if(cb)cb->error(_("Bad Tile Size"));
140                 return false;
141         }
142         const RendDesc &rend_desc(desc);
143 #define total_tiles total_tiles()
144
145         etl::clock total_time;
146         etl::clock::value_type work_time(0);
147         etl::clock::value_type find_tile_time(0);
148         etl::clock::value_type add_tile_time(0);
149         total_time.reset();
150         
151         // If the quality is set to zero, then we
152         // use the parametric scanline-renderer.
153         if(get_quality()==0)
154         {
155                 Surface surface;
156                 
157                 RendDesc tile_desc;
158                 int x,y,w,h;
159                 int i;
160                 etl::clock tile_timer;
161                 tile_timer.reset();
162                 while((i=next_tile(x,y)))
163                 {
164                         find_tile_time+=tile_timer();
165                         SuperCallback   super(cb,(total_tiles-i+1)*1000,(total_tiles-i+2)*1000,total_tiles*1000);
166                         if(!super.amount_complete(0,1000))
167                                 return false;
168                         //if(cb && !cb->amount_complete(total_tiles-i,total_tiles))
169                         //      return false;
170
171                         // Perform clipping on the tile
172                         if(clipping_)
173                         {
174                                 w=x+tile_w_<rend_desc.get_w()?tile_w_:rend_desc.get_w()-x;
175                                 h=y+tile_h_<rend_desc.get_h()?tile_h_:rend_desc.get_h()-y;
176                                 if(w<=0||h<=0)continue;
177                         }
178                         else
179                         {
180                                 w=tile_w_;
181                                 h=tile_h_;
182                         }
183
184                         tile_desc=rend_desc;
185                         tile_desc.set_subwindow(x,y,w,h);
186                         if(!parametric_render(context, surface, tile_desc,&super))
187                         {
188                                 // For some reason, the parametric renderer failed.
189                                 if(cb)cb->error(_("Parametric Renderer Failure"));
190                                 return false;
191                         }
192                         else
193                         {
194                                 if(!surface)
195                                 {
196                                         if(cb)cb->error(_("Bad surface"));
197                                         return false;
198                                 }
199                                 if(get_remove_alpha())
200                                         for(int i=0;i<surface.get_w()*surface.get_h();i++)
201                                                 surface[0][i]=Color::blend(surface[0][i],desc.get_bg_color(),1.0f);
202                                 
203                                 // Add the tile to the target
204                                 if(!add_tile(surface,x,y))
205                                 {
206                                         if(cb)cb->error(_("add_tile():Unable to put surface on target"));
207                                         return false;
208                                 }
209                         }
210                 tile_timer.reset();
211                 }
212         }
213         else // If quality is set otherwise, then we use the accelerated renderer
214         {
215                 Surface surface;
216                 
217                 RendDesc tile_desc;
218                 int x,y,w,h;
219                 int i;
220                 etl::clock tile_timer;
221                 tile_timer.reset();
222                 while((i=next_tile(x,y)))
223                 {
224                         find_tile_time+=tile_timer();
225                         SuperCallback   super(cb,(total_tiles-i)*1000,(total_tiles-i+1)*1000,total_tiles*1000);
226                         if(!super.amount_complete(0,1000))
227                                 return false;
228 //                      if(cb && !cb->amount_complete(total_tiles-i,total_tiles))
229 //                              return false;
230                         // Perform clipping on the tile
231                         if(clipping_)
232                         {
233                                 w=x+tile_w_<rend_desc.get_w()?tile_w_:rend_desc.get_w()-x;
234                                 h=y+tile_h_<rend_desc.get_h()?tile_h_:rend_desc.get_h()-y;
235                                 if(w<=0||h<=0)continue;
236                         }
237                         else
238                         {
239                                 w=tile_w_;
240                                 h=tile_h_;
241                         }
242
243                         tile_desc=rend_desc;
244                         tile_desc.set_subwindow(x,y,w,h);
245                         
246                         etl::clock timer2;
247                         timer2.reset();
248                         
249                         if(!context.accelerated_render(&surface,get_quality(),tile_desc,&super))
250                         {
251                                 // For some reason, the accelerated renderer failed.
252                                 if(cb)cb->error(_("Accelerated Renderer Failure"));
253                                 return false;
254                         }
255                         else
256                         {
257                                 work_time+=timer2();
258                                 if(!surface)
259                                 {
260                                         if(cb)cb->error(_("Bad surface"));
261                                         return false;
262                                 }
263                                 if(get_remove_alpha())
264                                         for(int i=0;i<surface.get_w()*surface.get_h();i++)
265                                                 surface[0][i]=Color::blend(surface[0][i],desc.get_bg_color(),1.0f);
266
267                                 etl::clock timer;
268                                 timer.reset();
269                                 // Add the tile to the target
270                                 if(!add_tile(surface,x,y))
271                                 {
272                                         if(cb)cb->error(_("add_tile():Unable to put surface on target"));
273                                         return false;
274                                 }
275                                 add_tile_time+=timer();
276                         }
277                         tile_timer.reset();
278                 }
279         }
280         if(cb && !cb->amount_complete(total_tiles,total_tiles))
281                 return false;
282         
283 #if SINFG_DISPLAY_EFFICIENCY==1
284         sinfg::info(">>>>>> Render Time: %fsec, Find Tile Time: %fsec, Add Tile Time: %fsec, Total Time: %fsec",work_time,find_tile_time,add_tile_time,total_time());
285         sinfg::info(">>>>>> FRAME EFICIENCY: %f%%",(100.0f*work_time/total_time()));
286 #endif
287 #undef total_tiles
288         return true;
289 }
290
291 bool
292 sinfg::Target_Tile::render(ProgressCallback *cb)
293 {
294         SuperCallback super_cb;
295         int
296                 i=0,
297                 total_frames,
298                 frame_start,
299                 frame_end;
300         Time
301                 t=0,
302                 time_start,
303                 time_end;
304
305         assert(canvas);
306         curr_frame_=0;
307         init();
308         
309         // If the description's end frame is equal to
310         // the start frame, then it is assumed that we
311         // are rendering only one frame. Correct it.
312         if(desc.get_frame_end()==desc.get_frame_start())
313                 desc.set_frame_end(desc.get_frame_start()+1);
314
315         frame_start=desc.get_frame_start();
316         frame_end=desc.get_frame_end();
317         time_start=desc.get_time_start();
318         time_end=desc.get_time_end();
319         
320         // Calculate the number of frames
321         total_frames=frame_end-frame_start;
322         
323         
324         
325         try {
326                 // Grab the time
327                 i=next_frame(t);
328                 
329                 //sinfg::info("1time_set_to %s",t.get_string().c_str());
330                 
331                 if(i>=1)
332                 {
333                 do
334                 {
335                         curr_tile_=0;
336                         
337                         // If we have a callback, and it returns
338                         // false, go ahead and bail. (maybe a use cancel)
339                         if(cb && !cb->amount_complete(total_frames-(i-1),total_frames))
340                                 return false;
341                         
342                         if(!start_frame(cb))
343                                 return false;
344
345                         // Set the time that we wish to render
346                         //if(!get_avoid_time_sync() || canvas->get_time()!=t)
347                                 canvas->set_time(t);
348                         
349                         Context context;
350                         
351                         #ifdef SINFG_OPTIMIZE_LAYER_TREE
352                         Canvas::Handle op_canvas(Canvas::create());
353                         optimize_layers(canvas->get_context(), op_canvas);
354                         context=op_canvas->get_context();
355                         #else
356                         context=canvas->get_context();
357                         #endif
358                         
359 /*
360                         #ifdef SINFG_OPTIMIZE_LAYER_TREE
361                         Context context;
362                         Canvas::Handle op_canvas(Canvas::create());
363                         // Set the time that we wish to render
364                         canvas->set_time(t);
365                         optimize_layers(canvas->get_context(), op_canvas);
366                         context=op_canvas->get_context();
367                         #else
368                         Context context;
369                         // Set the time that we wish to render
370                         canvas->set_time(t);
371                         context=canvas->get_context();
372                         #endif
373 */
374                         
375                         if(!render_frame_(context,0))
376                                 return false;
377                         end_frame();
378                 }while((i=next_frame(t)));
379                 //sinfg::info("tilerenderer: i=%d, t=%s",i,t.get_string().c_str());
380                 }
381                 else
382                 {
383                         curr_tile_=0;
384         
385                         if(!start_frame(cb))
386                                 return false;
387
388                         // Set the time that we wish to render
389 //                      if(!get_avoid_time_sync() || canvas->get_time()!=t)
390                                 canvas->set_time(t);
391
392                         //sinfg::info("2time_set_to %s",t.get_string().c_str());
393
394                         Context context;
395                         
396                         #ifdef SINFG_OPTIMIZE_LAYER_TREE
397                         Canvas::Handle op_canvas(Canvas::create());
398                         optimize_layers(canvas->get_context(), op_canvas);
399                         context=op_canvas->get_context();
400                         #else
401                         context=canvas->get_context();
402                         #endif
403                 
404                         if(!render_frame_(context, cb))
405                                 return false;
406                         end_frame();
407                 }
408         
409         }
410         catch(String str)
411         {
412                 if(cb)cb->error(_("Caught string :")+str);
413                 return false;
414         }
415         catch(std::bad_alloc)
416         {
417                 if(cb)cb->error(_("Ran out of memory (Probably a bug)"));
418                 return false;
419         }
420         catch(...)
421         {
422                 if(cb)cb->error(_("Caught unknown error, rethrowing..."));
423                 throw;
424         }
425         return true;
426 }