00001 /* 00002 Copyright (c) 2010, The Barbarian Group 00003 All rights reserved. 00004 00005 Redistribution and use in source and binary forms, with or without modification, are permitted provided that 00006 the following conditions are met: 00007 00008 * Redistributions of source code must retain the above copyright notice, this list of conditions and 00009 the following disclaimer. 00010 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 00011 the following disclaimer in the documentation and/or other materials provided with the distribution. 00012 00013 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 00014 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 00015 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 00016 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00017 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00018 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00019 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00020 POSSIBILITY OF SUCH DAMAGE. 00021 */ 00022 00023 #pragma once 00024 00025 #include "cinder/Cinder.h" 00026 #include "cinder/Area.h" 00027 00028 namespace cinder { 00029 00030 typedef shared_ptr<class ImageSource> ImageSourceRef; 00031 00032 template<typename T> 00033 class ChannelT { 00034 protected: 00035 struct Obj { 00036 Obj( int32_t width, int32_t height ); 00037 Obj( int32_t aWidth, int32_t aHeight, int32_t aRowBytes, uint8_t aIncrement, bool aOwnsData, T *aData ); 00038 ~Obj(); 00039 00040 int32_t mWidth, mHeight, mRowBytes; 00041 T *mData; 00042 uint8_t mIncrement; 00043 bool mOwnsData; 00044 00045 void (*mDeallocatorFunc)(void *refcon); 00046 void *mDeallocatorRefcon; 00047 }; 00048 00049 public: 00051 ChannelT() {} 00053 ChannelT( int32_t width, int32_t height ); 00055 ChannelT( int32_t width, int32_t height, int32_t rowBytes, uint8_t increment, T *data ); 00057 ChannelT( ImageSourceRef imageSource ); 00058 00059 operator ImageSourceRef() const; 00060 00062 ChannelT clone( bool copyPixels = true ) const; 00064 ChannelT clone( const Area &area, bool copyPixels = true ) const; 00065 00067 int32_t getWidth() const { return mObj->mWidth; } 00069 int32_t getHeight() const { return mObj->mHeight; } 00071 Vec2i getSize() const { return Vec2i( mObj->mWidth, mObj->mHeight ); } 00073 float getAspectRatio() const { return mObj->mWidth / (float)mObj->mHeight; } 00075 Area getBounds() const { return Area( 0, 0, mObj->mWidth, mObj->mHeight ); } 00077 int32_t getRowBytes() const { return mObj->mRowBytes; } 00079 uint8_t getIncrement() const { return mObj->mIncrement; } 00081 bool isPlanar() const { return mObj->mIncrement == 1; } 00082 00083 T* getData() { return mObj->mData; } 00084 const T* getData() const { return mObj->mData; } 00085 T* getData( const Vec2i &offset ) { return reinterpret_cast<T*>( reinterpret_cast<unsigned char*>( mObj->mData + offset.x * mObj->mIncrement ) + offset.y * mObj->mRowBytes ); } 00086 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 ); } 00087 T* getData( int32_t x, int32_t y ) { return reinterpret_cast<T*>( reinterpret_cast<unsigned char*>( mObj->mData + x * mObj->mIncrement ) + y * mObj->mRowBytes ); } 00088 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 ); } 00089 00091 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 ); } 00093 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; } 00094 00095 void copyFrom( const ChannelT<T> &srcChannel, const Area &srcArea, const Vec2i &relativeOffset = Vec2i::zero() ); 00096 00097 T areaAverage( const Area &area ) const; 00098 00099 void setDeallocator( void(*aDeallocatorFunc)( void * ), void *aDeallocatorRefcon ); 00100 00102 00103 typedef typename shared_ptr<Obj>::unspecified_bool_type unspecified_bool_type; 00104 operator unspecified_bool_type() const { return static_cast<typename shared_ptr<Obj>::unspecified_bool_type>( mObj ); } 00105 void reset() { mObj.reset(); } 00107 00108 class Iter { 00109 public: 00110 Iter( ChannelT<T> &channelT, const Area &area ) 00111 : mInc( channelT.getIncrement() ), mRowInc( channelT.getRowBytes() ) 00112 { 00113 Area clippedArea( area.getClipBy( channelT.getBounds() ) ); 00114 mWidth = clippedArea.getWidth(); 00115 mHeight = clippedArea.getHeight(); 00116 mLinePtr = reinterpret_cast<uint8_t*>( channelT.getData( clippedArea.getUL() ) ); 00117 mPtr = reinterpret_cast<T*>( mLinePtr ); 00118 mStartX = mX = clippedArea.getX1(); 00119 mStartY = mY = clippedArea.getY1(); 00120 mEndX = clippedArea.getX2(); 00121 mEndY = clippedArea.getY2(); 00122 // in order to be at the right place after an initial call to line(), we need to back up one line 00123 mY = clippedArea.getY1() - 1; 00124 mLinePtr -= mRowInc; 00125 } 00126 00127 T& v() const { return *mPtr; } 00128 T& v( int32_t xOff, int32_t yOff ) const { return mPtr[xOff * mInc + yOff * mRowInc]; } 00129 T& vClamped ( int32_t xOff, int32_t yOff ) const 00130 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY; 00131 return mPtr[xOff * mInc + yOff * mRowInc]; } 00132 00133 const int32_t x() const { return mX; } 00134 const int32_t y() const { return mY; } 00135 Vec2i getPos() const { return Vec2i( mX, mY ); } 00136 00137 bool pixel() { 00138 ++mX; 00139 mPtr += mInc; 00140 return mX < mEndX; 00141 } 00142 00143 bool line() { 00144 ++mY; 00145 mLinePtr += mRowInc; 00146 mPtr = reinterpret_cast<T*>( mLinePtr ); 00147 // in order to be at the right place after an initial call to pixel(), we need to back up one pixel 00148 mPtr -= mInc; 00149 mX = mStartX - 1; 00150 return mY < mEndY; 00151 } 00152 00153 int32_t getWidth() { return mWidth; } 00154 int32_t getHeight() { return mHeight; } 00155 00156 uint8_t mInc; 00157 uint8_t *mLinePtr; 00158 T *mPtr; 00159 int32_t mRowInc, mWidth, mHeight; 00160 int32_t mX, mY, mStartX, mStartY, mEndX, mEndY; 00161 }; 00162 00163 class ConstIter { 00164 public: 00165 ConstIter( const ChannelT<T> &channelT, const Area &area ) 00166 : mInc( channelT.getIncrement() ), mRowInc( channelT.getRowBytes() ) 00167 { 00168 Area clippedArea( area.getClipBy( channelT.getBounds() ) ); 00169 mWidth = clippedArea.getWidth(); 00170 mHeight = clippedArea.getHeight(); 00171 mLinePtr = reinterpret_cast<const uint8_t*>( channelT.getData( clippedArea.getUL() ) ); 00172 mPtr = reinterpret_cast<const T*>( mLinePtr ); 00173 mStartX = mX = clippedArea.getX1(); 00174 mStartY = mY = clippedArea.getY1(); 00175 mEndX = clippedArea.getX2(); 00176 mEndY = clippedArea.getY2(); 00177 // in order to be at the right place after an initial call to line(), we need to back up one line 00178 mY = clippedArea.getY1() - 1; 00179 mLinePtr -= mRowInc; 00180 } 00181 00182 const T& v() const { return *mPtr; } 00183 const T& v( int32_t xOff, int32_t yOff ) const { return mPtr[xOff * mInc + yOff * mRowInc]; } 00184 const T& vClamped( int32_t xOff, int32_t yOff ) const 00185 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY; 00186 return mPtr[xOff * mInc + yOff * mRowInc]; } 00187 00188 const int32_t x() const { return mX; } 00189 const int32_t y() const { return mY; } 00190 Vec2i getPos() const { return Vec2i( mX, mY ); } 00191 00192 bool pixel() { 00193 ++mX; 00194 mPtr += mInc; 00195 return mX < mEndX; 00196 } 00197 00198 bool line() { 00199 ++mY; 00200 mLinePtr += mRowInc; 00201 mPtr = reinterpret_cast<const T*>( mLinePtr ); 00202 // in order to be at the right place after an initial call to pixel(), we need to back up one pixel 00203 mPtr -= mInc; 00204 mX = mStartX - 1; 00205 return mY < mEndY; 00206 } 00207 00208 int32_t getWidth() { return mWidth; } 00209 int32_t getHeight() { return mHeight; } 00210 00211 uint8_t mInc; 00212 const uint8_t *mLinePtr; 00213 const T *mPtr; 00214 int32_t mRowInc, mWidth, mHeight; 00215 int32_t mX, mY, mStartX, mStartY, mEndX, mEndY; 00216 }; 00217 00218 Iter getIter() { return Iter( *this, this->getBounds() ); } 00219 Iter getIter( const Area &area ) { return Iter( *this, area ); } 00220 ConstIter getIter() const { return ConstIter( *this, this->getBounds() ); } 00221 ConstIter getIter( const Area &area ) const { return ConstIter( *this, area ); } 00222 00223 protected: 00224 shared_ptr<Obj> mObj; 00225 }; 00226 00227 00228 typedef ChannelT<uint8_t> Channel; 00229 typedef ChannelT<uint8_t> Channel8u; 00230 typedef ChannelT<float> Channel32f; 00231 00232 } // namespace cinder