include/cinder/Channel.h
Go to the documentation of this file.
00001 /*
00002  Copyright (c) 2010, The Cinder Project, All rights reserved.
00003  This code is intended for use with the Cinder C++ library: http://libcinder.org
00004 
00005  Portions Copyright (c) 2010, The Barbarian Group
00006  All rights reserved.
00007 
00008  Redistribution and use in source and binary forms, with or without modification, are permitted provided that
00009  the following conditions are met:
00010 
00011     * Redistributions of source code must retain the above copyright notice, this list of conditions and
00012     the following disclaimer.
00013     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
00014     the following disclaimer in the documentation and/or other materials provided with the distribution.
00015 
00016  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
00017  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00018  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00019  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00020  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00021  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00022  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00023  POSSIBILITY OF SUCH DAMAGE.
00024 */
00025 
00026 #pragma once
00027 
00028 #include "cinder/Cinder.h"
00029 #include "cinder/Area.h"
00030 
00031 namespace cinder {
00032 
00033 typedef std::shared_ptr<class ImageSource> ImageSourceRef;
00034 
00036 template<typename T>
00037 class ChannelT {     
00038  protected:
00040     struct Obj {
00041         Obj( int32_t width, int32_t height );
00042         Obj( int32_t aWidth, int32_t aHeight, int32_t aRowBytes, uint8_t aIncrement, bool aOwnsData, T *aData );
00043         ~Obj();
00044             
00045         int32_t                     mWidth, mHeight, mRowBytes;
00046         T                           *mData;
00047         uint8_t                     mIncrement;
00048         bool                        mOwnsData;
00049         
00050         void                        (*mDeallocatorFunc)(void *refcon);
00051         void                        *mDeallocatorRefcon;
00052     };
00054 
00055  public:
00057     ChannelT() {}
00059     ChannelT( int32_t width, int32_t height );
00061     ChannelT( int32_t width, int32_t height, int32_t rowBytes, uint8_t increment, T *data );
00063     ChannelT( ImageSourceRef imageSource );
00064 
00065     operator ImageSourceRef() const;
00066 
00068     ChannelT            clone( bool copyPixels = true ) const;
00070     ChannelT            clone( const Area &area, bool copyPixels = true ) const;
00071     
00073     int32_t     getWidth() const { return mObj->mWidth; }
00075     int32_t     getHeight() const { return mObj->mHeight; }
00077     Vec2i       getSize() const { return Vec2i( mObj->mWidth, mObj->mHeight ); }
00079     float       getAspectRatio() const { return mObj->mWidth / (float)mObj->mHeight; }
00081     Area        getBounds() const { return Area( 0, 0, mObj->mWidth, mObj->mHeight ); }
00083     int32_t     getRowBytes() const { return mObj->mRowBytes; }
00085     uint8_t     getIncrement() const { return mObj->mIncrement; }
00087     bool        isPlanar() const { return mObj->mIncrement == 1; }
00088 
00090     T*          getData() { return mObj->mData; }
00092     const T*    getData() const { return mObj->mData; }
00094     T*          getData( const Vec2i &offset ) { return reinterpret_cast<T*>( reinterpret_cast<unsigned char*>( mObj->mData + offset.x * mObj->mIncrement ) + offset.y * mObj->mRowBytes ); }
00096     const T*    getData( const Vec2i &offset ) const { return reinterpret_cast<T*>( reinterpret_cast<unsigned char*>( mObj->mData + offset.x * mObj->mIncrement ) + offset.y * mObj->mRowBytes ); }
00098     T*          getData( int32_t x, int32_t y ) { return reinterpret_cast<T*>( reinterpret_cast<unsigned char*>( mObj->mData + x * mObj->mIncrement ) + y * mObj->mRowBytes ); }
00100     const T*    getData( int32_t x, int32_t y ) const { return reinterpret_cast<T*>( reinterpret_cast<unsigned char*>( mObj->mData + x * mObj->mIncrement ) + y * mObj->mRowBytes ); }
00101 
00103     T       getValue ( Vec2i pos ) const { pos.x = constrain<int32_t>( pos.x, 0, mObj->mWidth - 1); pos.y = constrain<int32_t>( pos.y, 0, mObj->mHeight - 1 ); return *getData( pos ); }
00105     void    setValue( Vec2i pos, T v ) { pos.x = constrain<int32_t>( pos.x, 0, mObj->mWidth - 1); pos.y = constrain<int32_t>( pos.y, 0, mObj->mHeight - 1 ); *getData( pos ) = v; }
00106 
00108     void        copyFrom( const ChannelT<T> &srcChannel, const Area &srcArea, const Vec2i &relativeOffset = Vec2i::zero() );
00109 
00111     T           areaAverage( const Area &area ) const;
00112 
00114     void        setDeallocator( void(*aDeallocatorFunc)( void * ), void *aDeallocatorRefcon );
00115     
00117     typedef std::shared_ptr<Obj> ChannelT::*unspecified_bool_type;
00118     operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &ChannelT::mObj; }
00119     void reset() { mObj.reset(); }
00121 
00123     class Iter {
00124      public:
00125         Iter( ChannelT<T> &channelT, const Area &area ) 
00126             : mInc( channelT.getIncrement() ), mRowInc( channelT.getRowBytes() )
00127         {
00128             Area clippedArea( area.getClipBy( channelT.getBounds() ) );
00129             mWidth = clippedArea.getWidth();
00130             mHeight = clippedArea.getHeight();
00131             mLinePtr = reinterpret_cast<uint8_t*>( channelT.getData( clippedArea.getUL() ) );
00132             mPtr = reinterpret_cast<T*>( mLinePtr );
00133             mStartX = mX = clippedArea.getX1();
00134             mStartY = mY = clippedArea.getY1();         
00135             mEndX = clippedArea.getX2();
00136             mEndY = clippedArea.getY2();
00137             // in order to be at the right place after an initial call to line(), we need to back up one line
00138             mY = clippedArea.getY1() - 1;
00139             mLinePtr -= mRowInc;
00140         }
00141 
00143         T&      v() const { return *mPtr; }
00145         T&      v( int32_t xOff, int32_t yOff ) const { return mPtr[xOff * mInc + yOff * mRowInc]; }
00147         T&      vClamped( int32_t xOff, int32_t yOff ) const
00148                         {   xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY;
00149                             return *(T*)((uint8_t*)( mPtr + xOff * mInc ) + yOff * mRowInc); }
00150 
00152         const int32_t   x() const { return mX; }
00154         const int32_t   y() const { return mY; }
00156         Vec2i           getPos() const { return Vec2i( mX, mY ); }
00157 
00159         bool pixel() {
00160             ++mX;
00161             mPtr += mInc;
00162             return mX < mEndX;
00163         }
00164     
00166         bool line() {
00167             ++mY;
00168             mLinePtr += mRowInc;
00169             mPtr = reinterpret_cast<T*>( mLinePtr );
00170             // in order to be at the right place after an initial call to pixel(), we need to back up one pixel
00171             mPtr -= mInc;
00172             mX = mStartX - 1;
00173             return mY < mEndY;
00174         }
00175         
00177         int32_t     getWidth() { return mWidth; }
00179         int32_t     getHeight() { return mHeight; }
00180 
00182         uint8_t             mInc;
00183         uint8_t             *mLinePtr;
00184         T                   *mPtr;
00185         int32_t             mRowInc, mWidth, mHeight;
00186         int32_t             mX, mY, mStartX, mStartY, mEndX, mEndY;
00188     };
00189 
00191     class ConstIter {
00192      public:
00193         ConstIter( const ChannelT<T> &channelT, const Area &area ) 
00194             : mInc( channelT.getIncrement() ), mRowInc( channelT.getRowBytes() )
00195         {
00196             Area clippedArea( area.getClipBy( channelT.getBounds() ) );
00197             mWidth = clippedArea.getWidth();
00198             mHeight = clippedArea.getHeight();
00199             mLinePtr = reinterpret_cast<const uint8_t*>( channelT.getData( clippedArea.getUL() ) );
00200             mPtr = reinterpret_cast<const T*>( mLinePtr );
00201             mStartX = mX = clippedArea.getX1();
00202             mStartY = mY = clippedArea.getY1();         
00203             mEndX = clippedArea.getX2();
00204             mEndY = clippedArea.getY2();
00205             // in order to be at the right place after an initial call to line(), we need to back up one line
00206             mY = clippedArea.getY1() - 1;
00207             mLinePtr -= mRowInc;
00208         }
00209 
00211         const T&    v() const { return *mPtr; }
00213         const T&    v( int32_t xOff, int32_t yOff ) const { return mPtr[xOff * mInc + yOff * mRowInc]; }
00215         const T&    vClamped( int32_t xOff, int32_t yOff ) const
00216                         {   xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY;
00217                             return *(T*)((uint8_t*)( mPtr + xOff * mInc ) + yOff * mRowInc); }
00218 
00220         const int32_t   x() const { return mX; }
00222         const int32_t   y() const { return mY; }
00224         Vec2i           getPos() const { return Vec2i( mX, mY ); }
00225 
00227         bool pixel() {
00228             ++mX;
00229             mPtr += mInc;
00230             return mX < mEndX;
00231         }
00232 
00234         bool line() {
00235             ++mY;
00236             mLinePtr += mRowInc;
00237             mPtr = reinterpret_cast<const T*>( mLinePtr );
00238             // in order to be at the right place after an initial call to pixel(), we need to back up one pixel
00239             mPtr -= mInc;
00240             mX = mStartX - 1;
00241             return mY < mEndY;
00242         }
00243 
00245         int32_t     getWidth() { return mWidth; }
00247         int32_t     getHeight() { return mHeight; }
00248 
00250         uint8_t             mInc;
00251         const uint8_t       *mLinePtr;
00252         const T             *mPtr;
00253         int32_t             mRowInc, mWidth, mHeight;
00254         int32_t             mX, mY, mStartX, mStartY, mEndX, mEndY;
00256     };
00257 
00259     Iter        getIter() { return Iter( *this, this->getBounds() ); }
00261     Iter        getIter( const Area &area ) { return Iter( *this, area ); }
00263     ConstIter   getIter() const { return ConstIter( *this, this->getBounds() ); }
00265     ConstIter   getIter( const Area &area ) const { return ConstIter( *this, area ); }
00266     
00267   protected:
00268     std::shared_ptr<Obj>        mObj;
00269 };
00270 
00271 
00273 typedef ChannelT<uint8_t>   Channel;
00275 typedef ChannelT<uint8_t>   Channel8u;
00277 typedef ChannelT<uint16_t>  Channel16u;
00279 typedef ChannelT<float>     Channel32f;
00280 
00281 } // namespace cinder