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