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 #include "cinder/Channel.h" 00031 #include "cinder/ChanTraits.h" 00032 #include "cinder/Color.h" 00033 00034 #include <boost/logic/tribool.hpp> 00035 00036 namespace cinder { 00037 00039 class SurfaceChannelOrder { 00040 public: 00041 SurfaceChannelOrder() : mCode( UNSPECIFIED ), mRed( INVALID ), mGreen( INVALID ), mBlue( INVALID ), mAlpha( INVALID ), mPixelInc( INVALID ) {} 00042 SurfaceChannelOrder( int aCode ); 00043 SurfaceChannelOrder( const SurfaceChannelOrder &aOrder ); 00044 00045 // static ChannelOrder GetPlatformNativeChannelOrder( bool includeAlpha ); 00046 00047 uint8_t getRedOffset() const { return mRed; } 00048 uint8_t getGreenOffset() const { return mGreen; } 00049 uint8_t getBlueOffset() const { return mBlue; } 00050 uint8_t getAlphaOffset() const { return mAlpha; } 00051 bool hasAlpha() const { return ( mAlpha != INVALID ) ? true : false; } 00052 uint8_t getPixelInc() const { return mPixelInc; } 00053 int getCode() const { return mCode; } 00054 00055 bool operator==( const SurfaceChannelOrder& sco ) const 00056 { 00057 return mCode == sco.mCode; 00058 } 00059 00060 enum { CHAN_RED, CHAN_GREEN, CHAN_BLUE, CHAN_ALPHA, INVALID = 255 }; 00061 enum { RGBA, BGRA, ARGB, ABGR, RGBX, BGRX, XRGB, XBGR, RGB, BGR, UNSPECIFIED }; // Codes 00062 00063 int getImageIoChannelOrder() const; 00064 00065 private: 00066 void set( uint8_t aRed, uint8_t aGreen, uint8_t aBlue, uint8_t aAlpha, uint8_t aPixelInc ); 00067 int mCode; // the enum 00068 uint8_t mRed, mGreen, mBlue, mAlpha, mPixelInc; 00069 00070 }; 00071 00073 class SurfaceConstraints { 00074 public: 00075 virtual ~SurfaceConstraints() {} 00076 00077 virtual SurfaceChannelOrder getChannelOrder( bool alpha ) const { return ( alpha ) ? SurfaceChannelOrder::RGBA : SurfaceChannelOrder::RGB; } 00078 virtual int32_t getRowBytes( int requestedWidth, const SurfaceChannelOrder &sco, int elementSize ) const { return requestedWidth * elementSize * sco.getPixelInc(); } 00079 }; 00080 00081 class SurfaceConstraintsDefault : public SurfaceConstraints { 00082 }; 00083 00084 typedef std::shared_ptr<class ImageSource> ImageSourceRef; 00085 typedef std::shared_ptr<class ImageTarget> ImageTargetRef; 00086 00087 template<typename T> 00089 class SurfaceT { 00090 private: 00092 struct Obj { 00093 Obj( int32_t aWidth, int32_t aHeight, SurfaceChannelOrder aChannelOrder, T *aData, bool aOwnsData, int32_t aRowBytes ); 00094 ~Obj(); 00095 00096 void initChannels(); 00097 void setChannelOrder( const SurfaceChannelOrder &aChannelOrder ); 00098 void setDeallocator( void(*aDeallocatorFunc)( void * ), void *aDeallocatorRefcon ); 00099 00100 int32_t mWidth, mHeight, mRowBytes; 00101 bool mIsPremultiplied; 00102 T *mData; 00103 bool mOwnsData; 00104 SurfaceChannelOrder mChannelOrder; 00105 ChannelT<T> mChannels[4]; 00106 00107 void (*mDeallocatorFunc)(void *refcon); 00108 void *mDeallocatorRefcon; 00109 }; 00111 00112 public: 00114 SurfaceT() {} 00120 SurfaceT( int32_t width, int32_t height, bool alpha, SurfaceChannelOrder channelOrder = SurfaceChannelOrder::UNSPECIFIED ); 00121 SurfaceT( int32_t width, int32_t height, bool alpha, const SurfaceConstraints &constraints ); 00123 SurfaceT( T *data, int32_t width, int32_t height, int32_t rowBytes, SurfaceChannelOrder channelOrder ); 00129 SurfaceT( ImageSourceRef imageSource, const SurfaceConstraints &constraints = SurfaceConstraintsDefault(), boost::tribool alpha = boost::logic::indeterminate ); 00130 00131 operator ImageSourceRef() const; 00132 operator ImageTargetRef(); 00133 00135 int32_t getWidth() const { return mObj->mWidth; } 00137 int32_t getHeight() const { return mObj->mHeight; } 00139 Vec2i getSize() const { return Vec2i( mObj->mWidth, mObj->mHeight ); } 00141 float getAspectRatio() const { return mObj->mWidth / (float)mObj->mHeight; } 00143 Area getBounds() const { return Area( 0, 0, mObj->mWidth, mObj->mHeight ); } 00145 bool hasAlpha() const { return mObj->mChannelOrder.hasAlpha(); } 00147 bool isPremultiplied() const { return mObj->mIsPremultiplied; } 00149 bool setPremultiplied( bool premult = true ) const { return mObj->mIsPremultiplied = premult; } 00151 int32_t getRowBytes() const { return mObj->mRowBytes; } 00153 uint8_t getPixelInc() const { return mObj->mChannelOrder.getPixelInc(); } 00154 00156 SurfaceT clone( bool copyPixels = true ) const; 00158 SurfaceT clone( const Area &area, bool copyPixels = true ) const; 00159 00161 T* getData() { return mObj->mData; } 00162 const T* getData() const { return mObj->mData; } 00163 T* getData( const Vec2i &offset ) { return reinterpret_cast<T*>( reinterpret_cast<unsigned char*>( mObj->mData + offset.x * getPixelInc() ) + offset.y * mObj->mRowBytes ); } 00164 const T* getData( const Vec2i &offset ) const { return reinterpret_cast<T*>( reinterpret_cast<unsigned char*>( mObj->mData + offset.x * getPixelInc() ) + offset.y * mObj->mRowBytes ); } 00166 T* getDataRed( const Vec2i &offset ) { return getData( offset ) + getRedOffset(); } 00167 const T* getDataRed( const Vec2i &offset ) const { return getData( offset ) + getRedOffset(); } 00169 T* getDataGreen( const Vec2i &offset ) { return getData( offset ) + getGreenOffset(); } 00170 const T* getDataGreen( const Vec2i &offset ) const { return getData( offset ) + getGreenOffset(); } 00172 T* getDataBlue( const Vec2i &offset ) { return getData( offset ) + getBlueOffset(); } 00173 const T* getDataBlue( const Vec2i &offset ) const { return getData( offset ) + getBlueOffset(); } 00175 T* getDataAlpha( const Vec2i &offset ) { return getData( offset ) + getAlphaOffset(); } 00176 const T* getDataAlpha( const Vec2i &offset ) const { return getData( offset ) + getAlphaOffset(); } 00177 00179 void setDeallocator( void(*aDeallocatorFunc)( void * ), void *aDeallocatorRefcon ); 00180 00182 const SurfaceChannelOrder& getChannelOrder() const { return mObj->mChannelOrder; } 00184 uint8_t getRedOffset() const { return mObj->mChannelOrder.getRedOffset(); } 00186 uint8_t getGreenOffset() const { return mObj->mChannelOrder.getGreenOffset(); } 00188 uint8_t getBlueOffset() const { return mObj->mChannelOrder.getBlueOffset(); } 00190 uint8_t getAlphaOffset() const { return mObj->mChannelOrder.getAlphaOffset(); } 00192 void setChannelOrder( const SurfaceChannelOrder &aChannelOrder ); 00193 00195 ChannelT<T>& getChannel( uint8_t channelIndex ) { return mObj->mChannels[channelIndex]; } 00197 const ChannelT<T>& getChannel( uint8_t channelIndex ) const { return mObj->mChannels[channelIndex]; } 00198 00200 ChannelT<T>& getChannelRed() { return mObj->mChannels[SurfaceChannelOrder::CHAN_RED]; } 00202 ChannelT<T>& getChannelGreen() { return mObj->mChannels[SurfaceChannelOrder::CHAN_GREEN]; } 00204 ChannelT<T>& getChannelBlue() { return mObj->mChannels[SurfaceChannelOrder::CHAN_BLUE]; } 00206 ChannelT<T>& getChannelAlpha() { return mObj->mChannels[SurfaceChannelOrder::CHAN_ALPHA]; } 00207 00209 const ChannelT<T>& getChannelRed() const { return mObj->mChannels[SurfaceChannelOrder::CHAN_RED]; } 00211 const ChannelT<T>& getChannelGreen() const { return mObj->mChannels[SurfaceChannelOrder::CHAN_GREEN]; } 00213 const ChannelT<T>& getChannelBlue() const { return mObj->mChannels[SurfaceChannelOrder::CHAN_BLUE]; } 00215 const ChannelT<T>& getChannelAlpha() const { return mObj->mChannels[SurfaceChannelOrder::CHAN_ALPHA]; } 00216 00218 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() ); } 00220 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; } 00222 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; } 00223 00225 void copyFrom( const SurfaceT<T> &srcSurface, const Area &srcArea, const Vec2i &relativeOffset = Vec2i::zero() ); 00226 00228 ColorT<T> areaAverage( const Area &area ) const; 00229 00231 typedef std::shared_ptr<Obj> SurfaceT::*unspecified_bool_type; 00232 operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &SurfaceT::mObj; } 00233 void reset() { mObj.reset(); } 00235 00236 private: 00237 std::shared_ptr<Obj> mObj; 00238 00239 void init( ImageSourceRef imageSource, const SurfaceConstraints &constraints = SurfaceConstraintsDefault(), boost::tribool alpha = boost::logic::indeterminate ); 00240 00241 void copyRawSameChannelOrder( const SurfaceT<T> &srcSurface, const Area &srcArea, const Vec2i &absoluteOffset ); 00242 void copyRawRgba( const SurfaceT<T> &srcSurface, const Area &srcArea, const Vec2i &absoluteOffset ); 00243 void copyRawRgb( const SurfaceT<T> &srcSurface, const Area &srcArea, const Vec2i &absoluteOffset ); 00244 00245 public: 00246 00248 class Iter { 00249 public: 00250 Iter( SurfaceT<T> &SurfaceT, const Area &area ) 00251 : mRedOff( SurfaceT.getRedOffset() ), mGreenOff( SurfaceT.getGreenOffset() ), 00252 mBlueOff( SurfaceT.getBlueOffset() ), mAlphaOff( SurfaceT.getAlphaOffset() ), 00253 mInc( SurfaceT.getPixelInc() ), mRowInc( SurfaceT.getRowBytes() ) 00254 { 00255 Area clippedArea( area.getClipBy( SurfaceT.getBounds() ) ); 00256 mWidth = clippedArea.getWidth(); 00257 mHeight = clippedArea.getHeight(); 00258 mLinePtr = reinterpret_cast<uint8_t*>( SurfaceT.getData( clippedArea.getUL() ) ); 00259 mPtr = reinterpret_cast<T*>( mLinePtr ); 00260 mStartX = mX = clippedArea.getX1(); 00261 mStartY = mY = clippedArea.getY1(); 00262 mEndX = clippedArea.getX2(); 00263 mEndY = clippedArea.getY2(); 00264 // in order to be at the right place after an initial call to line(), we need to back up one line 00265 mY = clippedArea.getY1() - 1; 00266 mLinePtr -= mRowInc; 00267 } 00269 T& r() const { return mPtr[mRedOff]; } 00271 T& g() const { return mPtr[mGreenOff]; } 00273 T& b() const { return mPtr[mBlueOff]; } 00275 T& a() const { return mPtr[mAlphaOff]; } 00276 00278 T& r( int32_t xOff, int32_t yOff ) const { return mPtr[mRedOff + xOff * mInc + yOff * mRowInc]; } 00280 T& g( int32_t xOff, int32_t yOff ) const { return mPtr[mGreenOff + xOff * mInc + yOff * mRowInc]; } 00282 T& b( int32_t xOff, int32_t yOff ) const { return mPtr[mBlueOff + xOff * mInc + yOff * mRowInc]; } 00284 T& a( int32_t xOff, int32_t yOff ) const { return mPtr[mAlphaOff + xOff * mInc + yOff * mRowInc]; } 00285 00287 T& rClamped( int32_t xOff, int32_t yOff ) const 00288 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY; 00289 return *(T*)((uint8_t*)( mPtr + mRedOff + xOff * mInc ) + yOff * mRowInc); } 00291 T& gClamped( int32_t xOff, int32_t yOff ) const 00292 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY; 00293 return *(T*)((uint8_t*)( mPtr + mGreenOff + xOff * mInc ) + yOff * mRowInc); } 00295 T& bClamped( int32_t xOff, int32_t yOff ) const 00296 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY; 00297 return *(T*)((uint8_t*)( mPtr + mBlueOff + xOff * mInc ) + yOff * mRowInc); } 00299 T& aClamped( int32_t xOff, int32_t yOff ) const 00300 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY; 00301 return *(T*)((uint8_t*)( mPtr + mAlphaOff + xOff * mInc ) + yOff * mRowInc); } 00302 00304 const int32_t x() const { return mX; } 00306 const int32_t y() const { return mY; } 00308 Vec2i getPos() const { return Vec2i( mX, mY ); } 00309 00311 bool pixel() { 00312 ++mX; 00313 mPtr += mInc; 00314 return mX < mEndX; 00315 } 00316 00318 bool line() { 00319 ++mY; 00320 mLinePtr += mRowInc; 00321 mPtr = reinterpret_cast<T*>( mLinePtr ); 00322 // in order to be at the right place after an initial call to pixel(), we need to back up one pixel 00323 mPtr -= mInc; 00324 mX = mStartX - 1; 00325 return mY < mEndY; 00326 } 00327 00329 int32_t getWidth() const { return mWidth; } 00331 int32_t getHeight() const { return mHeight; } 00332 00334 uint8_t mRedOff, mGreenOff, mBlueOff, mAlphaOff, mInc; 00335 uint8_t *mLinePtr; 00336 T *mPtr; 00337 int32_t mRowInc, mWidth, mHeight; 00338 int32_t mX, mY, mStartX, mStartY, mEndX, mEndY; 00340 }; 00341 00343 class ConstIter { 00344 public: 00345 ConstIter( const Iter &iter ) { 00346 mRedOff = iter.mRedOff; 00347 mGreenOff = iter.mGreenOff; 00348 mBlueOff = iter.mBlueOff; 00349 mAlphaOff = iter.mAlphaOff; 00350 mInc = iter.mInc; 00351 mRowInc = iter.mRowInc; 00352 mWidth = iter.mWidth; 00353 mHeight = iter.mHeight; 00354 mLinePtr = iter.mLinePtr; 00355 mPtr = iter.mPtr; 00356 mStartX = iter.mStartX; 00357 mX = iter.mX; 00358 mStartY = iter.mStartY; 00359 mY = iter.mY; 00360 mEndX = iter.mEndX; 00361 mEndY = iter.mEndY; 00362 } 00363 00364 ConstIter( const SurfaceT<T> &SurfaceT, const Area &area ) 00365 : mRedOff( SurfaceT.getRedOffset() ), mGreenOff( SurfaceT.getGreenOffset() ), 00366 mBlueOff( SurfaceT.getBlueOffset() ), mAlphaOff( SurfaceT.getAlphaOffset() ), 00367 mInc( SurfaceT.getPixelInc() ), mRowInc( SurfaceT.getRowBytes() ) 00368 { 00369 Area clippedArea( area.getClipBy( SurfaceT.getBounds() ) ); 00370 mWidth = clippedArea.getWidth(); 00371 mHeight = clippedArea.getHeight(); 00372 mLinePtr = reinterpret_cast<const uint8_t*>( SurfaceT.getData( clippedArea.getUL() ) ); 00373 mPtr = reinterpret_cast<const T*>( mLinePtr ); 00374 mStartX = mX = clippedArea.getX1(); 00375 mStartY = mY = clippedArea.getY1(); 00376 mEndX = clippedArea.getX2(); 00377 mEndY = clippedArea.getY2(); 00378 // in order to be at the right place after an initial call to line(), we need to back up one line 00379 mY = clippedArea.getY1() - 1; 00380 mLinePtr -= mRowInc; 00381 } 00382 00384 const T& r() const { return mPtr[mRedOff]; } 00386 const T& g() const { return mPtr[mGreenOff]; } 00388 const T& b() const { return mPtr[mBlueOff]; } 00390 const T& a() const { return mPtr[mAlphaOff]; } 00391 00393 const T& r( int32_t xOff, int32_t yOff ) const { return mPtr[mRedOff + xOff * mInc + yOff * mRowInc]; } 00395 const T& g( int32_t xOff, int32_t yOff ) const { return mPtr[mGreenOff + xOff * mInc + yOff * mRowInc]; } 00397 const T& b( int32_t xOff, int32_t yOff ) const { return mPtr[mBlueOff + xOff * mInc + yOff * mRowInc]; } 00399 const T& a( int32_t xOff, int32_t yOff ) const { return mPtr[mAlphaOff + xOff * mInc + yOff * mRowInc]; } 00400 00402 const T& rClamped( int32_t xOff, int32_t yOff ) const 00403 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY; 00404 return *(T*)((uint8_t*)( mPtr + mRedOff + xOff * mInc ) + yOff * mRowInc); } 00406 const T& gClamped( int32_t xOff, int32_t yOff ) const 00407 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY; 00408 return *(T*)((uint8_t*)( mPtr + mGreenOff + xOff * mInc ) + yOff * mRowInc); } 00410 const T& bClamped( int32_t xOff, int32_t yOff ) const 00411 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY; 00412 return *(T*)((uint8_t*)( mPtr + mBlueOff + xOff * mInc ) + yOff * mRowInc); } 00414 const T& aClamped( int32_t xOff, int32_t yOff ) const 00415 { xOff = std::min(std::max(mX + xOff, mStartX),mEndX - 1) - mX; yOff = std::min(std::max( mY + yOff, mStartY ), mEndY - 1) - mY; 00416 return *(T*)((uint8_t*)( mPtr + mAlphaOff + xOff * mInc ) + yOff * mRowInc); } 00417 00419 const int32_t x() const { return mX; } 00421 const int32_t y() const { return mY; } 00423 Vec2i getPos() const { return Vec2i( mX, mY ); } 00424 00426 bool pixel() { 00427 ++mX; 00428 mPtr += mInc; 00429 return mX < mEndX; 00430 } 00431 00433 bool line() { 00434 ++mY; 00435 mLinePtr += mRowInc; 00436 mPtr = reinterpret_cast<const T*>( mLinePtr ); 00437 // in order to be at the right place after an initial call to pixel(), we need to back up one pixel 00438 mPtr -= mInc; 00439 mX = mStartX - 1; 00440 return mY < mEndY; 00441 } 00442 00444 int32_t getWidth() const { return mWidth; } 00446 int32_t getHeight() const { return mHeight; } 00447 00449 uint8_t mRedOff, mGreenOff, mBlueOff, mAlphaOff, mInc; 00450 const uint8_t *mLinePtr; 00451 const T *mPtr; 00452 int32_t mRowInc, mWidth, mHeight; 00453 int32_t mX, mY, mStartX, mStartY, mEndX, mEndY; 00455 }; 00456 00458 Iter getIter() { return Iter( *this, this->getBounds() ); } 00460 Iter getIter( const Area &area ) { return Iter( *this, area ); } 00462 ConstIter getIter() const { return ConstIter( *this, this->getBounds() ); } 00464 ConstIter getIter( const Area &area ) const { return ConstIter( *this, area ); } 00465 }; 00466 00467 class SurfaceExc : public std::exception { 00468 virtual const char* what() const throw() { 00469 return "Surface exception"; 00470 } 00471 }; 00472 00473 class SurfaceConstraintsExc : public SurfaceExc { 00474 virtual const char* what() const throw() { 00475 return "Surface exception: does not conform to expected SurfaceConstraints"; 00476 } 00477 }; 00478 00480 typedef SurfaceT<uint8_t> Surface; 00482 typedef SurfaceT<uint8_t> Surface8u; 00484 typedef SurfaceT<uint16_t> Surface16u; 00486 typedef SurfaceT<float> Surface32f; 00487 00488 } // namespace cinder