00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #pragma once
00024
00025 #include "cinder/Cinder.h"
00026 #include "cinder/Area.h"
00027 #include "cinder/Channel.h"
00028 #include "cinder/ChanTraits.h"
00029 #include "cinder/Color.h"
00030
00031 #include <boost/logic/tribool.hpp>
00032
00033 namespace cinder {
00034
00035 class SurfaceChannelOrder {
00036 public:
00037 SurfaceChannelOrder() : mCode( UNSPECIFIED ), mRed( INVALID ), mGreen( INVALID ), mBlue( INVALID ), mAlpha( INVALID ), mPixelInc( INVALID ) {}
00038 SurfaceChannelOrder( int aCode );
00039 SurfaceChannelOrder( const SurfaceChannelOrder &aOrder );
00040
00041
00042
00043 uint8_t getRedOffset() const { return mRed; }
00044 uint8_t getGreenOffset() const { return mGreen; }
00045 uint8_t getBlueOffset() const { return mBlue; }
00046 uint8_t getAlphaOffset() const { return mAlpha; }
00047 bool hasAlpha() const { return ( mAlpha != INVALID ) ? true : false; }
00048 uint8_t getPixelInc() const { return mPixelInc; }
00049 int getCode() const { return mCode; }
00050
00051 bool operator==( const SurfaceChannelOrder& sco ) const
00052 {
00053 return mCode == sco.mCode;
00054 }
00055
00056 enum { CHAN_RED, CHAN_GREEN, CHAN_BLUE, CHAN_ALPHA, INVALID = 255 };
00057 enum { RGBA, BGRA, ARGB, ABGR, RGBX, BGRX, XRGB, XBGR, RGB, BGR, UNSPECIFIED };
00058
00059 int getImageIoChannelOrder() const;
00060
00061 private:
00062 void set( uint8_t aRed, uint8_t aGreen, uint8_t aBlue, uint8_t aAlpha, uint8_t aPixelInc );
00063 int mCode;
00064 uint8_t mRed, mGreen, mBlue, mAlpha, mPixelInc;
00065
00066 };
00067
00069 class SurfaceConstraints {
00070 public:
00071 virtual ~SurfaceConstraints() {}
00072
00073 virtual SurfaceChannelOrder getChannelOrder( bool alpha ) const { return ( alpha ) ? SurfaceChannelOrder::RGBA : SurfaceChannelOrder::RGB; }
00074 virtual int32_t getRowBytes( int requestedWidth, const SurfaceChannelOrder &sco, int elementSize ) const { return requestedWidth * elementSize * sco.getPixelInc(); }
00075 };
00076
00077 class SurfaceConstraintsDefault : public SurfaceConstraints {
00078 };
00079
00080 typedef shared_ptr<class ImageSource> ImageSourceRef;
00081
00082 template<typename T>
00083 class SurfaceT {
00084 private:
00086 struct Obj {
00087 Obj( int32_t aWidth, int32_t aHeight, SurfaceChannelOrder aChannelOrder, T *aData, bool aOwnsData, int32_t aRowBytes );
00088 ~Obj();
00089
00090 void initChannels();
00091 void setData( T *aData, int32_t aWidth, int32_t aHeight, int32_t aRowBytes );
00092 void setChannelOrder( const SurfaceChannelOrder &aChannelOrder );
00093 void setDeallocator( void(*aDeallocatorFunc)( void * ), void *aDeallocatorRefcon );
00094
00095 int32_t mWidth, mHeight, mRowBytes;
00096 bool mIsPremultiplied;
00097 T *mData;
00098 bool mOwnsData;
00099 SurfaceChannelOrder mChannelOrder;
00100 ChannelT<T> mChannels[4];
00101
00102 void (*mDeallocatorFunc)(void *refcon);
00103 void *mDeallocatorRefcon;
00104 };
00106
00107 public:
00108 SurfaceT() {}
00109 SurfaceT( int32_t aWidth, int32_t aHeight, bool alpha, SurfaceChannelOrder aChannelOrder = SurfaceChannelOrder::UNSPECIFIED );
00110 SurfaceT( int32_t aWidth, int32_t aHeight, bool alpha, const SurfaceConstraints &constraints );
00111 SurfaceT( T *aData, int32_t aWidth, int32_t aHeight, int32_t aRowBytes, SurfaceChannelOrder aChannelOrder );
00112 SurfaceT( shared_ptr<class ImageSource> imageSource, const SurfaceConstraints &constraints = SurfaceConstraintsDefault(), boost::tribool alpha = boost::logic::indeterminate );
00113
00114 operator ImageSourceRef() const;
00115
00117 int32_t getWidth() const { return mObj->mWidth; }
00119 int32_t getHeight() const { return mObj->mHeight; }
00121 Vec2i getSize() const { return Vec2i( mObj->mWidth, mObj->mHeight ); }
00123 float getAspectRatio() const { return mObj->mWidth / (float)mObj->mHeight; }
00125 Area getBounds() const { return Area( 0, 0, mObj->mWidth, mObj->mHeight ); }
00127 bool hasAlpha() const { return mObj->mChannelOrder.hasAlpha(); }
00129 bool isPremultiplied() const { return mObj->mIsPremultiplied; }
00131 bool setPremultiplied( bool premult = true ) const { return mObj->mIsPremultiplied = premult; }
00133 int32_t getRowBytes() const { return mObj->mRowBytes; }
00135 uint8_t getPixelInc() const { return mObj->mChannelOrder.getPixelInc(); }
00136
00138 SurfaceT clone( bool copyPixels = true ) const;
00140 SurfaceT clone( const Area &area, bool copyPixels = true ) const;
00141
00142 T* getData() { return mObj->mData; }
00143 const T* getData() const { return mObj->mData; }
00144 T* getData( const Vec2i &offset ) { return reinterpret_cast<T*>( reinterpret_cast<unsigned char*>( mObj->mData + offset.x * getPixelInc() ) + offset.y * mObj->mRowBytes ); }
00145 const T* getData( const Vec2i &offset ) const { return reinterpret_cast<T*>( reinterpret_cast<unsigned char*>( mObj->mData + offset.x * getPixelInc() ) + offset.y * mObj->mRowBytes ); }
00146 T* getDataRed( const Vec2i &offset ) { return getData( offset ) + getRedOffset(); }
00147 const T* getDataRed( const Vec2i &offset ) const { return getData( offset ) + getRedOffset(); }
00148 T* getDataGreen( const Vec2i &offset ) { return getData( offset ) + getGreenOffset(); }
00149 const T* getDataGreen( const Vec2i &offset ) const { return getData( offset ) + getGreenOffset(); }
00150 T* getDataBlue( const Vec2i &offset ) { return getData( offset ) + getBlueOffset(); }
00151 const T* getDataBlue( const Vec2i &offset ) const { return getData( offset ) + getBlueOffset(); }
00152 T* getDataAlpha( const Vec2i &offset ) { return getData( offset ) + getAlphaOffset(); }
00153 const T* getDataAlpha( const Vec2i &offset ) const { return getData( offset ) + getAlphaOffset(); }
00154
00155 void setData( T *aData, int32_t aWidth, int32_t aHeight, int32_t aRowBytes );
00157 void setDeallocator( void(*aDeallocatorFunc)( void * ), void *aDeallocatorRefcon );
00158
00159 const SurfaceChannelOrder& getChannelOrder() const { return mObj->mChannelOrder; }
00160 uint8_t getRedOffset() const { return mObj->mChannelOrder.getRedOffset(); }
00161 uint8_t getGreenOffset() const { return mObj->mChannelOrder.getGreenOffset(); }
00162 uint8_t getBlueOffset() const { return mObj->mChannelOrder.getBlueOffset(); }
00163 uint8_t getAlphaOffset() const { return mObj->mChannelOrder.getAlphaOffset(); }
00164 void setChannelOrder( const SurfaceChannelOrder &aChannelOrder );
00165
00166 ChannelT<T>* getChannel( uint8_t ChannelT ) { return &mObj->mChannels[ChannelT]; }
00167 ChannelT<T>* getChannelRed() { return &mObj->mChannels[SurfaceChannelOrder::CHAN_RED]; }
00168 ChannelT<T>* getChannelGreen() { return &mObj->mChannels[SurfaceChannelOrder::CHAN_GREEN]; }
00169 ChannelT<T>* getChannelBlue() { return &mObj->mChannels[SurfaceChannelOrder::CHAN_BLUE]; }
00170 ChannelT<T>* getChannelAlpha() { return &mObj->mChannels[SurfaceChannelOrder::CHAN_ALPHA]; }
00171
00172 const ChannelT<T>* getChannel( uint8_t ChannelT ) const { return &mObj->mChannels[ChannelT]; }
00173 const ChannelT<T>* getChannelRed() const { return &mObj->mChannels[SurfaceChannelOrder::CHAN_RED]; }
00174 const ChannelT<T>* getChannelGreen() const { return &mObj->mChannels[SurfaceChannelOrder::CHAN_GREEN]; }
00175 const ChannelT<T>* getChannelBlue() const { return &mObj->mChannels[SurfaceChannelOrder::CHAN_BLUE]; }
00176 const ChannelT<T>* getChannelAlpha() const { return &mObj->mChannels[SurfaceChannelOrder::CHAN_ALPHA]; }
00177
00179 ColorAT<T> getPixel( 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 ); const T *p = getData( pos ); return ColorAT<T>( p[getRedOffset()], p[getGreenOffset()], p[getBlueOffset()], ( hasAlpha() ) ? p[getAlphaOffset()] : CHANTRAIT<T>::max() ); }
00181 void setPixel( Vec2i pos, const ColorT<T> &c ) { pos.x = constrain<int32_t>( pos.x, 0, mObj->mWidth - 1); pos.y = constrain<int32_t>( pos.y, 0, mObj->mHeight - 1 ); T *p = getData( pos ); p[getRedOffset()] = c.r; p[getGreenOffset()] = c.g; p[getBlueOffset()] = c.b; }
00183 void setPixel( Vec2i pos, const ColorAT<T> &c ) { pos.x = constrain<int32_t>( pos.x, 0, mObj->mWidth - 1); pos.y = constrain<int32_t>( pos.y, 0, mObj->mHeight - 1 ); T *p = getData( pos ); p[getRedOffset()] = c.r; p[getGreenOffset()] = c.g; p[getBlueOffset()] = c.b; if( hasAlpha() ) p[getAlphaOffset()] = c.a; }
00184
00185 void copyFrom( const SurfaceT<T> &srcSurface, const Area &srcArea, const Vec2i &relativeOffset = Vec2i::zero() );
00186
00187
00188
00189 ColorT<T> areaAverage( const Area &area ) const;
00190
00192
00193 typedef shared_ptr<Obj> SurfaceT::*unspecified_bool_type;
00194 operator unspecified_bool_type() { return ( mObj.get() == 0 ) ? 0 : &SurfaceT::mObj; }
00195 void reset() { mObj.reset(); }
00197
00198 private:
00199 shared_ptr<Obj> mObj;
00200
00201 void init( shared_ptr<class ImageSource> imageSource, const SurfaceConstraints &constraints = SurfaceConstraintsDefault(), boost::tribool alpha = boost::logic::indeterminate );
00202
00203 void copyRawSameChannelOrder( const SurfaceT<T> &srcSurface, const Area &srcArea, const Vec2i &absoluteOffset );
00204 void copyRawRgba( const SurfaceT<T> &srcSurface, const Area &srcArea, const Vec2i &absoluteOffset );
00205 void copyRawRgb( const SurfaceT<T> &srcSurface, const Area &srcArea, const Vec2i &absoluteOffset );
00206
00207 public:
00208 class Iter {
00209 public:
00210 Iter( SurfaceT<T> &SurfaceT, const Area &area )
00211 : mRedOff( SurfaceT.getRedOffset() ), mGreenOff( SurfaceT.getGreenOffset() ),
00212 mBlueOff( SurfaceT.getBlueOffset() ), mAlphaOff( SurfaceT.getAlphaOffset() ),
00213 mInc( SurfaceT.getPixelInc() ), mRowInc( SurfaceT.getRowBytes() )
00214 {
00215 Area clippedArea( area.getClipBy( SurfaceT.getBounds() ) );
00216 mWidth = clippedArea.getWidth();
00217 mHeight = clippedArea.getHeight();
00218 mLinePtr = reinterpret_cast<uint8_t*>( SurfaceT.getData( clippedArea.getUL() ) );
00219 mPtr = reinterpret_cast<T*>( mLinePtr );
00220 mStartX = mX = clippedArea.getX1();
00221 mStartY = mY = clippedArea.getY1();
00222 mEndX = clippedArea.getX2();
00223 mEndY = clippedArea.getY2();
00224
00225 mY = clippedArea.getY1() - 1;
00226 mLinePtr -= mRowInc;
00227 }
00228
00229 T& r() const { return mPtr[mRedOff]; }
00230 T& g() const { return mPtr[mGreenOff]; }
00231 T& b() const { return mPtr[mBlueOff]; }
00232 T& a() const { return mPtr[mAlphaOff]; }
00233
00234 T& r( int32_t xOff, int32_t yOff ) const { return mPtr[mRedOff + xOff * mInc + yOff * mRowInc]; }
00235 T& g( int32_t xOff, int32_t yOff ) const { return mPtr[mGreenOff + xOff * mInc + yOff * mRowInc]; }
00236 T& b( int32_t xOff, int32_t yOff ) const { return mPtr[mBlueOff + xOff * mInc + yOff * mRowInc]; }
00237 T& a( int32_t xOff, int32_t yOff ) const { return mPtr[mAlphaOff + xOff * mInc + yOff * mRowInc]; }
00238
00239 T& rClamped( int32_t xOff, int32_t yOff ) const
00240 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY;
00241 return mPtr[mRedOff + xOff * mInc + yOff * mRowInc]; }
00242 T& gClamped( int32_t xOff, int32_t yOff ) const
00243 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY;
00244 return mPtr[mGreenOff + xOff * mInc + yOff * mRowInc]; }
00245 T& bClamped( int32_t xOff, int32_t yOff ) const
00246 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY;
00247 return mPtr[mBlueOff + xOff * mInc + yOff * mRowInc]; }
00248 T& aClamped( int32_t xOff, int32_t yOff ) const
00249 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY;
00250 return mPtr[mAlphaOff + xOff * mInc + yOff * mRowInc]; }
00251
00252 const int32_t x() const { return mX; }
00253 const int32_t y() const { return mY; }
00254 Vec2i getPos() const { return Vec2i( mX, mY ); }
00255
00256 bool pixel() {
00257 ++mX;
00258 mPtr += mInc;
00259 return mX < mEndX;
00260 }
00261
00262 bool line() {
00263 ++mY;
00264 mLinePtr += mRowInc;
00265 mPtr = reinterpret_cast<T*>( mLinePtr );
00266
00267 mPtr -= mInc;
00268 mX = mStartX - 1;
00269 return mY < mEndY;
00270 }
00271
00272 int32_t getWidth() const { return mWidth; }
00273 int32_t getHeight() const { return mHeight; }
00274
00275 uint8_t mRedOff, mGreenOff, mBlueOff, mAlphaOff, mInc;
00276 uint8_t *mLinePtr;
00277 T *mPtr;
00278 int32_t mRowInc, mWidth, mHeight;
00279 int32_t mX, mY, mStartX, mStartY, mEndX, mEndY;
00280 };
00281
00282 class ConstIter {
00283 public:
00284 ConstIter( const Iter &iter ) {
00285 mRedOff = iter.mRedOff;
00286 mGreenOff = iter.mGreenOff;
00287 mBlueOff = iter.mBlueOff;
00288 mAlphaOff = iter.mAlphaOff;
00289 mInc = iter.mInc;
00290 mRowInc = iter.mRowInc;
00291 mWidth = iter.mWidth;
00292 mHeight = iter.mHeight;
00293 mLinePtr = iter.mLinePtr;
00294 mPtr = iter.mPtr;
00295 mStartX = iter.mStartX;
00296 mX = iter.mX;
00297 mStartY = iter.mStartY;
00298 mY = iter.mY;
00299 mEndX = iter.mEndX;
00300 mEndY = iter.mEndY;
00301 }
00302
00303 ConstIter( const SurfaceT<T> &SurfaceT, const Area &area )
00304 : mRedOff( SurfaceT.getRedOffset() ), mGreenOff( SurfaceT.getGreenOffset() ),
00305 mBlueOff( SurfaceT.getBlueOffset() ), mAlphaOff( SurfaceT.getAlphaOffset() ),
00306 mInc( SurfaceT.getPixelInc() ), mRowInc( SurfaceT.getRowBytes() )
00307 {
00308 Area clippedArea( area.getClipBy( SurfaceT.getBounds() ) );
00309 mWidth = clippedArea.getWidth();
00310 mHeight = clippedArea.getHeight();
00311 mLinePtr = reinterpret_cast<const uint8_t*>( SurfaceT.getData( clippedArea.getUL() ) );
00312 mPtr = reinterpret_cast<const T*>( mLinePtr );
00313 mStartX = mX = clippedArea.getX1();
00314 mStartY = mY = clippedArea.getY1();
00315 mEndX = clippedArea.getX2();
00316 mEndY = clippedArea.getY2();
00317
00318 mY = clippedArea.getY1() - 1;
00319 mLinePtr -= mRowInc;
00320 }
00321
00322 const T& r() const { return mPtr[mRedOff]; }
00323 const T& g() const { return mPtr[mGreenOff]; }
00324 const T& b() const { return mPtr[mBlueOff]; }
00325 const T& a() const { return mPtr[mAlphaOff]; }
00326
00327 const T& r( int32_t xOff, int32_t yOff ) const { return mPtr[mRedOff + xOff * mInc + yOff * mRowInc]; }
00328 const T& g( int32_t xOff, int32_t yOff ) const { return mPtr[mGreenOff + xOff * mInc + yOff * mRowInc]; }
00329 const T& b( int32_t xOff, int32_t yOff ) const { return mPtr[mBlueOff + xOff * mInc + yOff * mRowInc]; }
00330 const T& a( int32_t xOff, int32_t yOff ) const { return mPtr[mAlphaOff + xOff * mInc + yOff * mRowInc]; }
00331
00332 const T& rClamped( int32_t xOff, int32_t yOff ) const
00333 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY;
00334 return mPtr[mRedOff + xOff * mInc + yOff * mRowInc]; }
00335 const T& gClamped( int32_t xOff, int32_t yOff ) const
00336 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY;
00337 return mPtr[mGreenOff + xOff * mInc + yOff * mRowInc]; }
00338 const T& bClamped( int32_t xOff, int32_t yOff ) const
00339 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY;
00340 return mPtr[mBlueOff + xOff * mInc + yOff * mRowInc]; }
00341 const T& aClamped( int32_t xOff, int32_t yOff ) const
00342 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY;
00343 return mPtr[mAlphaOff + xOff * mInc + yOff * mRowInc]; }
00344
00345 const int32_t x() const { return mX; }
00346 const int32_t y() const { return mY; }
00347 Vec2i getPos() const { return Vec2i( mX, mY ); }
00348
00349 bool pixel() {
00350 ++mX;
00351 mPtr += mInc;
00352 return mX < mEndX;
00353 }
00354
00355 bool line() {
00356 ++mY;
00357 mLinePtr += mRowInc;
00358 mPtr = reinterpret_cast<const T*>( mLinePtr );
00359
00360 mPtr -= mInc;
00361 mX = mStartX - 1;
00362 return mY < mEndY;
00363 }
00364
00365 int32_t getWidth() const { return mWidth; }
00366 int32_t getHeight() const { return mHeight; }
00367
00368 uint8_t mRedOff, mGreenOff, mBlueOff, mAlphaOff, mInc;
00369 const uint8_t *mLinePtr;
00370 const T *mPtr;
00371 int32_t mRowInc, mWidth, mHeight;
00372 int32_t mX, mY, mStartX, mStartY, mEndX, mEndY;
00373 };
00374
00375 Iter getIter() { return Iter( *this, this->getBounds() ); }
00376 Iter getIter( const Area &area ) { return Iter( *this, area ); }
00377 ConstIter getIter() const { return ConstIter( *this, this->getBounds() ); }
00378 ConstIter getIter( const Area &area ) const { return ConstIter( *this, area ); }
00379 };
00380
00381 class SurfaceExc : public std::exception {
00382 virtual const char* what() const throw() {
00383 return "Surface exception";
00384 }
00385 };
00386
00387 class SurfaceConstraintsExc : public SurfaceExc {
00388 virtual const char* what() const throw() {
00389 return "Surface exception: does not conform to expected SurfaceConstraints";
00390 }
00391 };
00392
00393 typedef SurfaceT<uint8_t> Surface;
00394 typedef SurfaceT<uint8_t> Surface8u;
00395 typedef SurfaceT<float> Surface32f;
00396
00397 }