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/gl/gl.h" 00026 #include "cinder/TriMesh.h" 00027 00028 #include <vector> 00029 #include <utility> 00030 00031 namespace cinder { namespace gl { 00032 00033 class Vbo { 00034 public: 00035 Vbo() {} 00036 Vbo( GLenum aTarget ); 00037 00038 void bind(); 00039 void unbind(); 00040 00041 void bufferData( size_t size, const void *data, GLenum usage ); 00042 void bufferSubData( ptrdiff_t offset, size_t size, const void *data ); 00043 00044 uint8_t* map( GLenum access ); 00045 void unmap(); 00046 00047 GLenum getTarget() const { return mObj->mTarget; } 00048 GLuint getId() const { return mObj->mId; } 00049 00050 protected: 00051 struct Obj { 00052 Obj( GLenum aTarget ); 00053 ~Obj(); 00054 00055 GLenum mTarget; 00056 GLuint mId; 00057 }; 00058 00059 shared_ptr<Obj> mObj; 00060 00061 public: 00063 00064 typedef shared_ptr<Obj> Vbo::*unspecified_bool_type; 00065 operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &Vbo::mObj; } 00066 void reset() { mObj.reset(); } 00068 }; 00069 00070 class VboMesh { 00071 public: 00072 enum { NONE, STATIC, DYNAMIC }; 00073 enum { ATTR_INDICES, ATTR_POSITIONS, ATTR_NORMALS, ATTR_COLORS_RGB, ATTR_COLORS_RGBA, ATTR_TEXCOORDS2D_0, ATTR_TEXCOORDS2D_1, ATTR_TEXCOORDS2D_2, ATTR_TEXCOORDS2D_3, ATTR_TEXCOORDS3D_0, ATTR_TEXCOORDS3D_1, ATTR_TEXCOORDS3D_2, ATTR_TEXCOORDS3D_3, ATTR_TOTAL }; 00074 enum { ATTR_MAX_TEXTURE_UNIT = 3 }; 00075 00076 struct Layout { 00077 Layout() { initAttributes(); } 00078 00080 bool isDefaults() const { for( int a = 0; a < ATTR_TOTAL; ++a ) if( mAttributes[a] != NONE ) return false; return true; } 00081 00082 bool hasNormals() const { return hasDynamicNormals() || hasStaticNormals(); } 00083 bool hasStaticNormals() const { return mAttributes[ATTR_NORMALS] == STATIC; } 00084 bool hasDynamicNormals() const { return mAttributes[ATTR_NORMALS] == DYNAMIC; } 00085 void setStaticNormals() { mAttributes[ATTR_NORMALS] = STATIC; } 00086 void setDynamicNormals() { mAttributes[ATTR_NORMALS] = DYNAMIC; } 00087 00088 bool hasColorsRGB() const { return hasDynamicColorsRGB() || hasStaticColorsRGB(); } 00089 bool hasStaticColorsRGB() const { return mAttributes[ATTR_COLORS_RGB] == STATIC; } 00090 bool hasDynamicColorsRGB() const { return mAttributes[ATTR_COLORS_RGB] == DYNAMIC; } 00091 void setStaticColorsRGB() { mAttributes[ATTR_COLORS_RGB] = STATIC; mAttributes[ATTR_COLORS_RGBA] = NONE; } 00092 void setDynamicColorsRGB() { mAttributes[ATTR_COLORS_RGB] = DYNAMIC; mAttributes[ATTR_COLORS_RGBA] = NONE; } 00093 00094 bool hasColorsRGBA() const { return hasDynamicColorsRGBA() || hasStaticColorsRGBA(); } 00095 bool hasStaticColorsRGBA() const { return mAttributes[ATTR_COLORS_RGBA] == STATIC; } 00096 bool hasDynamicColorsRGBA() const { return mAttributes[ATTR_COLORS_RGBA] == DYNAMIC; } 00097 void setStaticColorsRGBA() { mAttributes[ATTR_COLORS_RGBA] = STATIC; mAttributes[ATTR_COLORS_RGB] = NONE; } 00098 void setDynamicColorsRGBA() { mAttributes[ATTR_COLORS_RGBA] = DYNAMIC; mAttributes[ATTR_COLORS_RGB] = NONE; } 00099 00100 bool hasTexCoords2d( size_t unit = 0 ) const { return hasDynamicTexCoords2d( unit ) || hasStaticTexCoords2d( unit ); } 00101 bool hasStaticTexCoords2d( size_t unit = 0 ) const { return mAttributes[ATTR_TEXCOORDS2D_0 + unit] == STATIC; } 00102 bool hasDynamicTexCoords2d( size_t unit = 0 ) const { return mAttributes[ATTR_TEXCOORDS2D_0 + unit] == DYNAMIC; } 00103 void setStaticTexCoords2d( size_t unit = 0 ) { mAttributes[ATTR_TEXCOORDS2D_0 + unit] = STATIC; mAttributes[ATTR_TEXCOORDS3D_0 + unit] = NONE; } 00104 void setDynamicTexCoords2d( size_t unit = 0 ) { mAttributes[ATTR_TEXCOORDS2D_0 + unit] = DYNAMIC; mAttributes[ATTR_TEXCOORDS3D_0 + unit] = NONE; } 00106 bool hasStaticTexCoords() const; 00108 bool hasDynamicTexCoords() const; 00110 bool hasTexCoords( size_t unit ) const { return ( mAttributes[ATTR_TEXCOORDS2D_0 + unit] != NONE ) || ( mAttributes[ATTR_TEXCOORDS3D_0 + unit] != NONE ); } 00111 00112 bool hasTexCoords3d( size_t unit = 0 ) const { return hasDynamicTexCoords3d( unit ) || hasStaticTexCoords3d( unit ); } 00113 bool hasStaticTexCoords3d( size_t unit = 0 ) const { return mAttributes[ATTR_TEXCOORDS3D_0 + unit] == STATIC; } 00114 bool hasDynamicTexCoords3d( size_t unit = 0 ) const { return mAttributes[ATTR_TEXCOORDS3D_0 + unit] == DYNAMIC; } 00115 void setStaticTexCoords3d( size_t unit = 0 ) { mAttributes[ATTR_TEXCOORDS3D_0 + unit] = STATIC; mAttributes[ATTR_TEXCOORDS2D_0 + unit] = NONE; } 00116 void setDynamicTexCoords3d( size_t unit = 0 ) { mAttributes[ATTR_TEXCOORDS3D_0 + unit] = DYNAMIC; mAttributes[ATTR_TEXCOORDS2D_0 + unit] = NONE; } 00117 00118 bool hasIndices() const { return hasStaticIndices() || hasDynamicIndices(); } 00119 bool hasStaticIndices() const { return mAttributes[ATTR_INDICES] == STATIC; } 00120 bool hasDynamicIndices() const { return mAttributes[ATTR_INDICES] == DYNAMIC; } 00121 void setStaticIndices() { mAttributes[ATTR_INDICES] = STATIC; } 00122 void setDynamicIndices() { mAttributes[ATTR_INDICES] = DYNAMIC; } 00123 00124 bool hasPositions() const { return hasStaticPositions() || hasDynamicPositions(); } 00125 bool hasStaticPositions() const { return mAttributes[ATTR_POSITIONS] == STATIC; } 00126 bool hasDynamicPositions() const { return mAttributes[ATTR_POSITIONS] == DYNAMIC; } 00127 void setStaticPositions() { mAttributes[ATTR_POSITIONS] = STATIC; } 00128 void setDynamicPositions() { mAttributes[ATTR_POSITIONS] = DYNAMIC; } 00129 00130 enum CustomAttr { CUSTOM_ATTR_FLOAT, CUSTOM_ATTR_FLOAT2, CUSTOM_ATTR_FLOAT3, CUSTOM_ATTR_FLOAT4, TOTAL_CUSTOM_ATTR_TYPES }; 00131 static int sCustomAttrSizes[TOTAL_CUSTOM_ATTR_TYPES]; 00132 static GLint sCustomAttrNumComponents[TOTAL_CUSTOM_ATTR_TYPES]; 00133 static GLenum sCustomAttrTypes[TOTAL_CUSTOM_ATTR_TYPES]; 00134 void addDynamicCustomFloat() { mCustomDynamic.push_back( std::make_pair( CUSTOM_ATTR_FLOAT, 0 ) ); } 00135 void addDynamicCustomVec2f() { mCustomDynamic.push_back( std::make_pair( CUSTOM_ATTR_FLOAT2, 0 ) ); } 00136 void addDynamicCustomVec3f() { mCustomDynamic.push_back( std::make_pair( CUSTOM_ATTR_FLOAT3, 0 ) ); } 00137 void addDynamicCustomVec4f() { mCustomDynamic.push_back( std::make_pair( CUSTOM_ATTR_FLOAT4, 0 ) ); } 00138 00139 int mAttributes[ATTR_TOTAL]; 00140 std::vector<std::pair<CustomAttr,size_t> > mCustomDynamic, mCustomStatic; // pair of <types,offset> 00141 00142 private: 00143 void initAttributes() { for( int a = 0; a < ATTR_TOTAL; ++a ) mAttributes[a] = NONE; } 00144 }; 00145 00146 enum { INDEX_BUFFER = 0, STATIC_BUFFER, DYNAMIC_BUFFER, TOTAL_BUFFERS }; 00147 00148 protected: 00149 struct Obj { 00150 size_t mNumIndices, mNumVertices; 00151 00152 Vbo mBuffers[TOTAL_BUFFERS]; 00153 size_t mPositionOffset; 00154 size_t mNormalOffset; 00155 size_t mColorRGBOffset, mColorRGBAOffset; 00156 size_t mTexCoordOffset[ATTR_MAX_TEXTURE_UNIT+1]; 00157 size_t mStaticStride, mDynamicStride; 00158 GLenum mPrimitiveType; 00159 Layout mLayout; 00160 std::vector<GLint> mCustomStaticLocations; 00161 std::vector<GLint> mCustomDynamicLocations; 00162 }; 00163 00164 public: 00165 class VertexIter; 00166 00167 VboMesh() {} 00168 explicit VboMesh( const TriMesh &triMesh, Layout layout = Layout() ); 00169 /*** Creates a VboMesh with \a numVertices vertices and \a numIndices indices. Dynamic data is stored interleaved and static data is planar. **/ 00170 VboMesh( size_t numVertices, size_t numIndices, Layout layout, GLenum primitiveType ); 00171 /*** Creates a VboMesh with \a numVertices vertices and \a numIndices indices. Accepts pointers to preexisting buffers, which may be NULL to request allocation **/ 00172 VboMesh( size_t numVertices, size_t numIndices, Layout layout, GLenum primitiveType, Vbo *indexBuffer, Vbo *staticBuffer, Vbo *dynamicBuffer ); 00173 00174 size_t getNumIndices() const { return mObj->mNumIndices; } 00175 size_t getNumVertices() const { return mObj->mNumVertices; } 00176 GLenum getPrimitiveType() const { return mObj->mPrimitiveType; } 00177 00178 const Layout& getLayout() const { return mObj->mLayout; } 00179 00180 void bindIndexBuffer() const; 00181 void enableClientStates() const; 00182 void disableClientStates() const; 00183 void bindAllData() const; 00184 static void unbindBuffers(); 00185 00186 void bufferIndices( const std::vector<uint32_t> &indices ); 00187 void bufferPositions( const std::vector<Vec3f> &positions ); 00188 void bufferPositions( const Vec3f *positions, size_t count ); 00189 void bufferNormals( const std::vector<Vec3f> &normals ); 00190 void bufferTexCoords2d( size_t unit, const std::vector<Vec2f> &texCoords ); 00191 class VertexIter mapVertexBuffer(); 00192 00193 Vbo& getIndexVbo() const { return mObj->mBuffers[INDEX_BUFFER]; } 00194 Vbo& getStaticVbo() const { return mObj->mBuffers[STATIC_BUFFER]; } 00195 Vbo& getDynamicVbo() const { return mObj->mBuffers[DYNAMIC_BUFFER]; } 00196 00197 void setCustomStaticLocation( size_t internalIndex, GLuint location ) { mObj->mCustomStaticLocations[internalIndex] = location; } 00198 void setCustomDynamicLocation( size_t internalIndex, GLuint location ) { mObj->mCustomDynamicLocations[internalIndex] = location; } 00199 00200 size_t getTexCoordOffset( size_t unit ) const { return mObj->mTexCoordOffset[unit]; } 00201 void setTexCoordOffset( size_t unit, size_t aTexCoordOffset ) { mObj->mTexCoordOffset[unit] = aTexCoordOffset; } 00202 00204 00205 typedef shared_ptr<Obj> VboMesh::*unspecified_bool_type; 00206 operator unspecified_bool_type() const { return ( mObj.get() == 0 ) ? 0 : &VboMesh::mObj; } 00207 void reset() { mObj.reset(); } 00209 00210 class VertexIter { 00211 public: 00212 VertexIter( const VboMesh &mesh ); 00213 00214 void setPosition( const Vec3f &v ) { *(reinterpret_cast<Vec3f*>( &mPtr[mPositionOffset] )) = v; } 00215 void setPosition( float x, float y, float z ) { *(reinterpret_cast<Vec3f*>( &mPtr[mPositionOffset] )) = Vec3f( x, y, z ); } 00216 void setNormal( const Vec3f &n ) { *(reinterpret_cast<Vec3f*>( &mPtr[mNormalOffset] )) = n; } 00217 void setColorRGB( const Color &n ) { *(reinterpret_cast<Color*>( &mPtr[mColorRGBOffset] )) = n; } 00218 void setColorRGBA( const ColorA &n ) { *(reinterpret_cast<ColorA*>( &mPtr[mColorRGBAOffset] )) = n; } 00219 void setTexCoord2d0( const Vec2f &t ) { *(reinterpret_cast<Vec2f*>( &mPtr[mTexCoordOffset[0]] )) = t; } 00220 void setTexCoord3d0( const Vec3f &t ) { *(reinterpret_cast<Vec3f*>( &mPtr[mTexCoordOffset[0]] )) = t; } 00221 void setTexCoord2d1( const Vec2f &t ) { *(reinterpret_cast<Vec2f*>( &mPtr[mTexCoordOffset[1]] )) = t; } 00222 void setTexCoord3d1( const Vec3f &t ) { *(reinterpret_cast<Vec3f*>( &mPtr[mTexCoordOffset[1]] )) = t; } 00223 void setTexCoord2d2( const Vec2f &t ) { *(reinterpret_cast<Vec2f*>( &mPtr[mTexCoordOffset[2]] )) = t; } 00224 void setTexCoord3d2( const Vec3f &t ) { *(reinterpret_cast<Vec3f*>( &mPtr[mTexCoordOffset[2]] )) = t; } 00225 void setCustomFloat( size_t index, float v ) { *(reinterpret_cast<float*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; } 00226 void setCustomVec2f( size_t index, const Vec2f &v ) { *(reinterpret_cast<Vec2f*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; } 00227 void setCustomVec3f( size_t index, const Vec3f &v ) { *(reinterpret_cast<Vec3f*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; } 00228 void setCustomVec4f( size_t index, const Vec4f &v ) { *(reinterpret_cast<Vec4f*>( &mPtr[mObj->mCustomOffsets[index]] )) = v; } 00229 00230 void operator++() { mPtr += mStride; } 00231 bool isDone() const { return mPtr < mDataEnd; } 00232 00234 size_t getIndex() const { return ( mPtr - mData ) / mStride; } 00236 size_t getStride() const { return mStride; } 00238 void* getPointer() const { return reinterpret_cast<void*>( mPtr ); } 00240 Vec3f* getPositionPointer() const { return reinterpret_cast<Vec3f*>( &mPtr[mPositionOffset] ); } 00241 00242 // VertexIter( const VertexIter &other ) { set( other ); } 00243 // VertexIter& operator=( const VertexIter &other ) { set( other ); return *this; } 00244 00245 protected: 00246 void set( const VertexIter &other ); 00247 00248 struct Obj { 00249 public: 00250 Obj( const VboMesh &mesh ); 00251 ~Obj(); 00252 00253 uint8_t *mData, *mDataEnd; 00254 std::vector<size_t> mCustomOffsets; 00255 Vbo mVbo; 00256 }; 00257 00258 shared_ptr<Obj> mObj; 00259 uint8_t *mPtr; 00260 uint8_t *mData, *mDataEnd; // we cache these from the Obj to reduce dereferencing 00261 size_t mPositionOffset, mNormalOffset; 00262 size_t mColorRGBOffset, mColorRGBAOffset; 00263 size_t mTexCoordOffset[ATTR_MAX_TEXTURE_UNIT+1]; 00264 uint8_t mStride; 00265 }; 00266 00267 protected: 00268 void initializeBuffers( bool staticDataPlanar ); 00269 00270 shared_ptr<Obj> mObj; 00271 }; 00272 00273 class VboExc : public std::exception { 00274 public: 00275 virtual const char* what() const throw() { return "OpenGL Vbo exception"; } 00276 }; 00277 00278 class VboInvalidTargetExc : public VboExc { 00279 public: 00280 virtual const char* what() const throw() { return "OpenGL Vbo exception: Invalid Target"; } 00281 }; 00282 00283 class VboFailedMapExc : public VboExc { 00284 public: 00285 virtual const char* what() const throw() { return "OpenGL Vbo exception: Map failure"; } 00286 }; 00287 00288 class VboFailedUnmapExc : public VboExc { 00289 public: 00290 virtual const char* what() const throw() { return "OpenGL Vbo exception: Unmap failure"; } 00291 }; 00292 00293 } } // namespace cinder::gl