/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #include #include using namespace osg; const Geometry::ArrayData Geometry::s_InvalidArrayData; #if 1 class DrawVertex { public: DrawVertex(const Array* vertices,const IndexArray* indices): _vertices(vertices), _indices(indices) { _verticesType = _vertices?_vertices->getType():Array::ArrayType; _indicesType = _indices?_indices->getType():Array::ArrayType; } inline unsigned int index(unsigned int pos) { switch(_indicesType) { case(Array::ByteArrayType): return (*static_cast(_indices))[pos]; case(Array::ShortArrayType): return (*static_cast(_indices))[pos]; case(Array::IntArrayType): return (*static_cast(_indices))[pos]; case(Array::UByteArrayType): return (*static_cast(_indices))[pos]; case(Array::UShortArrayType): return (*static_cast(_indices))[pos]; case(Array::UIntArrayType): return (*static_cast(_indices))[pos]; default: return 0; } } inline void operator () (unsigned int pos) { if (_indices) pos = index(pos); switch(_verticesType) { case(Array::Vec3ArrayType): apply((*(static_cast(_vertices)))[pos]); break; case(Array::Vec2ArrayType): apply((*(static_cast(_vertices)))[pos]); break; case(Array::Vec4ArrayType): apply((*(static_cast(_vertices)))[pos]); break; default: break; } } inline void apply(const Vec2& v) { glVertex2fv(v.ptr()); } inline void apply(const Vec3& v) { glVertex3fv(v.ptr()); } inline void apply(const Vec4& v) { glVertex4fv(v.ptr()); } const Array* _vertices; const IndexArray* _indices; Array::Type _verticesType; Array::Type _indicesType; }; #else class DrawVertex : public osg::ConstValueVisitor { public: DrawVertex(const Array* vertices,const IndexArray* indices): _vertices(vertices), _indices(indices) {} inline void operator () (unsigned int pos) { if (_indices) _vertices->accept(_indices->index(pos),*this); else _vertices->accept(pos,*this); } virtual void apply(const Vec2& v) { glVertex2fv(v.ptr()); } virtual void apply(const Vec3& v) { glVertex3fv(v.ptr()); } virtual void apply(const Vec4& v) { glVertex4fv(v.ptr()); } const Array* _vertices; const IndexArray* _indices; }; #endif class DrawNormal { public: DrawNormal(const Vec3Array* normals,const IndexArray* indices): _normals(normals), _indices(indices) {} void operator () (unsigned int pos) { if (_indices) glNormal3fv((*_normals)[_indices->index(pos)].ptr()); else glNormal3fv((*_normals)[pos].ptr()); } const Vec3Array* _normals; const IndexArray* _indices; }; #if 1 class DrawColor { public: DrawColor(const Array* colors,const IndexArray* indices): _colors(colors), _indices(indices) { _colorsType = _colors?_colors->getType():Array::ArrayType; _indicesType = _indices?_indices->getType():Array::ArrayType; } inline unsigned int index(unsigned int pos) { switch(_indicesType) { case(Array::ByteArrayType): return (*static_cast(_indices))[pos]; case(Array::ShortArrayType): return (*static_cast(_indices))[pos]; case(Array::IntArrayType): return (*static_cast(_indices))[pos]; case(Array::UByteArrayType): return (*static_cast(_indices))[pos]; case(Array::UShortArrayType): return (*static_cast(_indices))[pos]; case(Array::UIntArrayType): return (*static_cast(_indices))[pos]; default: return 0; } } inline void operator () (unsigned int pos) { if (_indices) pos = index(pos); switch(_colorsType) { case(Array::Vec4ArrayType): apply((*static_cast(_colors))[pos]); break; case(Array::UByte4ArrayType): apply((*static_cast(_colors))[pos]); break; case(Array::Vec3ArrayType): apply((*static_cast(_colors))[pos]); break; default: break; } } inline void apply(const UByte4& v) { glColor4ubv(v.ptr()); } inline void apply(const Vec3& v) { glColor3fv(v.ptr()); } inline void apply(const Vec4& v) { glColor4fv(v.ptr()); } const Array* _colors; const IndexArray* _indices; Array::Type _colorsType; Array::Type _indicesType; }; #else class DrawColor : public osg::ConstValueVisitor { public: DrawColor(const Array* colors,const IndexArray* indices): _colors(colors), _indices(indices) {} inline void operator () (unsigned int pos) { if (_indices) _colors->accept(_indices->index(pos),*this); else _colors->accept(pos,*this); } virtual void apply(const UByte4& v) { glColor4ubv(v.ptr()); } virtual void apply(const Vec3& v) { glColor3fv(v.ptr()); } virtual void apply(const Vec4& v) { glColor4fv(v.ptr()); } const Array* _colors; const IndexArray* _indices; }; #endif class DrawVertexAttrib : public osg::Referenced, public osg::ConstValueVisitor { public: DrawVertexAttrib(const Drawable::Extensions * extensions,unsigned int vertAttribIndex,GLboolean normalized,const Array* attribcoords,const IndexArray* indices): _vertAttribIndex(vertAttribIndex), _normalized(normalized), _extensions(extensions), _attribcoords(attribcoords), _indices(indices), _index(0) {;} inline void applyAndIncrement() { operator()(_index++); } inline void operator () (unsigned int pos) { if (_indices) _attribcoords->accept(_indices->index(pos),*this); else _attribcoords->accept(pos,*this); } virtual void apply(const GLshort& s) { _extensions->glVertexAttrib1s( _vertAttribIndex, s ); } virtual void apply(const GLfloat& f) { _extensions->glVertexAttrib1f( _vertAttribIndex, f ); } virtual void apply(const UByte4& v) { if( _normalized ) { _extensions->glVertexAttrib4Nubv( _vertAttribIndex, v.ptr() ); } else { _extensions->glVertexAttrib4ubv( _vertAttribIndex, v.ptr() ); } } virtual void apply(const Vec2& v) { _extensions->glVertexAttrib2fv( _vertAttribIndex, v.ptr() ); } virtual void apply(const Vec3& v) { _extensions->glVertexAttrib3fv( _vertAttribIndex, v.ptr() ); } virtual void apply(const Vec4& v) { _extensions->glVertexAttrib4fv( _vertAttribIndex, v.ptr() ); } unsigned int _vertAttribIndex; GLboolean _normalized; const Drawable::Extensions* _extensions; const Array* _attribcoords; const IndexArray* _indices; unsigned int _index; }; class DrawTexCoord : public osg::Referenced, public osg::ConstValueVisitor { public: DrawTexCoord(const Array* texcoords,const IndexArray* indices): _texcoords(texcoords), _indices(indices) {} inline void operator () (unsigned int pos) { if (_indices) _texcoords->accept(_indices->index(pos),*this); else _texcoords->accept(pos,*this); } virtual void apply(const GLfloat& v){ glTexCoord1f(v); } virtual void apply(const Vec2& v) { glTexCoord2fv(v.ptr()); } virtual void apply(const Vec3& v) { glTexCoord3fv(v.ptr()); } virtual void apply(const Vec4& v) { glTexCoord4fv(v.ptr()); } const Array* _texcoords; const IndexArray* _indices; }; class DrawMultiTexCoord : public osg::Referenced, public osg::ConstValueVisitor { public: DrawMultiTexCoord(GLenum target,const Array* texcoords,const IndexArray* indices, const Drawable::Extensions * extensions): _target(target), _texcoords(texcoords), _indices(indices), _extensions(extensions) {} inline void operator () (unsigned int pos) { if (_indices) _texcoords->accept(_indices->index(pos),*this); else _texcoords->accept(pos,*this); } virtual void apply(const GLfloat& v){ _extensions->glMultiTexCoord1f(_target,v); } virtual void apply(const Vec2& v) { _extensions->glMultiTexCoord2fv(_target,v.ptr()); } virtual void apply(const Vec3& v) { _extensions->glMultiTexCoord3fv(_target,v.ptr()); } virtual void apply(const Vec4& v) { _extensions->glMultiTexCoord4fv(_target,v.ptr()); } GLenum _target; const Array* _texcoords; const IndexArray* _indices; const Drawable::Extensions * _extensions; }; class DrawSecondaryColor : public osg::ConstValueVisitor { public: DrawSecondaryColor(const Array* colors,const IndexArray* indices, const Drawable::Extensions * extensions): _colors(colors), _indices(indices), _extensions(extensions) {} inline void operator () (unsigned int pos) { if (_indices) _colors->accept(_indices->index(pos),*this); else _colors->accept(pos,*this); } virtual void apply(const UByte4& v) { _extensions->glSecondaryColor3ubv(v.ptr()); } virtual void apply(const Vec3& v) { _extensions->glSecondaryColor3fv(v.ptr()); } virtual void apply(const Vec4& v) { _extensions->glSecondaryColor3fv(v.ptr()); } const Array* _colors; const IndexArray* _indices; const Drawable::Extensions * _extensions; }; class DrawFogCoord : public osg::ConstValueVisitor { public: DrawFogCoord(const Array* fogcoords,const IndexArray* indices,const Drawable::Extensions * extensions): _fogcoords(fogcoords), _indices(indices), _extensions(extensions) {} inline void operator () (unsigned int pos) { if (_indices) _fogcoords->accept(_indices->index(pos),*this); else _fogcoords->accept(pos,*this); } virtual void apply(const GLfloat& v) { _extensions->glFogCoordfv(&v); } const Array* _fogcoords; const IndexArray* _indices; const Drawable::Extensions * _extensions; }; Geometry::ArrayData::ArrayData(const ArrayData& data,const CopyOp& copyop): array(data.array.valid()?dynamic_cast(data.array->clone(copyop)):0), indices(data.indices.valid()?dynamic_cast(data.indices->clone(copyop)):0), binding(data.binding), normalize(data.normalize), offset(data.offset) { } Geometry::Vec3ArrayData::Vec3ArrayData(const Vec3ArrayData& data,const CopyOp& copyop): array(data.array.valid()?dynamic_cast(data.array->clone(copyop)):0), indices(data.indices.valid()?dynamic_cast(data.indices->clone(copyop)):0), binding(data.binding), normalize(data.normalize), offset(data.offset) { } Geometry::Geometry() { _fastPath = false; _fastPathHint = true; } Geometry::Geometry(const Geometry& geometry,const CopyOp& copyop): Drawable(geometry,copyop), _vertexData(geometry._vertexData,copyop), _normalData(geometry._normalData,copyop), _colorData(geometry._colorData,copyop), _secondaryColorData(geometry._secondaryColorData,copyop), _fogCoordData(geometry._fogCoordData,copyop), _fastPath(geometry._fastPath), _fastPathHint(geometry._fastPathHint) { for(PrimitiveSetList::const_iterator pitr=geometry._primitives.begin(); pitr!=geometry._primitives.end(); ++pitr) { PrimitiveSet* primitive = copyop(pitr->get()); if (primitive) _primitives.push_back(primitive); } for(ArrayList::const_iterator titr=geometry._texCoordList.begin(); titr!=geometry._texCoordList.end(); ++titr) { _texCoordList.push_back(*titr); } for(ArrayList::const_iterator vitr=geometry._vertexAttribList.begin(); vitr!=geometry._vertexAttribList.end(); ++vitr) { _vertexAttribList.push_back(*vitr); } } Geometry::~Geometry() { // no need to delete, all automatically handled by ref_ptr :-) } void Geometry::setTexCoordData(unsigned int unit,const ArrayData& arrayData) { if (_texCoordList.size()<=unit) _texCoordList.resize(unit+1); _texCoordList[unit] = arrayData; } Geometry::ArrayData& Geometry::getTexCoordData(unsigned int unit) { if (_texCoordList.size()<=unit) _texCoordList.resize(unit+1); return _texCoordList[unit]; } const Geometry::ArrayData& Geometry::getTexCoordData(unsigned int unit) const { if (_texCoordList.size()<=unit) return s_InvalidArrayData; return _texCoordList[unit]; } void Geometry::setTexCoordArray(unsigned int unit,Array* array) { getTexCoordData(unit).binding = BIND_PER_VERTEX; getTexCoordData(unit).array = array; computeFastPathsUsed(); dirtyDisplayList(); } Array* Geometry::getTexCoordArray(unsigned int unit) { if (unit<_texCoordList.size()) return _texCoordList[unit].array.get(); else return 0; } const Array* Geometry::getTexCoordArray(unsigned int unit) const { if (unit<_texCoordList.size()) return _texCoordList[unit].array.get(); else return 0; } void Geometry::setTexCoordIndices(unsigned int unit,IndexArray* array) { getTexCoordData(unit).indices = array; computeFastPathsUsed(); dirtyDisplayList(); } IndexArray* Geometry::getTexCoordIndices(unsigned int unit) { if (unit<_texCoordList.size()) return _texCoordList[unit].indices.get(); else return 0; } const IndexArray* Geometry::getTexCoordIndices(unsigned int unit) const { if (unit<_texCoordList.size()) return _texCoordList[unit].indices.get(); else return 0; } void Geometry::setVertexAttribData(unsigned int index, const Geometry::ArrayData& attrData) { if (_vertexAttribList.size()<=index) _vertexAttribList.resize(index+1); _vertexAttribList[index] = attrData; } Geometry::ArrayData& Geometry::getVertexAttribData(unsigned int index) { if (_vertexAttribList.size()<=index) _vertexAttribList.resize(index+1); return _vertexAttribList[index]; } const Geometry::ArrayData& Geometry::getVertexAttribData(unsigned int index) const { if (_vertexAttribList.size()<=_vertexAttribList.size()) return s_InvalidArrayData; return _vertexAttribList[index]; } void Geometry::setVertexAttribArray(unsigned int index, Array* array) { getVertexAttribData(index).array = array; computeFastPathsUsed(); dirtyDisplayList(); } Array *Geometry::getVertexAttribArray(unsigned int index) { if (index<_vertexAttribList.size()) return _vertexAttribList[index].array.get(); else return 0; } const Array *Geometry::getVertexAttribArray(unsigned int index) const { if (index<_vertexAttribList.size()) return _vertexAttribList[index].array.get(); else return 0; } void Geometry::setVertexAttribIndices(unsigned int index,IndexArray* array) { getVertexAttribData(index).indices = array; computeFastPathsUsed(); dirtyDisplayList(); } IndexArray* Geometry::getVertexAttribIndices(unsigned int index) { if (index<_vertexAttribList.size()) return _vertexAttribList[index].indices.get(); else return 0; } const IndexArray* Geometry::getVertexAttribIndices(unsigned int index) const { if (index<_vertexAttribList.size()) return _vertexAttribList[index].indices.get(); else return 0; } void Geometry::setVertexAttribBinding(unsigned int index,AttributeBinding ab) { getVertexAttribData(index).binding = ab; computeFastPathsUsed(); dirtyDisplayList(); } Geometry::AttributeBinding Geometry::getVertexAttribBinding(unsigned int index) const { if (index<_vertexAttribList.size()) return _vertexAttribList[index].binding; else return BIND_OFF; } void Geometry::setVertexAttribNormalize(unsigned int index,GLboolean norm) { getVertexAttribData(index).normalize = norm; dirtyDisplayList(); } GLboolean Geometry::getVertexAttribNormalize(unsigned int index) const { if (index<_vertexAttribList.size()) return _vertexAttribList[index].normalize; else return GL_FALSE; } bool Geometry::addPrimitiveSet(PrimitiveSet* primitiveset) { if (primitiveset) { _primitives.push_back(primitiveset); dirtyDisplayList(); dirtyBound(); return true; } notify(WARN)<<"Warning: invalid index i or primitiveset passed to osg::Geometry::addPrimitiveSet(i,primitiveset), ignoring call."<0) { if (i+numElementsToRemove<=_primitives.size()) { _primitives.erase(_primitives.begin()+i,_primitives.begin()+i+numElementsToRemove); } else { // asking to delete too many elements, report a warning, and delete to // the end of the primitive list. notify(WARN)<<"Warning: osg::Geometry::removePrimitiveSet(i,numElementsToRemove) has been asked to remove more elements than are available,"<getNumElements()>0 && idxArray && idxArray->getNumElements()>0 ) { _fastPath = false; break; } } } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Set up tex coords if required. // for(unsigned int unit=0;unit!=_texCoordList.size();++unit) { const ArrayData& texcoordData = _texCoordList[unit]; if (texcoordData.array.valid() && texcoordData.array->getNumElements()>0) { if (texcoordData.indices.valid()) { if (texcoordData.indices->getNumElements()>0) { _fastPath = false; break; } } } } _supportsVertexBufferObjects = _fastPath; //_supportsVertexBufferObjects = false; //_useVertexBufferObjects = false; return _fastPath; } void Geometry::drawImplementation(State& state) const { if (_internalOptimizedGeometry.valid()) { _internalOptimizedGeometry->drawImplementation(state); return; } const Extensions* extensions = getExtensions(state.getContextID(),true); if( !( ( _vertexData.array.valid() && _vertexData.array->getNumElements() != 0 ) || ( _vertexAttribList.size() > 0 && _vertexAttribList[0].array.valid() && _vertexAttribList[0].array->getNumElements() != 0 ) ) ) { return; } if( ( _vertexData.indices.valid() && _vertexData.indices->getNumElements() == 0 ) || ( _vertexAttribList.size() > 0 && _vertexAttribList[0].indices.valid() && _vertexAttribList[0].indices->getNumElements() == 0 ) ) { return; } DrawNormal drawNormal(_normalData.array.get(),_normalData.indices.get()); DrawColor drawColor(_colorData.array.get(),_colorData.indices.get()); DrawSecondaryColor drawSecondaryColor(_secondaryColorData.array.get(),_secondaryColorData.indices.get(),extensions); DrawFogCoord drawFogCoord(_fogCoordData.array.get(),_fogCoordData.indices.get(),extensions); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Set up secondary color if required. // AttributeBinding secondaryColorBinding = _secondaryColorData.binding; if (secondaryColorBinding!=BIND_OFF && !extensions->isSecondaryColorSupported()) { // switch off if not supported or have a valid data. secondaryColorBinding = BIND_OFF; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Set up fog coord if required. // AttributeBinding fogCoordBinding = _fogCoordData.binding; if (fogCoordBinding!=BIND_OFF && !extensions->isFogCoordSupported()) { // switch off if not supported or have a valid data. fogCoordBinding = BIND_OFF; } unsigned int normalIndex = 0; unsigned int colorIndex = 0; unsigned int secondaryColorIndex = 0; unsigned int fogCoordIndex = 0; #if USE_DEFAULT_NORMAL // if no values are defined for normal and color provide some defaults... if (_normalData.binding==BIND_OFF) glNormal3f(0.0f,0.0f,1.0f); #endif #if USE_DEFAULT_COLOUR if (_colorData.binding==BIND_OFF) glColor4f(1.0f,1.0f,1.0f,1.0f); #endif typedef std::vector< ref_ptr > DrawVertexAttribList; typedef std::map< Geometry::AttributeBinding, DrawVertexAttribList> DrawVertexAttribMap; DrawVertexAttribMap drawVertexAttribMap; bool vertexVertexAttributesSupported = extensions->isVertexProgramSupported(); bool handleVertexAttributes = (!_vertexAttribList.empty() && vertexVertexAttributesSupported); bool usingVertexBufferObjects = _useVertexBufferObjects && state.isVertexBufferObjectSupported(); if (areFastPathsUsed()) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // fast path. // if (usingVertexBufferObjects) { // // Vertex Buffer Object path for defining vertex arrays. // GLuint& buffer = _vboList[state.getContextID()]; if (!buffer) { //std::cout << "creating VertexBuffer "<glGenBuffers(1, &buffer); extensions->glBindBuffer(GL_ARRAY_BUFFER_ARB,buffer); //std::cout << " gen VertexBuffer "<getTotalDataSize(); _normalData.offset = totalSize; if (_normalData.array.valid()) totalSize += _normalData.array->getTotalDataSize(); _colorData.offset = totalSize; if (_colorData.array.valid()) totalSize += _colorData.array->getTotalDataSize(); _secondaryColorData.offset = totalSize; if (_secondaryColorData.array.valid()) totalSize += _secondaryColorData.array->getTotalDataSize(); _fogCoordData.offset = totalSize; if (_fogCoordData.array.valid()) totalSize += _fogCoordData.array->getTotalDataSize(); unsigned int unit; for(unit=0;unit<_texCoordList.size();++unit) { _texCoordList[unit].offset = totalSize; const Array* array = _texCoordList[unit].array.get(); if (array) totalSize += array->getTotalDataSize(); } if( handleVertexAttributes ) { unsigned int index; for( index = 0; index < _vertexAttribList.size(); ++index ) { _texCoordList[unit].offset = totalSize; const Array* array = _vertexAttribList[index].array.get(); const AttributeBinding ab = _vertexAttribList[index].binding; if( ab == BIND_PER_VERTEX && array ) { totalSize += array->getTotalDataSize(); } } } // allocated the buffer space, but leave the copy to be done per vertex array below extensions->glBufferData(GL_ARRAY_BUFFER_ARB,totalSize, 0, GL_STATIC_DRAW_ARB); //std::cout << " Created VertexBuffer "<glBindBuffer(GL_ARRAY_BUFFER_ARB,buffer); if( _vertexData.array.valid() ) state.setVertexPointer(_vertexData.array->getDataSize(),_vertexData.array->getDataType(),0,(const GLvoid*)_vertexData.offset); else state.disableVertexPointer(); if (_normalData.binding==BIND_PER_VERTEX) state.setNormalPointer(GL_FLOAT,0,(const GLvoid*)_normalData.offset); else state.disableNormalPointer(); if (_colorData.binding==BIND_PER_VERTEX) state.setColorPointer(_colorData.array->getDataSize(),_colorData.array->getDataType(),0,(const GLvoid*)_colorData.offset); else state.disableColorPointer(); if (secondaryColorBinding==BIND_PER_VERTEX) state.setSecondaryColorPointer(_secondaryColorData.array->getDataSize(),_secondaryColorData.array->getDataType(),0,(const GLvoid*)_secondaryColorData.offset); else state.disableSecondaryColorPointer(); if (fogCoordBinding==BIND_PER_VERTEX) state.setFogCoordPointer(GL_FLOAT,0,(const GLvoid*)_fogCoordData.offset); else state.disableFogCoordPointer(); unsigned int unit; for(unit=0;unit<_texCoordList.size();++unit) { const Array* array = _texCoordList[unit].array.get(); if (array) state.setTexCoordPointer(unit,array->getDataSize(),array->getDataType(),0,(const GLvoid*)_texCoordList[unit].offset); else state.disableTexCoordPointer(unit); } state.disableTexCoordPointersAboveAndIncluding(unit); if( handleVertexAttributes ) { unsigned int index; for( index = 0; index < _vertexAttribList.size(); ++index ) { const Array* array = _vertexAttribList[index].array.get(); const AttributeBinding ab = _vertexAttribList[index].binding; if( ab == BIND_PER_VERTEX && array ) { state.setVertexAttribPointer( index, array->getDataSize(), array->getDataType(), _vertexAttribList[index].normalize, 0, (const GLvoid*)_vertexAttribList[index].offset ); } else { if( array ) { const IndexArray* indexArray = _vertexAttribList[index].indices.get(); if( indexArray && indexArray->getNumElements() > 0 ) { drawVertexAttribMap[ab].push_back( new DrawVertexAttrib(extensions,index,_vertexAttribList[index].normalize,array,indexArray) ); } else { drawVertexAttribMap[ab].push_back( new DrawVertexAttrib(extensions,index,_vertexAttribList[index].normalize,array,0) ); } } state.disableVertexAttribPointer( index ); } } state.disableVertexAttribPointersAboveAndIncluding( index ); } else if (vertexVertexAttributesSupported) { state.disableVertexAttribPointersAboveAndIncluding( 0 ); } } else { //std::cout << "none VertexBuffer path"<getDataSize(),_vertexData.array->getDataType(),0,_vertexData.array->getDataPointer()); else state.disableVertexPointer(); if (_normalData.binding==BIND_PER_VERTEX) state.setNormalPointer(GL_FLOAT,0,_normalData.array->getDataPointer()); else state.disableNormalPointer(); if (_colorData.binding==BIND_PER_VERTEX) state.setColorPointer(_colorData.array->getDataSize(),_colorData.array->getDataType(),0,_colorData.array->getDataPointer()); else state.disableColorPointer(); if (secondaryColorBinding==BIND_PER_VERTEX) state.setSecondaryColorPointer(_secondaryColorData.array->getDataSize(),_secondaryColorData.array->getDataType(),0,_secondaryColorData.array->getDataPointer()); else state.disableSecondaryColorPointer(); if (fogCoordBinding==BIND_PER_VERTEX) state.setFogCoordPointer(GL_FLOAT,0,_fogCoordData.array->getDataPointer()); else state.disableFogCoordPointer(); unsigned int unit; for(unit=0;unit<_texCoordList.size();++unit) { const Array* array = _texCoordList[unit].array.get(); if (array) state.setTexCoordPointer(unit,array->getDataSize(),array->getDataType(),0,array->getDataPointer()); else state.disableTexCoordPointer(unit); } state.disableTexCoordPointersAboveAndIncluding(unit); if( handleVertexAttributes ) { unsigned int index; for( index = 0; index < _vertexAttribList.size(); ++index ) { const Array* array = _vertexAttribList[index].array.get(); const AttributeBinding ab = _vertexAttribList[index].binding; if( ab == BIND_PER_VERTEX && array ) { state.setVertexAttribPointer( index, array->getDataSize(), array->getDataType(), _vertexAttribList[index].normalize, 0, array->getDataPointer() ); } else { if( array ) { const IndexArray* indexArray = _vertexAttribList[index].indices.get(); if( indexArray && indexArray->getNumElements() > 0 ) { drawVertexAttribMap[ab].push_back( new DrawVertexAttrib(extensions,index,_vertexAttribList[index].normalize,array,indexArray) ); } else { drawVertexAttribMap[ab].push_back( new DrawVertexAttrib(extensions,index,_vertexAttribList[index].normalize,array,0) ); } } state.disableVertexAttribPointer( index ); } } state.disableVertexAttribPointersAboveAndIncluding( index ); } else if (vertexVertexAttributesSupported) { state.disableVertexAttribPointersAboveAndIncluding( 0 ); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // pass the overall binding values onto OpenGL. // if (_normalData.binding==BIND_OVERALL) drawNormal(normalIndex++); if (_colorData.binding==BIND_OVERALL) drawColor(colorIndex++); if (secondaryColorBinding==BIND_OVERALL) drawSecondaryColor(secondaryColorIndex++); if (fogCoordBinding==BIND_OVERALL) drawFogCoord(fogCoordIndex++); if (handleVertexAttributes) { DrawVertexAttribList &list = drawVertexAttribMap[BIND_OVERALL]; for( unsigned int i = 0; i < list.size(); ++i ) { list[i]->applyAndIncrement(); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // draw the primitives themselves. // for(PrimitiveSetList::const_iterator itr=_primitives.begin(); itr!=_primitives.end(); ++itr) { if (_normalData.binding==BIND_PER_PRIMITIVE_SET) drawNormal(normalIndex++); if (_colorData.binding==BIND_PER_PRIMITIVE_SET) drawColor(colorIndex++); if (secondaryColorBinding==BIND_PER_PRIMITIVE_SET) drawSecondaryColor(secondaryColorIndex++); if (fogCoordBinding==BIND_PER_PRIMITIVE_SET) drawFogCoord(fogCoordIndex++); if (handleVertexAttributes) { DrawVertexAttribList &list = drawVertexAttribMap[BIND_PER_PRIMITIVE_SET]; for( unsigned int i = 0; i < list.size(); ++i ) { list[i]->applyAndIncrement(); } } (*itr)->draw(); } if (usingVertexBufferObjects) { extensions->glBindBuffer(GL_ARRAY_BUFFER_ARB,0); } } else { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // slow path. // typedef std::vector< ref_ptr > DrawTexCoordList; DrawTexCoordList drawTexCoordList; drawTexCoordList.reserve(_texCoordList.size()); // fallback if multitexturing not supported. ref_ptr drawTextCoord; if (extensions->isMultiTexSupported() && _texCoordList.size()>1) { // multitexture supported.. for(unsigned int unit=0;unit!=_texCoordList.size();++unit) { const ArrayData& texcoordData = _texCoordList[unit]; if (texcoordData.array.valid() && texcoordData.array->getNumElements()>0) { if (texcoordData.indices.valid() && texcoordData.indices->getNumElements()>0) { drawTexCoordList.push_back(new DrawMultiTexCoord(GL_TEXTURE0+unit,texcoordData.array.get(),texcoordData.indices.get(), extensions)); } else { drawTexCoordList.push_back(new DrawMultiTexCoord(GL_TEXTURE0+unit,texcoordData.array.get(),0, extensions)); } } } } else { if (!_texCoordList.empty()) { const ArrayData& texcoordData = _texCoordList[0]; if (texcoordData.array.valid() && texcoordData.array->getNumElements()>0) { if (texcoordData.indices.valid()) { if (texcoordData.indices->getNumElements()>0) { drawTextCoord = new DrawTexCoord(texcoordData.array.get(),texcoordData.indices.get()); } } else { drawTextCoord = new DrawTexCoord(texcoordData.array.get(),0); } } } } if(handleVertexAttributes) { unsigned int index; for( index = 1; index < _vertexAttribList.size(); ++index ) { const ArrayData& vertAttribData = _vertexAttribList[index]; if( vertAttribData.array.valid() && vertAttribData.array->getNumElements() > 0 ) { if( vertAttribData.indices.valid() && vertAttribData.indices->getNumElements() > 0 ) { drawVertexAttribMap[vertAttribData.binding].push_back( new DrawVertexAttrib(extensions,index,vertAttribData.normalize,vertAttribData.array.get(),vertAttribData.indices.get() )); } else { drawVertexAttribMap[vertAttribData.binding].push_back( new DrawVertexAttrib(extensions,index,vertAttribData.normalize,vertAttribData.array.get(),0) ); } } } } // disable all the vertex arrays in the slow path as we are // sending everything using glVertex etc. state.disableAllVertexArrays(); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // pass the overall binding values onto OpenGL. // if (_normalData.binding==BIND_OVERALL) drawNormal(normalIndex++); if (_colorData.binding==BIND_OVERALL) drawColor(colorIndex++); if (secondaryColorBinding==BIND_OVERALL) drawSecondaryColor(secondaryColorIndex++); if (fogCoordBinding==BIND_OVERALL) drawFogCoord(fogCoordIndex++); if (handleVertexAttributes) { DrawVertexAttribList &list = drawVertexAttribMap[BIND_OVERALL]; for( unsigned int i = 0; i < list.size(); ++i ) { list[i]->applyAndIncrement(); } } // set up vertex functor. DrawVertex drawVertex(_vertexData.array.get(),_vertexData.indices.get()); bool useVertexAttrib = _vertexAttribList.size() > 0 && _vertexAttribList[0].array.valid() && _vertexAttribList[0].indices->getNumElements(); ref_ptr drawVertexAttribZero; if( useVertexAttrib ) { drawVertexAttribZero = new DrawVertexAttrib(extensions,0, _vertexAttribList[0].normalize,_vertexAttribList[0].array.get(), _vertexAttribList[0].indices.get()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // draw the primitives themselves. // for(PrimitiveSetList::const_iterator itr=_primitives.begin(); itr!=_primitives.end(); ++itr) { if (_normalData.binding==BIND_PER_PRIMITIVE_SET) drawNormal(normalIndex++); if (_colorData.binding==BIND_PER_PRIMITIVE_SET) drawColor(colorIndex++); if (secondaryColorBinding==BIND_PER_PRIMITIVE_SET) drawSecondaryColor(secondaryColorIndex++); if (fogCoordBinding==BIND_PER_PRIMITIVE_SET) drawFogCoord(fogCoordIndex++); if (handleVertexAttributes) { DrawVertexAttribList &list = drawVertexAttribMap[BIND_PER_PRIMITIVE_SET]; for( unsigned int i = 0; i < list.size(); ++i ) { list[i]->applyAndIncrement(); } } const PrimitiveSet* primitiveset = itr->get(); GLenum mode=primitiveset->getMode(); unsigned int primLength; switch(mode) { case(GL_POINTS): primLength=1; break; case(GL_LINES): primLength=2; break; case(GL_TRIANGLES): primLength=3; break; case(GL_QUADS): primLength=4; break; default: primLength=0; break; // compute later when =0. } // draw primtives by the more flexible "slow" path, // sending OpenGL glBegin/glVertex.../glEnd(). switch(primitiveset->getType()) { case(PrimitiveSet::DrawArraysPrimitiveType): { if (primLength==0) primLength=primitiveset->getNumIndices(); const DrawArrays* drawArray = static_cast(primitiveset); glBegin(mode); unsigned int primCount=0; unsigned int indexEnd = drawArray->getFirst()+drawArray->getCount(); for(unsigned int vindex=drawArray->getFirst(); vindexapplyAndIncrement(); } } } if (_normalData.binding==BIND_PER_VERTEX) drawNormal(vindex); if (_colorData.binding==BIND_PER_VERTEX) drawColor(vindex); if (secondaryColorBinding==BIND_PER_VERTEX) drawSecondaryColor(vindex); if (fogCoordBinding==BIND_PER_VERTEX) drawFogCoord(vindex); if (handleVertexAttributes) { DrawVertexAttribList &list = drawVertexAttribMap[BIND_PER_VERTEX]; for( unsigned int i = 0; i < list.size(); ++i ) { list[i]->applyAndIncrement(); } } for(DrawTexCoordList::iterator texItr=drawTexCoordList.begin(); texItr!=drawTexCoordList.end(); ++texItr) { (*(*texItr))(vindex); } if (drawTextCoord.valid()) (*drawTextCoord)(vindex); if( useVertexAttrib ) { (*drawVertexAttribZero)(vindex); } else { drawVertex(vindex); } } glEnd(); break; } case(PrimitiveSet::DrawArrayLengthsPrimitiveType): { const DrawArrayLengths* drawArrayLengths = static_cast(primitiveset); unsigned int vindex=drawArrayLengths->getFirst(); for(DrawArrayLengths::const_iterator primItr=drawArrayLengths->begin(); primItr!=drawArrayLengths->end(); ++primItr) { unsigned int localPrimLength; if (primLength==0) localPrimLength=*primItr; else localPrimLength=primLength; glBegin(mode); for(GLsizei primCount=0;primCount<*primItr;++primCount) { if ((primCount%localPrimLength)==0) { if (_normalData.binding==BIND_PER_PRIMITIVE) drawNormal(normalIndex++); if (_colorData.binding==BIND_PER_PRIMITIVE) drawColor(colorIndex++); if (secondaryColorBinding==BIND_PER_PRIMITIVE) drawSecondaryColor(secondaryColorIndex++); if (fogCoordBinding==BIND_PER_PRIMITIVE) drawFogCoord(fogCoordIndex++); if (handleVertexAttributes) { DrawVertexAttribList &list = drawVertexAttribMap[BIND_PER_PRIMITIVE]; for( unsigned int i = 0; i < list.size(); ++i ) { list[i]->applyAndIncrement(); } } } if (_normalData.binding==BIND_PER_VERTEX) drawNormal(vindex); if (_colorData.binding==BIND_PER_VERTEX) drawColor(vindex); if (secondaryColorBinding==BIND_PER_VERTEX) drawSecondaryColor(vindex); if (fogCoordBinding==BIND_PER_VERTEX) drawFogCoord(vindex); if (handleVertexAttributes) { DrawVertexAttribList &list = drawVertexAttribMap[BIND_PER_VERTEX]; for( unsigned int i = 0; i < list.size(); ++i ) { list[i]->applyAndIncrement(); } } for(DrawTexCoordList::iterator texItr=drawTexCoordList.begin(); texItr!=drawTexCoordList.end(); ++texItr) { (*(*texItr))(vindex); } if (drawTextCoord.valid()) (*drawTextCoord)(vindex); if( useVertexAttrib ) { (*drawVertexAttribZero)(vindex); } else { drawVertex(vindex); } ++vindex; } glEnd(); } break; } case(PrimitiveSet::DrawElementsUBytePrimitiveType): { if (primLength==0) primLength=primitiveset->getNumIndices(); const DrawElementsUByte* drawElements = static_cast(primitiveset); glBegin(mode); unsigned int primCount=0; for(DrawElementsUByte::const_iterator primItr=drawElements->begin(); primItr!=drawElements->end(); ++primCount,++primItr) { if ((primCount%primLength)==0) { if (_normalData.binding==BIND_PER_PRIMITIVE) drawNormal(normalIndex++); if (_colorData.binding==BIND_PER_PRIMITIVE) drawColor(colorIndex++); if (secondaryColorBinding==BIND_PER_PRIMITIVE) drawSecondaryColor(secondaryColorIndex++); if (fogCoordBinding==BIND_PER_PRIMITIVE) drawFogCoord(fogCoordIndex++); if (handleVertexAttributes) { DrawVertexAttribList &list = drawVertexAttribMap[BIND_PER_PRIMITIVE]; for( unsigned int i = 0; i < list.size(); ++i ) { list[i]->applyAndIncrement(); } } } unsigned int vindex=*primItr; if (_normalData.binding==BIND_PER_VERTEX) drawNormal(vindex); if (_colorData.binding==BIND_PER_VERTEX) drawColor(vindex); if (secondaryColorBinding==BIND_PER_VERTEX) drawSecondaryColor(vindex); if (fogCoordBinding==BIND_PER_VERTEX) drawFogCoord(vindex); if ( extensions->isVertexProgramSupported() ) { DrawVertexAttribList &list = drawVertexAttribMap[BIND_PER_VERTEX]; for( unsigned int i = 0; i < list.size(); ++i ) { list[i]->applyAndIncrement(); } } for(DrawTexCoordList::iterator texItr=drawTexCoordList.begin(); texItr!=drawTexCoordList.end(); ++texItr) { (*(*texItr))(vindex); } if (drawTextCoord.valid()) (*drawTextCoord)(vindex); if( useVertexAttrib ) { (*drawVertexAttribZero)(vindex); } else { drawVertex(vindex); } } glEnd(); break; } case(PrimitiveSet::DrawElementsUShortPrimitiveType): { if (primLength==0) primLength=primitiveset->getNumIndices(); const DrawElementsUShort* drawElements = static_cast(primitiveset); glBegin(mode); unsigned int primCount=0; for(DrawElementsUShort::const_iterator primItr=drawElements->begin(); primItr!=drawElements->end(); ++primCount,++primItr) { if ((primCount%primLength)==0) { if (_normalData.binding==BIND_PER_PRIMITIVE) drawNormal(normalIndex++); if (_colorData.binding==BIND_PER_PRIMITIVE) drawColor(colorIndex++); if (secondaryColorBinding==BIND_PER_PRIMITIVE) drawSecondaryColor(secondaryColorIndex++); if (fogCoordBinding==BIND_PER_PRIMITIVE) drawFogCoord(fogCoordIndex++); if (handleVertexAttributes) { DrawVertexAttribList &list = drawVertexAttribMap[BIND_PER_PRIMITIVE]; for( unsigned int i = 0; i < list.size(); ++i ) { list[i]->applyAndIncrement(); } } } unsigned int vindex=*primItr; if (_normalData.binding==BIND_PER_VERTEX) drawNormal(vindex); if (_colorData.binding==BIND_PER_VERTEX) drawColor(vindex); if (secondaryColorBinding==BIND_PER_VERTEX) drawSecondaryColor(vindex); if (fogCoordBinding==BIND_PER_VERTEX) drawFogCoord(vindex); if (handleVertexAttributes) { DrawVertexAttribList &list = drawVertexAttribMap[BIND_PER_VERTEX]; for( unsigned int i = 0; i < list.size(); ++i ) { list[i]->applyAndIncrement(); } } for(DrawTexCoordList::iterator texItr=drawTexCoordList.begin(); texItr!=drawTexCoordList.end(); ++texItr) { (*(*texItr))(vindex); } if (drawTextCoord.valid()) (*drawTextCoord)(vindex); if( useVertexAttrib ) { (*drawVertexAttribZero)(vindex); } else { drawVertex(vindex); } } glEnd(); break; } case(PrimitiveSet::DrawElementsUIntPrimitiveType): { if (primLength==0) primLength=primitiveset->getNumIndices(); const DrawElementsUInt* drawElements = static_cast(primitiveset); glBegin(mode); unsigned int primCount=0; for(DrawElementsUInt::const_iterator primItr=drawElements->begin(); primItr!=drawElements->end(); ++primCount,++primItr) { if ((primCount%primLength)==0) { if (_normalData.binding==BIND_PER_PRIMITIVE) drawNormal(normalIndex++); if (_colorData.binding==BIND_PER_PRIMITIVE) drawColor(colorIndex++); if (secondaryColorBinding==BIND_PER_PRIMITIVE) drawSecondaryColor(secondaryColorIndex++); if (fogCoordBinding==BIND_PER_PRIMITIVE) drawFogCoord(fogCoordIndex++); if ( extensions->isVertexProgramSupported() ) { DrawVertexAttribList &list = drawVertexAttribMap[BIND_PER_PRIMITIVE]; for( unsigned int i = 0; i < list.size(); ++i ) { list[i]->applyAndIncrement(); } } } unsigned int vindex=*primItr; if (_normalData.binding==BIND_PER_VERTEX) drawNormal(vindex); if (_colorData.binding==BIND_PER_VERTEX) drawColor(vindex); if (secondaryColorBinding==BIND_PER_VERTEX) drawSecondaryColor(vindex); if (fogCoordBinding==BIND_PER_VERTEX) drawFogCoord(vindex); if ( extensions->isVertexProgramSupported() ) { DrawVertexAttribList &list = drawVertexAttribMap[BIND_PER_VERTEX]; for( unsigned int i = 0; i < list.size(); ++i ) { list[i]->applyAndIncrement(); } } for(DrawTexCoordList::iterator texItr=drawTexCoordList.begin(); texItr!=drawTexCoordList.end(); ++texItr) { (*(*texItr))(vindex); } if (drawTextCoord.valid()) (*drawTextCoord)(vindex); if( useVertexAttrib ) { (*drawVertexAttribZero)(vindex); } else { drawVertex(vindex); } } glEnd(); break; } default: { break; } } } } } class AttrbuteFunctorArrayVisitor : public ArrayVisitor { public: AttrbuteFunctorArrayVisitor(Drawable::AttributeFunctor& af): _af(af) {} virtual ~AttrbuteFunctorArrayVisitor() {} virtual void apply(ByteArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(ShortArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(IntArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(UByteArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(UShortArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(UIntArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(UByte4Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(FloatArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(Vec2Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(Vec3Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(Vec4Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } inline void applyArray(Drawable::AttributeType type,Array* array) { if (array) { _type = type; array->accept(*this); } } Drawable::AttributeFunctor& _af; Drawable::AttributeType _type; }; void Geometry::accept(AttributeFunctor& af) { AttrbuteFunctorArrayVisitor afav(af); afav.applyArray(VERTICES,_vertexData.array.get()); afav.applyArray(NORMALS,_normalData.array.get()); afav.applyArray(COLORS,_colorData.array.get()); for(unsigned unit=0;unit<_texCoordList.size();++unit) { afav.applyArray((AttributeType)(TEXTURE_COORDS_0+unit),_texCoordList[unit].array.get()); } } class ConstAttrbuteFunctorArrayVisitor : public ConstArrayVisitor { public: ConstAttrbuteFunctorArrayVisitor(Drawable::ConstAttributeFunctor& af): _af(af) {} virtual ~ConstAttrbuteFunctorArrayVisitor() {} virtual void apply(const ByteArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(const ShortArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(const IntArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(const UByteArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(const UShortArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(const UIntArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(const UByte4Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(const FloatArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(const Vec2Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(const Vec3Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } virtual void apply(const Vec4Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } inline void applyArray(Drawable::AttributeType type,const Array* array) { if (array) { _type = type; array->accept(*this); } } Drawable::ConstAttributeFunctor& _af; Drawable::AttributeType _type; }; void Geometry::accept(ConstAttributeFunctor& af) const { ConstAttrbuteFunctorArrayVisitor afav(af); afav.applyArray(VERTICES,_vertexData.array.get()); afav.applyArray(NORMALS,_normalData.array.get()); afav.applyArray(COLORS,_colorData.array.get()); for(unsigned unit=0;unit<_texCoordList.size();++unit) { afav.applyArray((AttributeType)(TEXTURE_COORDS_0+unit),_texCoordList[unit].array.get()); } } void Geometry::accept(PrimitiveFunctor& functor) const { if (!_vertexData.array.valid() || _vertexData.array->getNumElements()==0) return; if (!_vertexData.indices.valid()) { switch(_vertexData.array->getType()) { case(Array::Vec2ArrayType): functor.setVertexArray(_vertexData.array->getNumElements(),static_cast(_vertexData.array->getDataPointer())); break; case(Array::Vec3ArrayType): functor.setVertexArray(_vertexData.array->getNumElements(),static_cast(_vertexData.array->getDataPointer())); break; case(Array::Vec4ArrayType): functor.setVertexArray(_vertexData.array->getNumElements(),static_cast(_vertexData.array->getDataPointer())); break; default: notify(WARN)<<"Warning: Geometry::accept(PrimtiveFunctor&) cannot handle Vertex Array type"<<_vertexData.array->getType()<accept(functor); } } else { const Vec2Array* vec2Array = 0; const Vec3Array* vec3Array = 0; const Vec4Array* vec4Array = 0; Array::Type type = _vertexData.array->getType(); switch(type) { case(Array::Vec2ArrayType): vec2Array = static_cast(_vertexData.array.get()); break; case(Array::Vec3ArrayType): vec3Array = static_cast(_vertexData.array.get()); break; case(Array::Vec4ArrayType): vec4Array = static_cast(_vertexData.array.get()); break; default: notify(WARN)<<"Warning: Geometry::accept(PrimtiveFunctor&) cannot handle Vertex Array type"<<_vertexData.array->getType()<get(); GLenum mode=primitiveset->getMode(); switch(primitiveset->getType()) { case(PrimitiveSet::DrawArraysPrimitiveType): { const DrawArrays* drawArray = static_cast(primitiveset); functor.begin(mode); unsigned int indexEnd = drawArray->getFirst()+drawArray->getCount(); for(unsigned int vindex=drawArray->getFirst(); vindexindex(vindex)]); break; case(Array::Vec3ArrayType): functor.vertex((*vec3Array)[_vertexData.indices->index(vindex)]); break; case(Array::Vec4ArrayType): functor.vertex((*vec4Array)[_vertexData.indices->index(vindex)]); break; default: break; } } functor.end(); break; } case(PrimitiveSet::DrawArrayLengthsPrimitiveType): { const DrawArrayLengths* drawArrayLengths = static_cast(primitiveset); unsigned int vindex=drawArrayLengths->getFirst(); for(DrawArrayLengths::const_iterator primItr=drawArrayLengths->begin(); primItr!=drawArrayLengths->end(); ++primItr) { functor.begin(mode); for(GLsizei primCount=0;primCount<*primItr;++primCount) { switch(type) { case(Array::Vec2ArrayType): functor.vertex((*vec2Array)[_vertexData.indices->index(vindex)]); break; case(Array::Vec3ArrayType): functor.vertex((*vec3Array)[_vertexData.indices->index(vindex)]); break; case(Array::Vec4ArrayType): functor.vertex((*vec4Array)[_vertexData.indices->index(vindex)]); break; default: break; } ++vindex; } functor.end(); } break; } case(PrimitiveSet::DrawElementsUBytePrimitiveType): { const DrawElementsUByte* drawElements = static_cast(primitiveset); functor.begin(mode); unsigned int primCount=0; for(DrawElementsUByte::const_iterator primItr=drawElements->begin(); primItr!=drawElements->end(); ++primCount,++primItr) { unsigned int vindex=*primItr; switch(type) { case(Array::Vec2ArrayType): functor.vertex((*vec2Array)[_vertexData.indices->index(vindex)]); break; case(Array::Vec3ArrayType): functor.vertex((*vec3Array)[_vertexData.indices->index(vindex)]); break; case(Array::Vec4ArrayType): functor.vertex((*vec4Array)[_vertexData.indices->index(vindex)]); break; default: break; } } functor.end(); break; } case(PrimitiveSet::DrawElementsUShortPrimitiveType): { const DrawElementsUShort* drawElements = static_cast(primitiveset); functor.begin(mode); for(DrawElementsUShort::const_iterator primItr=drawElements->begin(); primItr!=drawElements->end(); ++primItr) { unsigned int vindex=*primItr; switch(type) { case(Array::Vec2ArrayType): functor.vertex((*vec2Array)[_vertexData.indices->index(vindex)]); break; case(Array::Vec3ArrayType): functor.vertex((*vec3Array)[_vertexData.indices->index(vindex)]); break; case(Array::Vec4ArrayType): functor.vertex((*vec4Array)[_vertexData.indices->index(vindex)]); break; default: break; } } functor.end(); break; } case(PrimitiveSet::DrawElementsUIntPrimitiveType): { const DrawElementsUInt* drawElements = static_cast(primitiveset); functor.begin(mode); for(DrawElementsUInt::const_iterator primItr=drawElements->begin(); primItr!=drawElements->end(); ++primItr) { unsigned int vindex=*primItr; switch(type) { case(Array::Vec2ArrayType): functor.vertex((*vec2Array)[_vertexData.indices->index(vindex)]); break; case(Array::Vec3ArrayType): functor.vertex((*vec3Array)[_vertexData.indices->index(vindex)]); break; case(Array::Vec4ArrayType): functor.vertex((*vec4Array)[_vertexData.indices->index(vindex)]); break; default: break; } } functor.end(); break; } default: { break; } } } } return; } unsigned int _computeNumberOfPrimtives(const osg::Geometry& geom) { unsigned int totalNumberOfPrimitives = 0; for(Geometry::PrimitiveSetList::const_iterator itr=geom.getPrimitiveSetList().begin(); itr!=geom.getPrimitiveSetList().end(); ++itr) { const PrimitiveSet* primitiveset = itr->get(); GLenum mode=primitiveset->getMode(); unsigned int primLength; switch(mode) { case(GL_POINTS): primLength=1; break; case(GL_LINES): primLength=2; break; case(GL_TRIANGLES): primLength=3; break; case(GL_QUADS): primLength=4; break; default: primLength=0; break; // compute later when =0. } // draw primtives by the more flexible "slow" path, // sending OpenGL glBegin/glVertex.../glEnd(). switch(primitiveset->getType()) { case(PrimitiveSet::DrawArrayLengthsPrimitiveType): { const DrawArrayLengths* drawArrayLengths = static_cast(primitiveset); for(DrawArrayLengths::const_iterator primItr=drawArrayLengths->begin(); primItr!=drawArrayLengths->end(); ++primItr) { if (primLength==0) totalNumberOfPrimitives += 1; else totalNumberOfPrimitives = *primItr/primLength; } break; } default: { if (primLength==0) totalNumberOfPrimitives += 1; else totalNumberOfPrimitives = primitiveset->getNumIndices()/primLength; } } } return totalNumberOfPrimitives; } template bool _verifyBindings(const osg::Geometry& geom, const A& arrayData) { unsigned int numElements = arrayData.indices.valid()?arrayData.indices->getNumElements(): arrayData.array.valid()?arrayData.array->getNumElements():0; switch(arrayData.binding) { case(osg::Geometry::BIND_OFF): if (numElements>0) return false; break; case(osg::Geometry::BIND_OVERALL): if (numElements!=1) return false; break; case(osg::Geometry::BIND_PER_PRIMITIVE_SET): if (numElements!=geom.getPrimitiveSetList().size()) return false; break; case(osg::Geometry::BIND_PER_PRIMITIVE): if (numElements!=_computeNumberOfPrimtives(geom)) return false; break; case(osg::Geometry::BIND_PER_VERTEX): { unsigned int numVertices = geom.getVertexIndices()?geom.getVertexIndices()->getNumElements(): geom.getVertexArray()?geom.getVertexArray()->getNumElements():0; if (numElements!=numVertices) return false; break; } } return true; } template void _computeCorrectBindingsAndArraySizes(const osg::Geometry& geom, A& arrayData, const char* arrayName) { unsigned int numVertices = geom.getVertexIndices()?geom.getVertexIndices()->getNumElements(): geom.getVertexArray()?geom.getVertexArray()->getNumElements():0; if ( numVertices==0 ) { if (arrayData.binding!=osg::Geometry::BIND_OFF) { arrayData.array = 0; arrayData.indices = 0; arrayData.binding = osg::Geometry::BIND_OFF; notify(WARN)<<"Warning: in osg::Geometry::computeCorrectBindingsAndArraySizes() vertex array is empty but "<getNumElements(): arrayData.array.valid()?arrayData.array->getNumElements():0; switch(arrayData.binding) { case(osg::Geometry::BIND_OFF): if (numElements!=0) { arrayData.array = 0; arrayData.indices = 0; notify(WARN)<<"Warning: in osg::Geometry::computeCorrectBindingsAndArraySizes() "<1) { notify(WARN)<<"Warning: in osg::Geometry::computeCorrectBindingsAndArraySizes() "<geom.getPrimitiveSetList().size()) { notify(WARN)<<"Warning: in osg::Geometry::computeCorrectBindingsAndArraySizes() "<numPrimitives) { notify(WARN)<<"Warning: in osg::Geometry::computeCorrectBindingsAndArraySizes() "<numVertices) { notify(WARN)<<"Warning: in osg::Geometry::computeCorrectBindingsAndArraySizes() "< T* create(const T& array,const I& indices) { T* newArray = 0; // if source array type and target array type are equal if (_targetArray && _targetArray->getType()==array.getType()) { // reuse exisiting target array newArray = static_cast(_targetArray); if (newArray->size()!=indices.size()) { // make sure its the right size newArray->resize(indices.size()); } } else { // else create a new array. newArray = new T(indices.size()); } for(unsigned int i=0;i T* create(const T& array) { switch(_indices.getType()) { case(osg::Array::ByteArrayType): return create(array,static_cast(_indices)); case(osg::Array::ShortArrayType): return create(array,static_cast(_indices)); case(osg::Array::IntArrayType): return create(array,static_cast(_indices)); case(osg::Array::UByteArrayType): return create(array,static_cast(_indices)); case(osg::Array::UShortArrayType): return create(array,static_cast(_indices)); case(osg::Array::UIntArrayType): return create(array,static_cast(_indices)); default: return 0; } } virtual void apply(const osg::ByteArray& array) { _targetArray = create(array); } virtual void apply(const osg::ShortArray& array) { _targetArray = create(array); } virtual void apply(const osg::IntArray& array) { _targetArray = create(array); } virtual void apply(const osg::UByteArray& array) { _targetArray = create(array); } virtual void apply(const osg::UShortArray& array) { _targetArray = create(array); } virtual void apply(const osg::UIntArray& array) { _targetArray = create(array); } virtual void apply(const osg::UByte4Array& array) { _targetArray = create(array); } virtual void apply(const osg::FloatArray& array) { _targetArray = create(array); } virtual void apply(const osg::Vec2Array& array) { _targetArray = create(array); } virtual void apply(const osg::Vec3Array& array) { _targetArray = create(array); } virtual void apply(const osg::Vec4Array& array) { _targetArray = create(array); } const osg::IndexArray& _indices; osg::Array* _targetArray; }; bool Geometry::suitableForOptimization() const { bool hasIndices = false; if (getVertexIndices()) hasIndices = true; if (getNormalIndices()) hasIndices = true; if (getColorIndices()) hasIndices = true; if (getSecondaryColorIndices()) hasIndices = true; if (getFogCoordIndices()) hasIndices = true; for(unsigned int ti=0;tiaccept(eia); target.setVertexArray(eia._targetArray); target.setVertexIndices(0); } else if (getVertexArray()) { target.setVertexArray(getVertexArray()); } target.setNormalBinding(getNormalBinding()); if (getNormalIndices()) { ExpandIndexedArray eia(*(getNormalIndices()),target.getNormalArray()); getNormalArray()->accept(eia); target.setNormalArray(dynamic_cast(eia._targetArray)); target.setNormalIndices(0); } else if (getNormalArray()) { target.setNormalArray(getNormalArray()); } target.setColorBinding(getColorBinding()); if (getColorIndices()) { ExpandIndexedArray eia(*(getColorIndices()),target.getColorArray()); getColorArray()->accept(eia); target.setColorArray(eia._targetArray); target.setColorIndices(0); } else if (getColorArray()) { target.setColorArray(getColorArray()); } target.setSecondaryColorBinding(getSecondaryColorBinding()); if (getSecondaryColorIndices()) { ExpandIndexedArray eia(*(getSecondaryColorIndices()),target.getSecondaryColorArray()); getSecondaryColorArray()->accept(eia); target.setSecondaryColorArray(eia._targetArray); target.setSecondaryColorIndices(0); } else if (getSecondaryColorArray()) { target.setSecondaryColorArray(getSecondaryColorArray()); } target.setFogCoordBinding(getFogCoordBinding()); if (getFogCoordIndices()) { ExpandIndexedArray eia(*(getFogCoordIndices()),target.getFogCoordArray()); getFogCoordArray()->accept(eia); target.setFogCoordArray(eia._targetArray); target.setFogCoordIndices(0); } else if (getFogCoordArray()) { target.setFogCoordArray(getFogCoordArray()); } for(unsigned int ti=0;tiaccept(eia); target.setTexCoordArray(ti,eia._targetArray); target.setTexCoordIndices(ti,0); } else if (getTexCoordArray(ti)) { target.setTexCoordArray(ti,getTexCoordArray(ti)); } } for(unsigned int vi=0;vi<_vertexAttribList.size();++vi) { ArrayData& arrayData = _vertexAttribList[vi]; if (arrayData.indices.valid()) { ExpandIndexedArray eia(*arrayData.indices,target.getVertexAttribArray(vi)); arrayData.array->accept(eia); target.setVertexAttribData(vi,ArrayData(eia._targetArray, 0, arrayData.binding, arrayData.normalize)); } else if (arrayData.array.valid()) { target.setVertexAttribData(vi,arrayData); } } } void Geometry::computeInternalOptimizedGeometry() { if (suitableForOptimization()) { if (!_internalOptimizedGeometry) _internalOptimizedGeometry = new Geometry; copyToAndOptimize(*_internalOptimizedGeometry); } } Geometry* osg::createTexturedQuadGeometry(const osg::Vec3& corner,const osg::Vec3& widthVec,const osg::Vec3& heightVec) { Geometry* geom = new Geometry; Vec3Array* coords = new Vec3Array(4); (*coords)[0] = corner+heightVec; (*coords)[1] = corner; (*coords)[2] = corner+widthVec; (*coords)[3] = corner+widthVec+heightVec; geom->setVertexArray(coords); Vec2Array* tcoords = new Vec2Array(4); (*tcoords)[0].set(0.0f,1.0f); (*tcoords)[1].set(0.0f,0.0f); (*tcoords)[2].set(1.0f,0.0f); (*tcoords)[3].set(1.0f,1.0f); geom->setTexCoordArray(0,tcoords); osg::Vec4Array* colours = new osg::Vec4Array(1); (*colours)[0].set(1.0f,1.0f,1.0,1.0f); geom->setColorArray(colours); geom->setColorBinding(Geometry::BIND_OVERALL); osg::Vec3Array* normals = new osg::Vec3Array(1); (*normals)[0] = widthVec^heightVec; (*normals)[0].normalize(); geom->setNormalArray(normals); geom->setNormalBinding(Geometry::BIND_OVERALL); geom->addPrimitiveSet(new DrawArrays(PrimitiveSet::QUADS,0,4)); return geom; } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// // experimental templated rendering code, please ignore... // will move to osg::Geometry once complete. // Robert Osfield, August 2003. #if 0 struct DrawAttributeArrays { virtual bool valid() const = 0; virtual void set(osg::Geometry* geometry) = 0; virtual unsigned int draw(unsigned int index, unsigned int count) const = 0; }; struct V3 { V3():_array(0) {} bool valid() const { return _array!=0; } void set(osg::Geometry* geometry) { _array = 0; osg::Array* array = geometry->getVertexArray(); if (array && array->getType()==osg::Array::Vec3ArrayType) { osg::Vec3Array* vec3array = static_cast(array); if (!vec3array->empty()) _array = &(vec3array->front()); } } inline void draw(unsigned int index) const { glVertex3fv(_array[index].ptr()); } osg::Vec3* _array; }; struct V3USI { V3USI():_array(0),_indices(0) {} bool valid() const { return _array!=0 && _indices!=0; } void set(osg::Geometry* geometry) { _array = 0; osg::Array* array = geometry->getVertexArray(); if (array && array->getType()==osg::Array::Vec3ArrayType) { osg::Vec3Array* vec3array = static_cast(array); if (!vec3array->empty()) _array = &(vec3array->front()); } _indices = 0; osg::IndexArray* indices = geometry->getVertexIndices(); if (indices && indices->getType()==osg::Array::UShortArrayType) { osg::UShortArray* ushort3array = static_cast(array); if (!ushort3array->empty()) _indices = &(ushort3array->front()); } } inline void draw(unsigned int index) const { glVertex3fv(_array[_indices[index]].ptr()); } osg::Vec3* _array; unsigned short* _indices; }; ////////////////////////////// struct N3 { N3():_array(0) {} bool valid() const { return _array!=0; } void set(osg::Geometry* geometry) { _array = 0; osg::Array* array = geometry->getVertexArray(); if (array && array->getType()==osg::Array::Vec3ArrayType) { osg::Vec3Array* vec3array = static_cast(array); if (!vec3array->empty()) _array = &(vec3array->front()); } } inline void draw(unsigned int index) const { glNormal3fv(_array[index].ptr()); } osg::Vec3* _array; }; struct N3USI { N3USI():_array(0),_indices(0) {} bool valid() const { return _array!=0 && _indices!=0; } void set(osg::Geometry* geometry) { _array = 0; osg::Array* array = geometry->getVertexArray(); if (array && array->getType()==osg::Array::Vec3ArrayType) { osg::Vec3Array* vec3array = static_cast(array); if (!vec3array->empty()) _array = &(vec3array->front()); } _indices = 0; osg::IndexArray* indices = geometry->getVertexIndices(); if (indices && indices->getType()==osg::Array::UShortArrayType) { osg::UShortArray* ushortarray = static_cast(array); if (!ushortarray->empty()) _indices = &(ushortarray->front()); } } inline void draw(unsigned int index) const { glNormal3fv(_array[_indices[index]].ptr()); } osg::Vec3* _array; unsigned short* _indices; }; ////////////////////////////// struct C4 { C4():_array(0) {} bool valid() const { return _array!=0; } void set(osg::Geometry* geometry) { _array = 0; osg::Array* array = geometry->getColorArray(); if (array && array->getType()==osg::Array::Vec4ArrayType) { osg::Vec4Array* vec4array = static_cast(array); if (!vec4array->empty()) _array = &(vec4array->front()); } } inline void draw(unsigned int index) const { glVertex3fv(_array[index].ptr()); } osg::Vec4* _array; }; struct C4USI { C4USI():_array(0),_indices(0) {} bool valid() const { return _array!=0 && _indices!=0; } void set(osg::Geometry* geometry) { _array = 0; osg::Array* array = geometry->getColorArray(); if (array && array->getType()==osg::Array::Vec4ArrayType) { osg::Vec4Array* vec4array = static_cast(array); if (!vec4array->empty()) _array = &(vec4array->front()); } _indices = 0; osg::IndexArray* indices = geometry->getColorIndices(); if (indices && indices->getType()==osg::Array::UShortArrayType) { osg::UShortArray* ushortarray = static_cast(array); if (!ushortarray->empty()) _indices = &(ushortarray->front()); } } inline void draw(unsigned int index) const { glColor4fv(_array[_indices[index]].ptr()); } osg::Vec4* _array; unsigned short* _indices; }; ////////////////////////////// struct T2 { T2():_array(0) {} bool valid() const { return _array!=0; } void set(osg::Geometry* geometry) { _array = 0; osg::Array* array = geometry->getTexCoordArray(0); if (array && array->getType()==osg::Array::Vec2ArrayType) { osg::Vec2Array* vec2array = static_cast(array); if (!vec2array->empty()) _array = &(vec2array->front()); } } inline void draw(unsigned int index) const { glTexCoord2fv(_array[index].ptr()); } osg::Vec2* _array; }; struct T2USI { T2USI():_array(0),_indices(0) {} bool valid() const { return _array!=0 && _indices!=0; } void set(osg::Geometry* geometry) { _array = 0; osg::Array* array = geometry->getTexCoordArray(0); if (array && array->getType()==osg::Array::Vec2ArrayType) { osg::Vec2Array* vec2array = static_cast(array); if (!vec2array->empty()) _array = &(vec2array->front()); } _indices = 0; osg::IndexArray* indices = geometry->getTexCoordIndices(0); if (indices && indices->getType()==osg::Array::UShortArrayType) { osg::UShortArray* ushortarray = static_cast(array); if (!ushortarray->empty()) _indices = &(ushortarray->front()); } } inline void draw(unsigned int index) const { glTexCoord2fv(_array[_indices[index]].ptr()); } osg::Vec2* _array; unsigned short* _indices; }; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template < class T1 > struct DrawAttributeArrays_T : public DrawAttributeArrays { DrawAttributeArrays_T(osg::Geometry* geometry) { } virtual bool valid() const { return _t1.valid(); } virtual void set(osg::Geometry* geometry) { _t1.set(geometry); } virtual unsigned int draw(unsigned int index, unsigned int count) const { for(unsigned int i=0;i struct DrawAttributeArrays_TT : public DrawAttributeArrays { DrawAttributeArrays_TT() { } virtual bool valid() const { return _t1.valid() && _t2.valid(); } virtual void set(osg::Geometry* geometry) { _t1.set(geometry); _t2.set(geometry); } virtual unsigned int draw(unsigned int index, unsigned int count) const { for(unsigned int i=0;i struct DrawAttributeArrays_TTT : public DrawAttributeArrays { DrawAttributeArrays_TTT() { } virtual bool valid() const { return _t1.valid() && _t2.valid() && _t3.valid(); } virtual void set(osg::Geometry* geometry) { _t1.set(geometry); _t2.set(geometry); _t3.set(geometry); } virtual unsigned int draw(unsigned int index, unsigned int count) const { for(unsigned int i=0;i struct DrawAttributeArrays_TTTT : public DrawAttributeArrays { DrawAttributeArrays_TTTT() { } virtual bool valid() const { return _t1.valid() && _t2.valid() && _t3.valid() && _t4.valid(); } virtual void set(osg::Geometry* geometry) { _t1.set(geometry); _t2.set(geometry); _t3.set(geometry); _t4.set(geometry); } virtual unsigned int draw(unsigned int index, unsigned int count) const { for(unsigned int i=0;i struct DrawAttributeArrays_TT_USI : public DrawAttributeArrays { DrawAttributeArrays_TT_USI() { } virtual bool valid() const { return _t1.valid() && _t2.valid() && _indices!=0; } virtual void set(osg::Geometry* geometry) { _t1.set(geometry); _t2.set(geometry); _indices = 0; osg::IndexArray* indices = geometry->getVertexIndices(); if (indices && indices->getType()==osg::Array::UShortArrayType) { osg::UShortArray* ushort3array = static_cast(array); if (!ushort3array->empty()) _indices = &(ushort3array->front()); } } virtual unsigned int draw(unsigned int index, unsigned int count) const { for(unsigned int i=0;i struct DrawAttributeArrays_TTT_USI : public DrawAttributeArrays { DrawAttributeArrays_TTT_USI() { } virtual bool valid() const { return _t1.valid() && _t2.valid() && _t3.valid() && _indices!=0; } virtual void set(osg::Geometry* geometry) { _t1.set(geometry); _t2.set(geometry); _t3.set(geometry); _indices = 0; osg::IndexArray* indices = geometry->getVertexIndices(); if (indices && indices->getType()==osg::Array::UShortArrayType) { osg::UShortArray* ushort3array = static_cast(array); if (!ushort3array->empty()) _indices = &(ushort3array->front()); } } virtual unsigned int draw(unsigned int index, unsigned int count) const { for(unsigned int i=0;i struct DrawAttributeArrays_TTTT_USI : public DrawAttributeArrays { DrawAttributeArrays_TTTT_USI() { } virtual bool valid() const { return _t1.valid() && _t2.valid() && _t3.valid() && _t4.valid() && _indices!=0; } virtual void set(osg::Geometry* geometry) { _t1.set(geometry); _t2.set(geometry); _t3.set(geometry); _t4.set(geometry); _indices = 0; osg::IndexArray* indices = geometry->getVertexIndices(); if (indices && indices->getType()==osg::Array::UShortArrayType) { osg::UShortArray* ushort3array = static_cast(array); if (!ushort3array->empty()) _indices = &(ushort3array->front()); } } virtual unsigned int draw(unsigned int index, unsigned int count) const { for(unsigned int i=0;i DrawAttributeArrays_V3; typedef DrawAttributeArrays_T DrawAttributeArrays_V3i; // Two attributes x 15 typedef DrawAttributeArrays_TT DrawAttributeArrays_N3V3; typedef DrawAttributeArrays_TT DrawAttributeArrays_N3iV3; typedef DrawAttributeArrays_TT DrawAttributeArrays_N3V3i; typedef DrawAttributeArrays_TT DrawAttributeArrays_N3iV3i; typedef DrawAttributeArrays_TT_USI DrawAttributeArrays_N3V3_i; typedef DrawAttributeArrays_TT DrawAttributeArrays_C4V3; typedef DrawAttributeArrays_TT DrawAttributeArrays_C4iV3; typedef DrawAttributeArrays_TT DrawAttributeArrays_C4V3i; typedef DrawAttributeArrays_TT DrawAttributeArrays_C4iV3i; typedef DrawAttributeArrays_TT_USI DrawAttributeArrays_C4V3_i; typedef DrawAttributeArrays_TT DrawAttributeArrays_T2V3; typedef DrawAttributeArrays_TT DrawAttributeArrays_T2iV3; typedef DrawAttributeArrays_TT DrawAttributeArrays_T2V3i; typedef DrawAttributeArrays_TT DrawAttributeArrays_T2iV3i; typedef DrawAttributeArrays_TT_USI DrawAttributeArrays_T2V3_i; // Three attributes x 27 typedef DrawAttributeArrays_TTT DrawAttributeArrays_C4N3V3; typedef DrawAttributeArrays_TTT DrawAttributeArrays_C4iN3V3; typedef DrawAttributeArrays_TTT DrawAttributeArrays_C4N3iV3; typedef DrawAttributeArrays_TTT DrawAttributeArrays_C4iN3iV3; typedef DrawAttributeArrays_TTT DrawAttributeArrays_C4N3V3i; typedef DrawAttributeArrays_TTT DrawAttributeArrays_C4iN3V3i; typedef DrawAttributeArrays_TTT DrawAttributeArrays_C4N3iV3i; typedef DrawAttributeArrays_TTT DrawAttributeArrays_C4iN3iV3i; typedef DrawAttributeArrays_TTT_USI DrawAttributeArrays_C4N3V3_i; typedef DrawAttributeArrays_TTT DrawAttributeArrays_T2N3V3; typedef DrawAttributeArrays_TTT DrawAttributeArrays_T2iN3V3; typedef DrawAttributeArrays_TTT DrawAttributeArrays_T2iN3iV3; typedef DrawAttributeArrays_TTT DrawAttributeArrays_T2N3iV3; typedef DrawAttributeArrays_TTT DrawAttributeArrays_T2N3V3i; typedef DrawAttributeArrays_TTT DrawAttributeArrays_T2iN3V3i; typedef DrawAttributeArrays_TTT DrawAttributeArrays_T2iN3iV3i; typedef DrawAttributeArrays_TTT DrawAttributeArrays_T2N3iV3i; typedef DrawAttributeArrays_TTT_USI DrawAttributeArrays_T2N3V3_i; typedef DrawAttributeArrays_TTT DrawAttributeArrays_T2C4V3; typedef DrawAttributeArrays_TTT DrawAttributeArrays_T2iC4V3; typedef DrawAttributeArrays_TTT DrawAttributeArrays_T2C4iV3; typedef DrawAttributeArrays_TTT DrawAttributeArrays_T2iC4iV3; typedef DrawAttributeArrays_TTT DrawAttributeArrays_T2C4V3i; typedef DrawAttributeArrays_TTT DrawAttributeArrays_T2iC4V3i; typedef DrawAttributeArrays_TTT DrawAttributeArrays_T2C4iV3i; typedef DrawAttributeArrays_TTT DrawAttributeArrays_T2iC4iV3i; typedef DrawAttributeArrays_TTT_USI DrawAttributeArrays_T2C4V3_t; // Four attributes x 17 typedef DrawAttributeArrays_TTTT DrawAttributeArrays_T2C4N3V3; typedef DrawAttributeArrays_TTTT DrawAttributeArrays_T2iC4N3V3; typedef DrawAttributeArrays_TTTT DrawAttributeArrays_T2C4iN3V3; typedef DrawAttributeArrays_TTTT DrawAttributeArrays_T2iC4iN3V3; typedef DrawAttributeArrays_TTTT DrawAttributeArrays_T2C4N3iV3; typedef DrawAttributeArrays_TTTT DrawAttributeArrays_T2iC4N3iV3; typedef DrawAttributeArrays_TTTT DrawAttributeArrays_T2C4iN3iV3; typedef DrawAttributeArrays_TTTT DrawAttributeArrays_T2iC4iN3iV3; typedef DrawAttributeArrays_TTTT DrawAttributeArrays_T2C4N3V3i; typedef DrawAttributeArrays_TTTT DrawAttributeArrays_T2iC4N3V3i; typedef DrawAttributeArrays_TTTT DrawAttributeArrays_T2C4iN3V3i; typedef DrawAttributeArrays_TTTT DrawAttributeArrays_T2iC4iN3V3i; typedef DrawAttributeArrays_TTTT DrawAttributeArrays_T2C4N3iV3i; typedef DrawAttributeArrays_TTTT DrawAttributeArrays_T2iC4N3iV3i; typedef DrawAttributeArrays_TTTT DrawAttributeArrays_T2C4iN3iV3i; typedef DrawAttributeArrays_TTTT DrawAttributeArrays_T2iC4iN3iV3i; typedef DrawAttributeArrays_TTTT_USI DrawAttributeArrays_T2C4N3V3_i; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #endif