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