Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-core / tags / synfig_0_61_03 / synfig-core / src / synfig / surfacenew.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file surfacenew.cpp
3 **      \brief Template File
4 **
5 **      $Id: surfacenew.cpp,v 1.1 2005/01/21 19:29:10 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 "surfacenew.h"
33 #include <ETL/ref_count>
34 #include "mutex.h"
35
36 #endif
37
38 /* === U S I N G =========================================================== */
39
40 using namespace std;
41 using namespace etl;
42 using namespace synfig;
43
44 /* === M A C R O S ========================================================= */
45
46 /* === G L O B A L S ======================================================= */
47
48 /* === P R O C E D U R E S ================================================= */
49
50 /* === C L A S S E S & S T R U C T S ======================================= */
51
52 class SurfaceNew::ChannelData
53 {
54 private:
55         etl::reference_counter ref_count_;
56
57         float* data_;
58         float* origin_;
59         
60         int w_,h_,stride_;
61         
62 public:
63
64         RWLock rw_lock;
65
66         ChannelData():
67                 is_defined_(false),
68                 data_(0),
69                 origin_(0),
70                 w_(0),
71                 h_(0)
72         {
73         }
74         
75         ~ChannelData()
76         {
77                 if(ref_count_.unique())
78                         delete [] data_;
79         }
80         
81         void set_wh(int w, int h)
82         {
83                 w_=w;
84                 h_=h;
85                 stride_=w;
86                 
87                 if(data_&&ref_count_.is_unique())
88                         delete [] data_;
89                         
90                 ref_count.make_unique();
91                 data_=new float [w_*h_];
92                 origin_=data_;
93                 clear();
94         }
95         
96         void crop(int x, int y, int w, int h)
97         {
98                 origin_=origin+y*stride_+x;
99                 w_=w;
100                 h_=h;
101         }
102         
103         int get_stride()const
104         {
105                 return stride_;
106         }
107         
108         void clear()
109         {
110                 for(int i=0;i<h;i++)
111                         bzero(origin_+stride_*i,w_*sizeof(float));
112         }
113
114         void fill(float v)
115         {
116                 float* ptr(get_data());
117                 
118                 for(int y=0;y<h;y++,ptr+=stride_)
119                         for(int i=0;i<w_;i++)
120                                 ptr[i]=v;
121         }
122
123         float* get_data() { return origin_; }
124
125         void make_unique()
126         {
127                 if(!ref_count_.unique())
128                 {
129                         ref_count_.make_unique();
130                         float* old_data(origin_);
131                         int old_stride;
132                         
133                         data_=new float [w_*h_];
134                         origin_=data_;
135                         stride_=w_;
136                         
137                         for(int i=0;i<h;i++)
138                                 memcpy(data_+i*stride_,old_data+i*old_stride,sizeof(float)*w_);
139                 }
140         }
141 }; // END of class ChannelData
142
143 /* === M E T H O D S ======================================================= */
144
145 SurfaceNew::SurfaceNew():
146         w_(0),
147         h_(0),
148         color_system_(COLORSYS_RGB),
149         premult_flag_(false)
150 {
151 }
152
153 SurfaceNew~SurfaceNew()
154 {
155 }
156
157 SurfaceNew::Handle
158 SurfaceNew::create(int w, int h, ColorSystem sys=COLORSYS_RGB)
159 {
160         Handle ret(new SurfaceNew);
161         
162         ret.set_wh(w,h);
163         ret.set_color_system(sys);
164         
165         return ret;
166 }
167
168 SurfaceNew::Handle
169 SurfaceNew::create(const Surface&)
170 {
171         // ***WRITEME***
172         return 0;
173 }
174
175 SurfaceNew::Handle
176 SurfaceNew::create(HandleConst orig)
177 {
178         Lock lock(orig);
179         
180         Handle ret(new SurfaceNew);
181
182         ret.w_=orig.w_;
183         ret.h_=orig.h_;
184         ret.color_system_=orig.color_system_;
185         ret.premult_flag_=orig.premult_flag_;
186         ret.channel_map_=orig.channel_map_;
187         
188         return ret;
189 }
190
191 Handle
192 SurfaceNew::crop(HandleConst, int x, int y, int w, int h)
193 {
194         Lock lock(orig);
195         
196         Handle ret(new SurfaceNew);
197
198         ret.w_=orig.w_;
199         ret.h_=orig.h_;
200         ret.color_system_=orig.color_system_;
201         ret.premult_flag_=orig.premult_flag_;
202         ret.channel_map_=orig.channel_map_;
203
204         std::map<Channel,ChannelData>::iterator iter;
205         for(iter=ret.channel_map_.begin();iter!=ret.channel_map_.end();++iter)
206                 iter->crop(x,y,w,h);
207         
208         return ret;
209 }
210
211 int
212 SurfaceNew::get_w()const
213 {
214         return w_;
215 }
216         
217 int
218 SurfaceNew::get_h()const
219 {
220         return h_;
221 }
222         
223 void
224 SurfaceNew::set_wh(int w, int h)
225 {
226         if(w!=w_ || h!=h_)
227         {
228                 w_=w;
229                 h_=h;
230                 channel_map_.clear();
231         }
232 }
233
234 SurfaceNew::ColorSystem
235 SurfaceNew::get_color_system()const
236 {
237         return color_system_;
238 }
239
240 void
241 SurfaceNew::set_color_system(SurfaceNew::ColorSystem x)
242 {
243         color_system_=x;
244 }
245
246 Color
247 SurfaceNew::get_color(int x, int y)const
248 {
249         // This operation is rather expensive, as it should be.
250         // I want to discurage people from using it all over the place.
251         
252         Color ret(
253                 lock_channel_const(CHAN_R).get_value(x,y),
254                 lock_channel_const(CHAN_G).get_value(x,y),
255                 lock_channel_const(CHAN_B).get_value(x,y),
256                 lock_channel_const(CHAN_A).get_value(x,y)
257         );
258         
259         if(get_premult())
260         {
261                 ret=ret.demult_alpha();
262         }
263         
264         return ret;
265 }
266         
267 void
268 SurfaceNew::lock()
269 {
270         mutex_.lock();
271 }
272         
273 void
274 SurfaceNew::unlock()
275 {
276         mutex_.unlock();
277 }
278         
279 bool
280 SurfaceNew::trylock()
281 {
282         return mutex_.trylock();
283 }
284         
285 SurfaceNew::ChannelLock
286 SurfaceNew::lock_channel(SurfaceNew::Channel chan)
287 {
288         if(!is_channel_defined(chan)
289                 channel_map_[chan].set_wh(get_w(),get_h());
290         else
291                 channel_map_[chan].make_unique();
292
293         ChannelLockConst channel_lock;
294         
295         channel_lock.surface_=this;
296         channel_lock.channel_=chan;
297
298         channel_map_[chan].rw_lock.writer_lock();
299         
300         return channel_lock;
301 }
302
303 SurfaceNew::ChannelLockConst
304 SurfaceNew::lock_channel_const(SurfaceNew::Channel chan)const
305 {
306         if(!is_channel_defined(chan)
307                 channel_map_[chan].set_wh(get_w(),get_h());
308
309         ChannelLockConst channel_lock;
310         
311         channel_lock.surface_=this;
312         channel_lock.channel_=chan;
313
314         channel_map_[chan].rw_lock.reader_lock();
315         
316         return channel_lock;
317 }
318
319 SurfaceNew::ChannelLock
320 SurfaceNew::lock_channel_alpha(SurfaceNew::Channel chan)
321 {
322         // Change this when per-channel alpha
323         // is implemented
324         return lock_channel(CHAN_A);
325 }
326
327 SurfaceNew::ChannelLockConst
328 SurfaceNew::lock_channel_alpha_const(SurfaceNew::Channel chan)const
329 {
330         // Change this when per-channel alpha
331         // is implemented
332         return lock_channel_const(CHAN_A);
333 }
334
335 bool
336 SurfaceNew::is_channel_defined(Channel chan)const
337 {
338         return channel_map_.count(chan);
339 }
340
341 bool
342 SurfaceNew::get_premult()const
343 {
344         return premult_flag_;
345 }
346
347 void
348 SurfaceNew::set_premult(bool x)
349 {
350         if(x==premult_flag_)
351                 return;
352                 
353         premult_flag_=x;
354         
355         for(int i=0;i<3;i++)
356         {
357                 Channel chan;
358                 if(get_color_system()==COLORSYS_RGB)switch(i)
359                 {
360                         case 0: chan=CHAN_R;
361                         case 1: chan=CHAN_G;
362                         case 2: chan=CHAN_B;
363                 }
364                 else
365                 if(get_color_system()==COLORSYS_YUV)switch(i)
366                 {
367                         case 0: chan=CHAN_Y;
368                         case 1: chan=CHAN_U;
369                         case 2: chan=CHAN_V;
370                 }
371                 
372                 // If this channel isn't defined, then
373                 // skip it and move on to the next one
374                 if(!is_channel_defined(chan))
375                         continue;
376                         
377                 ChannelLock color_channel(lock_channel(chan));
378                 ChannelLockConst alpha_channel(lock_channel_alpha_const(chan));
379                 const int w(get_w());
380                 const int h(get_h());
381                 
382                 float* color_ptr(color_channel.get_data_ptr());
383                 const float* alpha_ptr(alpha_channel.get_data_ptr());
384                 
385                 const int color_pitch(color_channel.get_data_ptr_stride()-w);
386                 const int alpha_pitch(alpha_channel.get_data_ptr_stride()-w);
387                 
388                 if(premult_flag_)
389                 {
390                         for(int y=0;y<h;y++,color_ptr+=color_pitch,alpha_ptr+=alpha_pitch)
391                                 for(int x=0;x<w;x++,color_ptr++,alpha_ptr++)
392                                         *color_ptr *= *alpha_ptr;
393                 }
394                 else
395                 {
396                         for(int y=0;y<h;y++,color_ptr+=color_pitch,alpha_ptr+=alpha_pitch)
397                                 for(int x=0;x<w;x++,color_ptr++,alpha_ptr++)
398                                         *color_ptr /= *alpha_ptr;
399                 }
400         }
401 }
402
403 void
404 SurfaceNew::blit(
405         Handle dest, int x_dest, int y_dest,
406         HandleConst src, int x_src, int y_src, int w_src, int h_src,
407         float amount=1.0, Color::BlendMethod bm=Color::BLEND_COMPOSITE
408 )
409 {
410         blit(
411                 dest,
412                 x_dest,
413                 y_dest,
414                 crop(
415                         src,
416                         x,
417                         y,
418                         w,
419                         h
420                 ),
421                 amount,
422                 bm
423         );
424 }
425
426 void
427 SurfaceNew::blit(
428         Handle dest, int x_dest, int y_dest,
429         HandleConst src
430         float amount=1.0, Color::BlendMethod bm=Color::BLEND_COMPOSITE
431 )
432 {
433         int w(src->get_w()), h(src->get_h);
434         
435         // Clip
436         {
437                 int x(0), y(0);
438                 
439                 if(x_dest+w>dest.get_w())
440                         w=dest.get_w()-x_dest;
441                 if(y_dest+h>dest.get_h())
442                         h=dest.get_h()-y_dest;
443                 if(x_dest<0)
444                 {
445                         x-=x_dest;
446                         w+=x_dest;
447                 }
448                 if(y_dest<0)
449                 {
450                         y-=y_dest;
451                         h+=y_dest;
452                 }
453                 src=crop(src,x,y,w,h);
454         }
455         
456         dest=crop(dest,x_dest,y_dest,w,h);
457
458         if(bm==Color::BLEND_STRAIGHT)
459         {
460                 chan_mlt(dest,amount/(1.0-amount));
461                 chan_add(dest,src);
462                 chan_mlt(dest,(1.0-amount)/amount);
463         }
464         
465         if(bm==Color::BLEND_COMPOSITE)
466         {
467                 
468         }
469 }
470
471
472
473 // -----------------------------------------------------------------------------------
474
475 SurfaceChannelLockConst::SurfaceChannelLockConst():
476         data_ptr_checked_out_(false)
477 {
478 }
479
480 SurfaceChannelLockConst::~SurfaceChannelLockConst()
481 {
482         if(data_ptr_checked_out_)
483                 release_data_ptr();
484                 
485         if(surface_ && ref_count_.is_unique())
486                 return surface->channel_map_[channel_].rw_lock.reader_unlock();
487         surface=0;
488 }
489
490 SurfaceChannel
491 SurfaceChannelLockConst::get_channel()const
492 {
493         return channel_;
494 }
495
496 int
497 SurfaceChannelLockConst::get_w()const
498 {
499         return surface_->get_w();
500 }
501         
502 int
503 SurfaceChannelLockConst::get_h()const
504 {
505         return surface_->get_h();
506 }
507         
508 float
509 SurfaceChannelLockConst::get_value(int x, int y)
510 {
511         // WOW! CRAZY SLOW!
512         const ChannelData& channel_data(surface_->channel_map_[channel_]);
513         return *(channel_data.get_data()+y*channel_data.get_stride()+x);
514 }
515
516 const float*
517 SurfaceChannelLockConst::get_data_ptr()const
518 {
519         data_ptr_checked_out_=true;
520         
521         // WOW! CRAZY SLOW!
522         return surface_->channel_map_[channel_].get_data();
523 }
524
525 int
526 SurfaceChannelLockConst::get_data_ptr_stride()const
527 {
528         return surface_->channel_map_[channel_].get_stride();
529 }
530
531 void
532 SurfaceChannelLockConst::release_data_ptr()const
533 {
534         data_ptr_checked_out_=false;
535 }
536
537 SurfaceChannelLockConst::operator bool()const
538 {
539         return static_cast<bool>(surface_);
540 }
541
542 // -----------------------------------------------------------------------------------
543
544 SurfaceChannelLock::SurfaceChannelLock()
545 {
546 }
547
548 SurfaceChannelLock::~SurfaceChannelLock()
549 {
550         if(data_ptr_checked_out_)
551                 release_data_ptr();
552
553         if(surface_ && ref_count_.is_unique())
554                 return surface_->channel_map_[channel_].rw_lock.writer_unlock();
555         surface=0;
556 }
557
558 void
559 SurfaceChannelLock::clear()
560 {
561         return surface_->channel_map_[channel_].clear();
562 }
563
564 void
565 SurfaceChannelLock::fill(float v)
566 {
567         return surface_->channel_map_[channel_].fill(v);
568 }
569
570 void
571 SurfaceChannelLock::set_value(int x, int y, float v)
572 {
573         // WOW! CRAZY SLOW!
574         const ChannelData& channel_data(surface_->channel_map_[channel_]);
575         *(channel_data.get_data()+y*channel_data.get_stride()+x)=v;
576 }
577
578 float*
579 SurfaceChannelLock::get_data_ptr()
580 {
581         data_ptr_checked_out_=true;
582
583         // WOW! CRAZY SLOW!
584         return surface_->channel_map_[channel_].get_data();
585 }
586
587
588
589 // -----------------------------------------------------------------------------------
590
591
592
593 void
594 SurfaceNew::chan_mlt(ChannelLock& dest, float x)
595 {
596         float* ptr(dest.get_data_ptr());
597         const int w(dest.get_w());
598         const int h(dest.get_h());
599         const int pitch(dest.get_data_pitch()-w);
600         
601         int(y=0;y<h;y++,ptr+=pitch)
602                 int(x=0;x<w;x++,ptr++)
603                         *ptr*=x;
604 }
605
606 void
607 SurfaceNew::chan_mlt(ChannelLock& dest, const ChannelLockConst& x)
608 {
609         float* d_ptr(dest.get_data_ptr());
610         const float* s_ptr(x.get_data_ptr());
611         const int w(dest.get_w());
612         const int h(dest.get_h());
613         const int d_pitch(dest.get_data_stride()-w);
614         const int s_pitch(x.get_data_stride()-w);
615         
616         int(y=0;y<h;y++,d_ptr+=d_pitch,s_ptr+=s_pitch)
617                 int(x=0;x<w;x++,d_ptr++,s_ptr++)
618                         *d_ptr *= *s_ptr;
619 }
620
621 void
622 SurfaceNew::chan_div(ChannelLock& dest, float x)
623 {
624         float* ptr(dest.get_data_ptr());
625         const int w(dest.get_w());
626         const int h(dest.get_h());
627         const int pitch(dest.get_data_pitch()-w);
628         
629         int(y=0;y<h;y++,ptr+=pitch)
630                 int(x=0;x<w;x++,ptr++)
631                         *ptr/=x;
632 }
633
634 void
635 SurfaceNew::chan_div(ChannelLock& dest, const ChannelLockConst& x)
636 {
637         float* d_ptr(dest.get_data_ptr());
638         const float* s_ptr(x.get_data_ptr());
639         const int w(dest.get_w());
640         const int h(dest.get_h());
641         const int d_pitch(dest.get_data_stride()-w);
642         const int s_pitch(x.get_data_stride()-w);
643         
644         int(y=0;y<h;y++,d_ptr+=d_pitch,s_ptr+=s_pitch)
645                 int(x=0;x<w;x++,d_ptr++,s_ptr++)
646                         *d_ptr /= *s_ptr;
647 }
648
649 void
650 SurfaceNew::chan_add(ChannelLock& dest, float x)
651 {
652         float* ptr(dest.get_data_ptr());
653         const int w(dest.get_w());
654         const int h(dest.get_h());
655         const int pitch(dest.get_data_pitch()-w);
656         
657         int(y=0;y<h;y++,ptr+=pitch)
658                 int(x=0;x<w;x++,ptr++)
659                         *ptr+=x;
660 }
661
662 void
663 SurfaceNew::chan_add(ChannelLock& dest, const ChannelLockConst& x)
664 {
665         float* d_ptr(dest.get_data_ptr());
666         const float* s_ptr(x.get_data_ptr());
667         const int w(dest.get_w());
668         const int h(dest.get_h());
669         const int d_pitch(dest.get_data_stride()-w);
670         const int s_pitch(x.get_data_stride()-w);
671         
672         int(y=0;y<h;y++,d_ptr+=d_pitch,s_ptr+=s_pitch)
673                 int(x=0;x<w;x++,d_ptr++,s_ptr++)
674                         *d_ptr += *s_ptr;
675 }
676
677 void
678 SurfaceNew::chan_sub(ChannelLock& dest, float x)
679 {
680         float* ptr(dest.get_data_ptr());
681         const int w(dest.get_w());
682         const int h(dest.get_h());
683         const int pitch(dest.get_data_pitch()-w);
684         
685         int(y=0;y<h;y++,ptr+=pitch)
686                 int(x=0;x<w;x++,ptr++)
687                         *ptr-=x;
688 }
689
690 void
691 SurfaceNew::chan_sub(ChannelLock& dest, const ChannelLockConst& x)
692 {
693         float* d_ptr(dest.get_data_ptr());
694         const float* s_ptr(x.get_data_ptr());
695         const int w(dest.get_w());
696         const int h(dest.get_h());
697         const int d_pitch(dest.get_data_stride()-w);
698         const int s_pitch(x.get_data_stride()-w);
699         
700         int(y=0;y<h;y++,d_ptr+=d_pitch,s_ptr+=s_pitch)
701                 int(x=0;x<w;x++,d_ptr++,s_ptr++)
702                         *d_ptr -= *s_ptr;
703 }
704
705
706