more updates
[synfig.git] / synfig-core / trunk / src / synfig / render.cpp
1 /* === S I N F G =========================================================== */
2 /*!     \file render.cpp
3 **      \brief Renderer
4 **
5 **      $Id: render.cpp,v 1.1.1.1 2005/01/04 01:23:14 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 #define SINFG_NO_ANGLE
25
26 #ifdef USING_PCH
27 #       include "pch.h"
28 #else
29 #ifdef HAVE_CONFIG_H
30 #       include <config.h>
31 #endif
32
33 #ifndef WIN32
34 #include <unistd.h>
35 #include <sys/types.h>
36 #include <signal.h>
37 #endif
38
39 #include "render.h"
40 #include "target.h"
41 #include "canvas.h"
42 #include <ETL/handle>
43 #include <cassert>
44 #include "context.h"
45 #include "surface.h"
46
47 #endif
48
49 using namespace std;
50 using namespace sinfg;
51 using namespace etl;
52
53 /* === M A C R O S ========================================================= */
54
55 /* === P R O C E D U R E S ================================================= */
56
57 bool
58 sinfg::parametric_render(
59         Context context,
60         Surface &surface,
61         const RendDesc &desc,
62         ProgressCallback *callback
63 )
64 {
65         Point::value_type
66                 u,v,            // Current location in image
67                 su,sv,          // Starting locations
68                 du, dv,         // Distance between pixels
69                 dsu,dsv;        // Distance between subpixels
70
71         bool
72                 no_clamp=!desc.get_clamp();
73         
74         int
75                 w(desc.get_w()),
76                 h(desc.get_h()),
77                 a(desc.get_antialias());
78         
79         Point
80                 tl(desc.get_tl()),
81                 br(desc.get_br());
82         
83         //Gamma
84         //      gamma(desc.get_gamma());
85
86         int
87                 x,y,            // Current location on output bitmap
88                 x2,y2;          // Subpixel counters
89
90         Color::value_type
91                 pool;           // Alpha pool (for correct alpha antialiasing)
92         
93         // Calculate the number of channels
94         //chan=channels(desc.get_pixel_format());
95                 
96         // Calculate the distance between pixels
97         du=(br[0]-tl[0])/(Point::value_type)w;
98         dv=(br[1]-tl[1])/(Point::value_type)h;
99
100         // Calculate the distance between sub pixels
101         dsu=du/(Point::value_type)a;
102         dsv=dv/(Point::value_type)a;
103
104         // Calculate the starting points
105         //su=tl[0]+(du-dsu)/(Point::value_type)2.0;
106         //sv=tl[1]-(dv-dsv)/(Point::value_type)2.0;
107         su=tl[0];
108         sv=tl[1];
109         
110         surface.set_wh(desc.get_w(),desc.get_h());
111
112         assert(surface);
113         
114         // Loop through all horizontal lines
115         for(y=0,v=sv;y<h;y++,v+=dv)
116         {
117                 // Set the current pixel pointer
118                 // to the start of the line
119                 Color *colordata=surface[y];
120
121                 assert(colordata);
122                 
123                 // If we have a callback that we need
124                 // to report to, do so now.
125                 if(callback)
126                         if( callback->amount_complete(y,h) == false )
127                         {
128                                 // If the callback returns false,
129                                 // then the render has been aborted.
130
131                                 return false;
132                         }
133
134                 // Loop through every pixel in row
135                 for(x=0,u=su;x<w;x++,u+=du)
136                 {
137                         Color &c(*(colordata++));
138                         c=Color::alpha();
139
140                         // Loop through all subpixels
141                         for(y2=0,pool=0;y2<a;y2++)
142                                 for(x2=0;x2<a;x2++)
143                                 {
144                                         Color color=context.get_color(
145                                                 Point(
146                                                         u+(Point::value_type)(x2)*dsu,
147                                                         v+(Point::value_type)(y2)*dsv
148                                                         )
149                                                 );
150                                         if(!no_clamp)
151                                         {
152                                                 color=color.clamped();
153                                                 c+=color*color.get_a();
154                                                 pool+=color.get_a();
155                                         }
156                                         else
157                                         {
158                                                 c+=color*color.get_a();
159                                                 pool+=color.get_a();
160                                         }
161                                 }
162                         if(pool)
163                                 c/=pool;
164                 }
165         }
166         
167         // Give the callback one more last call,
168         // this time with the full height as the
169         // current line
170         if(callback)
171                 callback->amount_complete(h,h);
172
173         // Report our success
174         return(true);
175 }
176
177 bool
178 sinfg::render(
179         Context context,
180         Target_Scanline::Handle target,
181         const RendDesc &desc,
182         ProgressCallback *callback)
183 {
184         Point::value_type
185                 u,v,            // Current location in image
186                 su,sv,          // Starting locations
187                 du, dv,         // Distance between pixels
188                 dsu,dsv;        // Distance between subpixels
189
190         bool
191                 no_clamp=!desc.get_clamp();
192         
193         int
194                 w(desc.get_w()),
195                 h(desc.get_h()),
196                 a(desc.get_antialias());
197         
198         Point
199                 tl(desc.get_tl()),
200                 br(desc.get_br());
201         
202         //Gamma
203         //      gamma(desc.get_gamma());
204
205         int
206                 x,y,            // Current location on output bitmap
207                 x2,y2;          // Subpixel counters
208
209         Color::value_type
210                 pool;           // Alpha pool (for correct alpha antialiasing)
211
212         assert(target);
213         
214         // If we do not have a a target then bail
215         if(!target)
216                 return false;
217         
218         // Calculate the number of channels
219         //chan=channels(desc.get_pixel_format());
220                 
221         // Calculate the distance between pixels
222         du=(br[0]-tl[0])/(Point::value_type)w;
223         dv=(br[1]-tl[1])/(Point::value_type)h;
224
225         // Calculate the distance between sub pixels
226         dsu=du/(Point::value_type)a;
227         dsv=dv/(Point::value_type)a;
228
229         // Calculate the starting points
230         su=tl[0]+(du-dsu)/(Point::value_type)2.0;
231         sv=tl[1]-(dv-dsv)/(Point::value_type)2.0;
232
233         // Mark the start of a new frame.
234         if(!target->start_frame(callback))
235                 return false;
236                         
237         // Loop through all horizontal lines
238         for(y=0,v=sv;y<h;y++,v+=dv)
239         {
240                 // Set the current pixel pointer
241                 // to the start of the line
242                 Color *colordata=target->start_scanline(y);
243
244                 if(!colordata)
245                 {
246                         if(callback)callback->error(_("Target panic"));
247                         else throw(string(_("Target panic")));
248                         return false;
249                 }
250                 
251                 // If we have a callback that we need
252                 // to report to, do so now.
253                 if(callback)
254                         if( callback->amount_complete(y,h) == false )
255                         {
256                                 // If the callback returns false,
257                                 // then the render has been aborted.
258                                 // Exit gracefuly.
259
260                                 target->end_scanline();
261                                 target->end_frame();
262                                 return false;
263                         }
264
265                 // Loop through every pixel in row
266                 for(x=0,u=su;x<w;x++,u+=du)
267                 {
268                         Color &c(*(colordata++));
269                         c=Color::alpha();
270
271                         // Loop through all subpixels
272                         for(y2=0,pool=0;y2<a;y2++)
273                                 for(x2=0;x2<a;x2++)
274                                 {
275                                         Color color=context.get_color(
276                                                 Point(
277                                                         u+(Point::value_type)(x2)*dsu,
278                                                         v+(Point::value_type)(y2)*dsv
279                                                         )
280                                                 );
281                                         if(!no_clamp)
282                                         {
283                                                 color=color.clamped();
284                                                 c+=color*color.get_a();
285                                                 pool+=color.get_a();
286                                         }
287                                         else
288                                         {
289                                                 c+=color*color.get_a();
290                                                 pool+=color.get_a();
291                                         }
292                                 }
293                         if(pool)
294                                 c/=pool;
295                 }
296
297                 // Send the buffer to the render target.
298                 // If anything goes wrong, cleanup and bail.
299                 if(!target->end_scanline())
300                 {
301                         if(callback)callback->error(_("Target panic"));
302                         else throw(string(_("Target panic")));
303                         return false;
304                 }
305         }
306         
307         // Finish up the target's frame
308         target->end_frame();
309
310         // Give the callback one more last call,
311         // this time with the full height as the
312         // current line
313         if(callback)
314                 callback->amount_complete(h,h);
315
316         // Report our success
317         return(true);
318 }
319
320 bool
321 sinfg::render_threaded(
322         Context context,
323         Target_Scanline::Handle target,
324         const RendDesc &desc,
325         ProgressCallback *callback,
326         int threads)
327 {
328 #ifndef WIN32
329     struct _render_thread
330     {
331                 int
332                         pipe_read,
333                         pipe_write,
334                         pid;
335                 _render_thread()
336                 {
337                         pipe(&pipe_read);
338                         pid=0;
339                 }
340                 ~_render_thread()
341                 {
342                         close(pipe_read);
343                         close(pipe_write);
344                         if(pid)
345                         {
346                                 kill(pid,9);
347                         }
348                 }
349     } *render_thread;
350     
351     int i, mythread=-1;
352         
353         Point::value_type
354                 u,v,            // Current location in image
355                 su,sv,          // Starting locations
356                 du, dv,         // Distance between pixels
357                 dsu,dsv;        // Distance between subpixels
358
359         bool
360                 no_clamp=!desc.get_clamp();
361         
362         int
363                 w(desc.get_w()),
364                 h(desc.get_h()),
365                 a(desc.get_antialias());
366         
367         Point
368                 tl(desc.get_tl()),
369                 br(desc.get_br());
370         
371         int
372                 x,y,            // Current location on output bitmap
373                 x2,y2;          // Subpixel counters
374
375         Color::value_type
376                 pool;           // Alpha pool (for correct alpha antialiasing)
377
378         assert(target);
379         
380         // If we do not have a a target then bail
381         if(!target)
382                 return false;
383                         
384         // Calculate the distance between pixels
385         du=(br[0]-tl[0])/(Point::value_type)w;
386         dv=(br[1]-tl[1])/(Point::value_type)h;
387
388         // Calculate the distance between sub pixels
389         dsu=du/(Point::value_type)a;
390         dsv=dv/(Point::value_type)a;
391
392         // Calculate the starting points
393         su=tl[0]+(du-dsu)/(Point::value_type)2.0;
394         sv=tl[1]-(dv-dsv)/(Point::value_type)2.0;
395
396     render_thread=new _render_thread[threads];
397     
398         // Start the forks
399     for(i=0;i<threads;i++)
400     {
401                 int pid=fork();
402                 if(pid==0)
403                 {
404                 mythread=i;
405                 goto renderthread;
406                 }
407                 render_thread[i].pid=pid;
408     }
409     
410         // Mark the start of a new frame.
411         if(!target->start_frame(callback))
412                 return false;
413
414     for(y=0;y<h;y++)
415     {
416                 // Set the current pixel pointer
417                 // to the start of the line
418                 Color *colordata(target->start_scanline(y));
419
420                 if(!colordata)
421                 {
422                         if(callback)callback->error(_("Target panic"));
423                         else throw(string(_("Target panic")));
424                         return false;
425                 }
426                 
427                 // If we have a callback that we need
428                 // to report to, do so now.
429                 if(callback)
430                         if( callback->amount_complete(y,h) == false )
431                         {
432                                 // If the callback returns false,
433                                 // then the render has been aborted.
434                                 // Exit gracefuly.
435
436                                 target->end_scanline();
437                                 target->end_frame();
438                                 delete [] render_thread;
439                                 return false;
440                         }
441                                 
442                 read(render_thread[y%threads].pipe_read,colordata,w*sizeof(Color));
443                 
444                 // Send the buffer to the render target.
445                 // If anything goes wrong, cleanup and bail.
446                 if(!target->end_scanline())
447                 {
448                         delete [] render_thread;
449                         if(callback)callback->error(_("Target panic"));
450                         else throw(string(_("Target panic")));
451                         return false;
452                 }
453     }
454
455         // Finish up the target's frame
456         target->end_frame();
457
458         // Give the callback one more last call,
459         // this time with the full height as the
460         // current line
461         if(callback)
462                 callback->amount_complete(h,h);
463     
464     delete [] render_thread;
465     return true;
466
467 renderthread:
468         
469         // Change the random seed, so that each thread has a different one
470         srand(mythread*20+threads+time(0));
471         
472         Color *buffer(new Color[w]);
473
474         // Loop through all horizontal lines
475         for(y=mythread,v=sv+dv*(Real)mythread;y<h;y+=threads,v+=dv*(Real)threads)
476         {
477                 // Set the current pixel pointer
478                 // to the start of the line
479                 Color* colordata(buffer);
480                 
481                 // Loop through every pixel in row
482                 for(x=0,u=su;x<w;x++,u+=du)
483                 {
484                         Color &c(*(colordata++));
485                         c=Color::alpha();
486
487                         // Loop through all subpixels
488                         for(y2=0,pool=0;y2<a;y2++)
489                                 for(x2=0;x2<a;x2++)
490                                 {
491                                         Color color=context.get_color(
492                                                 Point(
493                                                         u+(Point::value_type)(x2)*dsu,
494                                                         v+(Point::value_type)(y2)*dsv
495                                                         )
496                                                 );
497                                         if(!no_clamp)
498                                         {
499                                                 color=color.clamped();
500                                                 c+=color*color.get_a();
501                                                 pool+=color.get_a();
502                                         }
503                                         else
504                                         {
505                                                 c+=color*color.get_a();
506                                                 pool+=color.get_a();
507                                         }
508                                 }
509                         if(pool)
510                                 c/=pool;
511                 }
512                 
513                 // Send the buffer to the primary thread.
514                 write(render_thread[mythread].pipe_write,buffer,w*sizeof(Color));
515         }
516         
517         delete [] buffer;
518         
519     _exit(0);
520         return false;   
521 #else
522         return render(context, target, desc, callback);
523
524 #endif  
525 }