-/* === S Y N F I G ========================================================= */
-/*! \file surfacenew.cpp
-** \brief Template File
-**
-** $Id$
-**
-** \legal
-** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
-**
-** This package is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License as
-** published by the Free Software Foundation; either version 2 of
-** the License, or (at your option) any later version.
-**
-** This package is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-** General Public License for more details.
-** \endlegal
-*/
-/* ========================================================================= */
-
-/* === H E A D E R S ======================================================= */
-
-#ifdef USING_PCH
-# include "pch.h"
-#else
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "surfacenew.h"
-#include <ETL/ref_count>
-#include "mutex.h"
-
-#endif
-
-/* === U S I N G =========================================================== */
-
-using namespace std;
-using namespace etl;
-using namespace synfig;
-
-/* === M A C R O S ========================================================= */
-
-/* === G L O B A L S ======================================================= */
-
-/* === P R O C E D U R E S ================================================= */
-
-/* === C L A S S E S & S T R U C T S ======================================= */
-
-class SurfaceNew::ChannelData
-{
-private:
- etl::reference_counter ref_count_;
-
- float* data_;
- float* origin_;
-
- int w_,h_,stride_;
-
-public:
-
- RWLock rw_lock;
-
- ChannelData():
- is_defined_(false),
- data_(0),
- origin_(0),
- w_(0),
- h_(0)
- {
- }
-
- ~ChannelData()
- {
- if(ref_count_.unique())
- delete [] data_;
- }
-
- void set_wh(int w, int h)
- {
- w_=w;
- h_=h;
- stride_=w;
-
- if(data_&&ref_count_.is_unique())
- delete [] data_;
-
- ref_count.make_unique();
- data_=new float [w_*h_];
- origin_=data_;
- clear();
- }
-
- void crop(int x, int y, int w, int h)
- {
- origin_=origin+y*stride_+x;
- w_=w;
- h_=h;
- }
-
- int get_stride()const
- {
- return stride_;
- }
-
- void clear()
- {
- for(int i=0;i<h;i++)
- bzero(origin_+stride_*i,w_*sizeof(float));
- }
-
- void fill(float v)
- {
- float* ptr(get_data());
-
- for(int y=0;y<h;y++,ptr+=stride_)
- for(int i=0;i<w_;i++)
- ptr[i]=v;
- }
-
- float* get_data() { return origin_; }
-
- void make_unique()
- {
- if(!ref_count_.unique())
- {
- ref_count_.make_unique();
- float* old_data(origin_);
- int old_stride;
-
- data_=new float [w_*h_];
- origin_=data_;
- stride_=w_;
-
- for(int i=0;i<h;i++)
- memcpy(data_+i*stride_,old_data+i*old_stride,sizeof(float)*w_);
- }
- }
-}; // END of class ChannelData
-
-/* === M E T H O D S ======================================================= */
-
-SurfaceNew::SurfaceNew():
- w_(0),
- h_(0),
- color_system_(COLORSYS_RGB),
- premult_flag_(false)
-{
-}
-
-SurfaceNew~SurfaceNew()
-{
-}
-
-SurfaceNew::Handle
-SurfaceNew::create(int w, int h, ColorSystem sys=COLORSYS_RGB)
-{
- Handle ret(new SurfaceNew);
-
- ret.set_wh(w,h);
- ret.set_color_system(sys);
-
- return ret;
-}
-
-SurfaceNew::Handle
-SurfaceNew::create(const Surface&)
-{
- // ***WRITEME***
- return 0;
-}
-
-SurfaceNew::Handle
-SurfaceNew::create(HandleConst orig)
-{
- Lock lock(orig);
-
- Handle ret(new SurfaceNew);
-
- ret.w_=orig.w_;
- ret.h_=orig.h_;
- ret.color_system_=orig.color_system_;
- ret.premult_flag_=orig.premult_flag_;
- ret.channel_map_=orig.channel_map_;
-
- return ret;
-}
-
-Handle
-SurfaceNew::crop(HandleConst, int x, int y, int w, int h)
-{
- Lock lock(orig);
-
- Handle ret(new SurfaceNew);
-
- ret.w_=orig.w_;
- ret.h_=orig.h_;
- ret.color_system_=orig.color_system_;
- ret.premult_flag_=orig.premult_flag_;
- ret.channel_map_=orig.channel_map_;
-
- std::map<Channel,ChannelData>::iterator iter;
- for(iter=ret.channel_map_.begin();iter!=ret.channel_map_.end();++iter)
- iter->crop(x,y,w,h);
-
- return ret;
-}
-
-int
-SurfaceNew::get_w()const
-{
- return w_;
-}
-
-int
-SurfaceNew::get_h()const
-{
- return h_;
-}
-
-void
-SurfaceNew::set_wh(int w, int h)
-{
- if(w!=w_ || h!=h_)
- {
- w_=w;
- h_=h;
- channel_map_.clear();
- }
-}
-
-SurfaceNew::ColorSystem
-SurfaceNew::get_color_system()const
-{
- return color_system_;
-}
-
-void
-SurfaceNew::set_color_system(SurfaceNew::ColorSystem x)
-{
- color_system_=x;
-}
-
-Color
-SurfaceNew::get_color(int x, int y)const
-{
- // This operation is rather expensive, as it should be.
- // I want to discourage people from using it all over the place.
-
- Color ret(
- lock_channel_const(CHAN_R).get_value(x,y),
- lock_channel_const(CHAN_G).get_value(x,y),
- lock_channel_const(CHAN_B).get_value(x,y),
- lock_channel_const(CHAN_A).get_value(x,y)
- );
-
- if(get_premult())
- {
- ret=ret.demult_alpha();
- }
-
- return ret;
-}
-
-void
-SurfaceNew::lock()
-{
- mutex_.lock();
-}
-
-void
-SurfaceNew::unlock()
-{
- mutex_.unlock();
-}
-
-bool
-SurfaceNew::trylock()
-{
- return mutex_.trylock();
-}
-
-SurfaceNew::ChannelLock
-SurfaceNew::lock_channel(SurfaceNew::Channel chan)
-{
- if(!is_channel_defined(chan)
- channel_map_[chan].set_wh(get_w(),get_h());
- else
- channel_map_[chan].make_unique();
-
- ChannelLockConst channel_lock;
-
- channel_lock.surface_=this;
- channel_lock.channel_=chan;
-
- channel_map_[chan].rw_lock.writer_lock();
-
- return channel_lock;
-}
-
-SurfaceNew::ChannelLockConst
-SurfaceNew::lock_channel_const(SurfaceNew::Channel chan)const
-{
- if(!is_channel_defined(chan)
- channel_map_[chan].set_wh(get_w(),get_h());
-
- ChannelLockConst channel_lock;
-
- channel_lock.surface_=this;
- channel_lock.channel_=chan;
-
- channel_map_[chan].rw_lock.reader_lock();
-
- return channel_lock;
-}
-
-SurfaceNew::ChannelLock
-SurfaceNew::lock_channel_alpha(SurfaceNew::Channel chan)
-{
- // Change this when per-channel alpha
- // is implemented
- return lock_channel(CHAN_A);
-}
-
-SurfaceNew::ChannelLockConst
-SurfaceNew::lock_channel_alpha_const(SurfaceNew::Channel chan)const
-{
- // Change this when per-channel alpha
- // is implemented
- return lock_channel_const(CHAN_A);
-}
-
-bool
-SurfaceNew::is_channel_defined(Channel chan)const
-{
- return channel_map_.count(chan);
-}
-
-bool
-SurfaceNew::get_premult()const
-{
- return premult_flag_;
-}
-
-void
-SurfaceNew::set_premult(bool x)
-{
- if(x==premult_flag_)
- return;
-
- premult_flag_=x;
-
- for(int i=0;i<3;i++)
- {
- Channel chan;
- if(get_color_system()==COLORSYS_RGB)switch(i)
- {
- case 0: chan=CHAN_R;
- case 1: chan=CHAN_G;
- case 2: chan=CHAN_B;
- }
- else
- if(get_color_system()==COLORSYS_YUV)switch(i)
- {
- case 0: chan=CHAN_Y;
- case 1: chan=CHAN_U;
- case 2: chan=CHAN_V;
- }
-
- // If this channel isn't defined, then
- // skip it and move on to the next one
- if(!is_channel_defined(chan))
- continue;
-
- ChannelLock color_channel(lock_channel(chan));
- ChannelLockConst alpha_channel(lock_channel_alpha_const(chan));
- const int w(get_w());
- const int h(get_h());
-
- float* color_ptr(color_channel.get_data_ptr());
- const float* alpha_ptr(alpha_channel.get_data_ptr());
-
- const int color_pitch(color_channel.get_data_ptr_stride()-w);
- const int alpha_pitch(alpha_channel.get_data_ptr_stride()-w);
-
- if(premult_flag_)
- {
- for(int y=0;y<h;y++,color_ptr+=color_pitch,alpha_ptr+=alpha_pitch)
- for(int x=0;x<w;x++,color_ptr++,alpha_ptr++)
- *color_ptr *= *alpha_ptr;
- }
- else
- {
- for(int y=0;y<h;y++,color_ptr+=color_pitch,alpha_ptr+=alpha_pitch)
- for(int x=0;x<w;x++,color_ptr++,alpha_ptr++)
- *color_ptr /= *alpha_ptr;
- }
- }
-}
-
-void
-SurfaceNew::blit(
- Handle dest, int x_dest, int y_dest,
- HandleConst src, int x_src, int y_src, int w_src, int h_src,
- float amount=1.0, Color::BlendMethod bm=Color::BLEND_COMPOSITE
-)
-{
- blit(
- dest,
- x_dest,
- y_dest,
- crop(
- src,
- x,
- y,
- w,
- h
- ),
- amount,
- bm
- );
-}
-
-void
-SurfaceNew::blit(
- Handle dest, int x_dest, int y_dest,
- HandleConst src
- float amount=1.0, Color::BlendMethod bm=Color::BLEND_COMPOSITE
-)
-{
- int w(src->get_w()), h(src->get_h);
-
- // Clip
- {
- int x(0), y(0);
-
- if(x_dest+w>dest.get_w())
- w=dest.get_w()-x_dest;
- if(y_dest+h>dest.get_h())
- h=dest.get_h()-y_dest;
- if(x_dest<0)
- {
- x-=x_dest;
- w+=x_dest;
- }
- if(y_dest<0)
- {
- y-=y_dest;
- h+=y_dest;
- }
- src=crop(src,x,y,w,h);
- }
-
- dest=crop(dest,x_dest,y_dest,w,h);
-
- if(bm==Color::BLEND_STRAIGHT)
- {
- chan_mlt(dest,amount/(1.0-amount));
- chan_add(dest,src);
- chan_mlt(dest,(1.0-amount)/amount);
- }
-
- if(bm==Color::BLEND_COMPOSITE)
- {
-
- }
-}
-
-
-
-// -----------------------------------------------------------------------------------
-
-SurfaceChannelLockConst::SurfaceChannelLockConst():
- data_ptr_checked_out_(false)
-{
-}
-
-SurfaceChannelLockConst::~SurfaceChannelLockConst()
-{
- if(data_ptr_checked_out_)
- release_data_ptr();
-
- if(surface_ && ref_count_.is_unique())
- return surface->channel_map_[channel_].rw_lock.reader_unlock();
- surface=0;
-}
-
-SurfaceChannel
-SurfaceChannelLockConst::get_channel()const
-{
- return channel_;
-}
-
-int
-SurfaceChannelLockConst::get_w()const
-{
- return surface_->get_w();
-}
-
-int
-SurfaceChannelLockConst::get_h()const
-{
- return surface_->get_h();
-}
-
-float
-SurfaceChannelLockConst::get_value(int x, int y)
-{
- // WOW! CRAZY SLOW!
- const ChannelData& channel_data(surface_->channel_map_[channel_]);
- return *(channel_data.get_data()+y*channel_data.get_stride()+x);
-}
-
-const float*
-SurfaceChannelLockConst::get_data_ptr()const
-{
- data_ptr_checked_out_=true;
-
- // WOW! CRAZY SLOW!
- return surface_->channel_map_[channel_].get_data();
-}
-
-int
-SurfaceChannelLockConst::get_data_ptr_stride()const
-{
- return surface_->channel_map_[channel_].get_stride();
-}
-
-void
-SurfaceChannelLockConst::release_data_ptr()const
-{
- data_ptr_checked_out_=false;
-}
-
-SurfaceChannelLockConst::operator bool()const
-{
- return static_cast<bool>(surface_);
-}
-
-// -----------------------------------------------------------------------------------
-
-SurfaceChannelLock::SurfaceChannelLock()
-{
-}
-
-SurfaceChannelLock::~SurfaceChannelLock()
-{
- if(data_ptr_checked_out_)
- release_data_ptr();
-
- if(surface_ && ref_count_.is_unique())
- return surface_->channel_map_[channel_].rw_lock.writer_unlock();
- surface=0;
-}
-
-void
-SurfaceChannelLock::clear()
-{
- return surface_->channel_map_[channel_].clear();
-}
-
-void
-SurfaceChannelLock::fill(float v)
-{
- return surface_->channel_map_[channel_].fill(v);
-}
-
-void
-SurfaceChannelLock::set_value(int x, int y, float v)
-{
- // WOW! CRAZY SLOW!
- const ChannelData& channel_data(surface_->channel_map_[channel_]);
- *(channel_data.get_data()+y*channel_data.get_stride()+x)=v;
-}
-
-float*
-SurfaceChannelLock::get_data_ptr()
-{
- data_ptr_checked_out_=true;
-
- // WOW! CRAZY SLOW!
- return surface_->channel_map_[channel_].get_data();
-}
-
-
-
-// -----------------------------------------------------------------------------------
-
-
-
-void
-SurfaceNew::chan_mlt(ChannelLock& dest, float x)
-{
- float* ptr(dest.get_data_ptr());
- const int w(dest.get_w());
- const int h(dest.get_h());
- const int pitch(dest.get_data_pitch()-w);
-
- int(y=0;y<h;y++,ptr+=pitch)
- int(x=0;x<w;x++,ptr++)
- *ptr*=x;
-}
-
-void
-SurfaceNew::chan_mlt(ChannelLock& dest, const ChannelLockConst& x)
-{
- float* d_ptr(dest.get_data_ptr());
- const float* s_ptr(x.get_data_ptr());
- const int w(dest.get_w());
- const int h(dest.get_h());
- const int d_pitch(dest.get_data_stride()-w);
- const int s_pitch(x.get_data_stride()-w);
-
- int(y=0;y<h;y++,d_ptr+=d_pitch,s_ptr+=s_pitch)
- int(x=0;x<w;x++,d_ptr++,s_ptr++)
- *d_ptr *= *s_ptr;
-}
-
-void
-SurfaceNew::chan_div(ChannelLock& dest, float x)
-{
- float* ptr(dest.get_data_ptr());
- const int w(dest.get_w());
- const int h(dest.get_h());
- const int pitch(dest.get_data_pitch()-w);
-
- int(y=0;y<h;y++,ptr+=pitch)
- int(x=0;x<w;x++,ptr++)
- *ptr/=x;
-}
-
-void
-SurfaceNew::chan_div(ChannelLock& dest, const ChannelLockConst& x)
-{
- float* d_ptr(dest.get_data_ptr());
- const float* s_ptr(x.get_data_ptr());
- const int w(dest.get_w());
- const int h(dest.get_h());
- const int d_pitch(dest.get_data_stride()-w);
- const int s_pitch(x.get_data_stride()-w);
-
- int(y=0;y<h;y++,d_ptr+=d_pitch,s_ptr+=s_pitch)
- int(x=0;x<w;x++,d_ptr++,s_ptr++)
- *d_ptr /= *s_ptr;
-}
-
-void
-SurfaceNew::chan_add(ChannelLock& dest, float x)
-{
- float* ptr(dest.get_data_ptr());
- const int w(dest.get_w());
- const int h(dest.get_h());
- const int pitch(dest.get_data_pitch()-w);
-
- int(y=0;y<h;y++,ptr+=pitch)
- int(x=0;x<w;x++,ptr++)
- *ptr+=x;
-}
-
-void
-SurfaceNew::chan_add(ChannelLock& dest, const ChannelLockConst& x)
-{
- float* d_ptr(dest.get_data_ptr());
- const float* s_ptr(x.get_data_ptr());
- const int w(dest.get_w());
- const int h(dest.get_h());
- const int d_pitch(dest.get_data_stride()-w);
- const int s_pitch(x.get_data_stride()-w);
-
- int(y=0;y<h;y++,d_ptr+=d_pitch,s_ptr+=s_pitch)
- int(x=0;x<w;x++,d_ptr++,s_ptr++)
- *d_ptr += *s_ptr;
-}
-
-void
-SurfaceNew::chan_sub(ChannelLock& dest, float x)
-{
- float* ptr(dest.get_data_ptr());
- const int w(dest.get_w());
- const int h(dest.get_h());
- const int pitch(dest.get_data_pitch()-w);
-
- int(y=0;y<h;y++,ptr+=pitch)
- int(x=0;x<w;x++,ptr++)
- *ptr-=x;
-}
-
-void
-SurfaceNew::chan_sub(ChannelLock& dest, const ChannelLockConst& x)
-{
- float* d_ptr(dest.get_data_ptr());
- const float* s_ptr(x.get_data_ptr());
- const int w(dest.get_w());
- const int h(dest.get_h());
- const int d_pitch(dest.get_data_stride()-w);
- const int s_pitch(x.get_data_stride()-w);
-
- int(y=0;y<h;y++,d_ptr+=d_pitch,s_ptr+=s_pitch)
- int(x=0;x<w;x++,d_ptr++,s_ptr++)
- *d_ptr -= *s_ptr;
-}
-
-
-