1 /* === S Y N F I G ========================================================= */
2 /*! \file surfacenew.cpp
3 ** \brief Template File
5 ** $Id: surfacenew.cpp,v 1.1 2005/01/21 19:29:10 darco Exp $
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
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.
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.
21 /* ========================================================================= */
23 /* === H E A D E R S ======================================================= */
32 #include "surfacenew.h"
33 #include <ETL/ref_count>
38 /* === U S I N G =========================================================== */
42 using namespace synfig;
44 /* === M A C R O S ========================================================= */
46 /* === G L O B A L S ======================================================= */
48 /* === P R O C E D U R E S ================================================= */
50 /* === C L A S S E S & S T R U C T S ======================================= */
52 class SurfaceNew::ChannelData
55 etl::reference_counter ref_count_;
77 if(ref_count_.unique())
81 void set_wh(int w, int h)
87 if(data_&&ref_count_.is_unique())
90 ref_count.make_unique();
91 data_=new float [w_*h_];
96 void crop(int x, int y, int w, int h)
98 origin_=origin+y*stride_+x;
103 int get_stride()const
111 bzero(origin_+stride_*i,w_*sizeof(float));
116 float* ptr(get_data());
118 for(int y=0;y<h;y++,ptr+=stride_)
119 for(int i=0;i<w_;i++)
123 float* get_data() { return origin_; }
127 if(!ref_count_.unique())
129 ref_count_.make_unique();
130 float* old_data(origin_);
133 data_=new float [w_*h_];
138 memcpy(data_+i*stride_,old_data+i*old_stride,sizeof(float)*w_);
141 }; // END of class ChannelData
143 /* === M E T H O D S ======================================================= */
145 SurfaceNew::SurfaceNew():
148 color_system_(COLORSYS_RGB),
153 SurfaceNew~SurfaceNew()
158 SurfaceNew::create(int w, int h, ColorSystem sys=COLORSYS_RGB)
160 Handle ret(new SurfaceNew);
163 ret.set_color_system(sys);
169 SurfaceNew::create(const Surface&)
176 SurfaceNew::create(HandleConst orig)
180 Handle ret(new SurfaceNew);
184 ret.color_system_=orig.color_system_;
185 ret.premult_flag_=orig.premult_flag_;
186 ret.channel_map_=orig.channel_map_;
192 SurfaceNew::crop(HandleConst, int x, int y, int w, int h)
196 Handle ret(new SurfaceNew);
200 ret.color_system_=orig.color_system_;
201 ret.premult_flag_=orig.premult_flag_;
202 ret.channel_map_=orig.channel_map_;
204 std::map<Channel,ChannelData>::iterator iter;
205 for(iter=ret.channel_map_.begin();iter!=ret.channel_map_.end();++iter)
212 SurfaceNew::get_w()const
218 SurfaceNew::get_h()const
224 SurfaceNew::set_wh(int w, int h)
230 channel_map_.clear();
234 SurfaceNew::ColorSystem
235 SurfaceNew::get_color_system()const
237 return color_system_;
241 SurfaceNew::set_color_system(SurfaceNew::ColorSystem x)
247 SurfaceNew::get_color(int x, int y)const
249 // This operation is rather expensive, as it should be.
250 // I want to discurage people from using it all over the place.
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)
261 ret=ret.demult_alpha();
280 SurfaceNew::trylock()
282 return mutex_.trylock();
285 SurfaceNew::ChannelLock
286 SurfaceNew::lock_channel(SurfaceNew::Channel chan)
288 if(!is_channel_defined(chan)
289 channel_map_[chan].set_wh(get_w(),get_h());
291 channel_map_[chan].make_unique();
293 ChannelLockConst channel_lock;
295 channel_lock.surface_=this;
296 channel_lock.channel_=chan;
298 channel_map_[chan].rw_lock.writer_lock();
303 SurfaceNew::ChannelLockConst
304 SurfaceNew::lock_channel_const(SurfaceNew::Channel chan)const
306 if(!is_channel_defined(chan)
307 channel_map_[chan].set_wh(get_w(),get_h());
309 ChannelLockConst channel_lock;
311 channel_lock.surface_=this;
312 channel_lock.channel_=chan;
314 channel_map_[chan].rw_lock.reader_lock();
319 SurfaceNew::ChannelLock
320 SurfaceNew::lock_channel_alpha(SurfaceNew::Channel chan)
322 // Change this when per-channel alpha
324 return lock_channel(CHAN_A);
327 SurfaceNew::ChannelLockConst
328 SurfaceNew::lock_channel_alpha_const(SurfaceNew::Channel chan)const
330 // Change this when per-channel alpha
332 return lock_channel_const(CHAN_A);
336 SurfaceNew::is_channel_defined(Channel chan)const
338 return channel_map_.count(chan);
342 SurfaceNew::get_premult()const
344 return premult_flag_;
348 SurfaceNew::set_premult(bool x)
358 if(get_color_system()==COLORSYS_RGB)switch(i)
365 if(get_color_system()==COLORSYS_YUV)switch(i)
372 // If this channel isn't defined, then
373 // skip it and move on to the next one
374 if(!is_channel_defined(chan))
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());
382 float* color_ptr(color_channel.get_data_ptr());
383 const float* alpha_ptr(alpha_channel.get_data_ptr());
385 const int color_pitch(color_channel.get_data_ptr_stride()-w);
386 const int alpha_pitch(alpha_channel.get_data_ptr_stride()-w);
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;
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;
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
428 Handle dest, int x_dest, int y_dest,
430 float amount=1.0, Color::BlendMethod bm=Color::BLEND_COMPOSITE
433 int w(src->get_w()), h(src->get_h);
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;
453 src=crop(src,x,y,w,h);
456 dest=crop(dest,x_dest,y_dest,w,h);
458 if(bm==Color::BLEND_STRAIGHT)
460 chan_mlt(dest,amount/(1.0-amount));
462 chan_mlt(dest,(1.0-amount)/amount);
465 if(bm==Color::BLEND_COMPOSITE)
473 // -----------------------------------------------------------------------------------
475 SurfaceChannelLockConst::SurfaceChannelLockConst():
476 data_ptr_checked_out_(false)
480 SurfaceChannelLockConst::~SurfaceChannelLockConst()
482 if(data_ptr_checked_out_)
485 if(surface_ && ref_count_.is_unique())
486 return surface->channel_map_[channel_].rw_lock.reader_unlock();
491 SurfaceChannelLockConst::get_channel()const
497 SurfaceChannelLockConst::get_w()const
499 return surface_->get_w();
503 SurfaceChannelLockConst::get_h()const
505 return surface_->get_h();
509 SurfaceChannelLockConst::get_value(int x, int y)
512 const ChannelData& channel_data(surface_->channel_map_[channel_]);
513 return *(channel_data.get_data()+y*channel_data.get_stride()+x);
517 SurfaceChannelLockConst::get_data_ptr()const
519 data_ptr_checked_out_=true;
522 return surface_->channel_map_[channel_].get_data();
526 SurfaceChannelLockConst::get_data_ptr_stride()const
528 return surface_->channel_map_[channel_].get_stride();
532 SurfaceChannelLockConst::release_data_ptr()const
534 data_ptr_checked_out_=false;
537 SurfaceChannelLockConst::operator bool()const
539 return static_cast<bool>(surface_);
542 // -----------------------------------------------------------------------------------
544 SurfaceChannelLock::SurfaceChannelLock()
548 SurfaceChannelLock::~SurfaceChannelLock()
550 if(data_ptr_checked_out_)
553 if(surface_ && ref_count_.is_unique())
554 return surface_->channel_map_[channel_].rw_lock.writer_unlock();
559 SurfaceChannelLock::clear()
561 return surface_->channel_map_[channel_].clear();
565 SurfaceChannelLock::fill(float v)
567 return surface_->channel_map_[channel_].fill(v);
571 SurfaceChannelLock::set_value(int x, int y, float v)
574 const ChannelData& channel_data(surface_->channel_map_[channel_]);
575 *(channel_data.get_data()+y*channel_data.get_stride()+x)=v;
579 SurfaceChannelLock::get_data_ptr()
581 data_ptr_checked_out_=true;
584 return surface_->channel_map_[channel_].get_data();
589 // -----------------------------------------------------------------------------------
594 SurfaceNew::chan_mlt(ChannelLock& dest, float x)
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);
601 int(y=0;y<h;y++,ptr+=pitch)
602 int(x=0;x<w;x++,ptr++)
607 SurfaceNew::chan_mlt(ChannelLock& dest, const ChannelLockConst& x)
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);
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++)
622 SurfaceNew::chan_div(ChannelLock& dest, float x)
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);
629 int(y=0;y<h;y++,ptr+=pitch)
630 int(x=0;x<w;x++,ptr++)
635 SurfaceNew::chan_div(ChannelLock& dest, const ChannelLockConst& x)
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);
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++)
650 SurfaceNew::chan_add(ChannelLock& dest, float x)
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);
657 int(y=0;y<h;y++,ptr+=pitch)
658 int(x=0;x<w;x++,ptr++)
663 SurfaceNew::chan_add(ChannelLock& dest, const ChannelLockConst& x)
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);
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++)
678 SurfaceNew::chan_sub(ChannelLock& dest, float x)
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);
685 int(y=0;y<h;y++,ptr+=pitch)
686 int(x=0;x<w;x++,ptr++)
691 SurfaceNew::chan_sub(ChannelLock& dest, const ChannelLockConst& x)
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);
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++)