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