OpenSceneGraph/src/osg/Geometry.cpp

2518 lines
94 KiB
C++
Raw Normal View History

/* -*-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 <osg/Geometry>
#include <osg/Notify>
using namespace osg;
2003-08-09 08:46:48 +08:00
#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;
2003-08-09 08:46:48 +08:00
}
inline unsigned int index(unsigned int pos)
{
switch(_indicesType)
{
case(Array::ByteArrayType): return (*static_cast<const ByteArray*>(_indices))[pos];
case(Array::ShortArrayType): return (*static_cast<const ShortArray*>(_indices))[pos];
case(Array::IntArrayType): return (*static_cast<const IntArray*>(_indices))[pos];
case(Array::UByteArrayType): return (*static_cast<const UByteArray*>(_indices))[pos];
case(Array::UShortArrayType): return (*static_cast<const UShortArray*>(_indices))[pos];
case(Array::UIntArrayType): return (*static_cast<const UIntArray*>(_indices))[pos];
default: return 0;
}
}
2003-08-09 08:46:48 +08:00
inline void operator () (unsigned int pos)
{
if (_indices) pos = index(pos);
2003-08-09 08:46:48 +08:00
switch(_verticesType)
{
case(Array::Vec3ArrayType):
apply((*(static_cast<const Vec3Array*>(_vertices)))[pos]);
break;
case(Array::Vec2ArrayType):
apply((*(static_cast<const Vec2Array*>(_vertices)))[pos]);
break;
case(Array::Vec4ArrayType):
apply((*(static_cast<const Vec4Array*>(_vertices)))[pos]);
break;
default:
break;
2003-08-09 08:46:48 +08:00
}
}
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;
2003-08-09 08:46:48 +08:00
};
#else
2003-06-24 23:40:09 +08:00
class DrawVertex : public osg::ConstValueVisitor
{
public:
2003-06-24 23:40:09 +08:00
DrawVertex(const Array* vertices,const IndexArray* indices):
_vertices(vertices),
_indices(indices) {}
2003-08-09 08:46:48 +08:00
inline void operator () (unsigned int pos)
{
2003-06-24 23:40:09 +08:00
if (_indices) _vertices->accept(_indices->index(pos),*this);
else _vertices->accept(pos,*this);
}
2003-06-24 23:40:09 +08:00
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;
};
2003-08-09 08:46:48 +08:00
#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;
};
2003-08-09 08:46:48 +08:00
#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;
2003-08-09 08:46:48 +08:00
}
inline unsigned int index(unsigned int pos)
{
switch(_indicesType)
{
case(Array::ByteArrayType): return (*static_cast<const ByteArray*>(_indices))[pos];
case(Array::ShortArrayType): return (*static_cast<const ShortArray*>(_indices))[pos];
case(Array::IntArrayType): return (*static_cast<const IntArray*>(_indices))[pos];
case(Array::UByteArrayType): return (*static_cast<const UByteArray*>(_indices))[pos];
case(Array::UShortArrayType): return (*static_cast<const UShortArray*>(_indices))[pos];
case(Array::UIntArrayType): return (*static_cast<const UIntArray*>(_indices))[pos];
default: return 0;
}
}
inline void operator () (unsigned int pos)
{
if (_indices) pos = index(pos);
switch(_colorsType)
{
case(Array::Vec4ArrayType):
apply((*static_cast<const Vec4Array*>(_colors))[pos]);
break;
case(Array::UByte4ArrayType):
apply((*static_cast<const UByte4Array*>(_colors))[pos]);
break;
case(Array::Vec3ArrayType):
apply((*static_cast<const Vec3Array*>(_colors))[pos]);
break;
default:
break;
2003-08-09 08:46:48 +08:00
}
}
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) {}
2003-08-09 08:46:48 +08:00
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;
};
2003-08-09 08:46:48 +08:00
#endif
class DrawVertexAttrib : public osg::Referenced, public osg::ConstValueVisitor
{
public:
DrawVertexAttrib(const Drawable::Extensions * extensions,unsigned int index,GLboolean normalized,const Array* attribcoords,const IndexArray* indices):
_index(index),
_normalized(normalized),
_extensions(extensions),
_attribcoords(attribcoords),
_indices(indices) {;}
2003-08-09 08:46:48 +08:00
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( _index, s );
}
virtual void apply(const GLfloat& f)
{
_extensions->glVertexAttrib1f( _index, f );
}
virtual void apply(const UByte4& v)
{
if( _normalized )
{
_extensions->glVertexAttrib4Nubv( _index, v.ptr() );
}
else
{
_extensions->glVertexAttrib4ubv( _index, v.ptr() );
}
}
virtual void apply(const Vec2& v)
{
_extensions->glVertexAttrib2fv( _index, v.ptr() );
}
virtual void apply(const Vec3& v)
{
_extensions->glVertexAttrib3fv( _index, v.ptr() );
}
virtual void apply(const Vec4& v)
{
_extensions->glVertexAttrib4fv( _index, v.ptr() );
}
unsigned int _index;
GLboolean _normalized;
const Drawable::Extensions* _extensions;
const Array* _attribcoords;
const IndexArray* _indices;
};
class DrawTexCoord : public osg::Referenced, public osg::ConstValueVisitor
{
public:
DrawTexCoord(const Array* texcoords,const IndexArray* indices):
_texcoords(texcoords),
_indices(indices) {}
2003-08-09 08:46:48 +08:00
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) {}
2003-08-09 08:46:48 +08:00
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)
{}
2003-08-09 08:46:48 +08:00
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) {}
2003-08-09 08:46:48 +08:00
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::Geometry()
{
_normalBinding = BIND_OFF;
_colorBinding = BIND_OFF;
_secondaryColorBinding = BIND_OFF;
_fogCoordBinding = BIND_OFF;
_fastPath = false;
2003-08-09 08:46:48 +08:00
_fastPathHint = true;
}
Geometry::Geometry(const Geometry& geometry,const CopyOp& copyop):
Drawable(geometry,copyop),
#ifdef COMPILE_POSSIBLE_NEW_ARRAY_METHODS
_attributeList(geometry._attributeList),
#endif
_vertexArray((copyop(geometry._vertexArray.get()))),
_vertexIndices(dynamic_cast<IndexArray*>(copyop(geometry._vertexIndices.get()))),
_normalBinding(geometry._normalBinding),
_normalArray(dynamic_cast<Vec3Array*>(copyop(geometry._normalArray.get()))),
_normalIndices(dynamic_cast<IndexArray*>(copyop(geometry._normalIndices.get()))),
_colorBinding(geometry._colorBinding),
_colorArray(copyop(geometry._colorArray.get())),
_colorIndices(dynamic_cast<IndexArray*>(copyop(geometry._colorIndices.get()))),
_secondaryColorBinding(geometry._secondaryColorBinding),
_secondaryColorArray(copyop(geometry._secondaryColorArray.get())),
_secondaryColorIndices(dynamic_cast<IndexArray*>(copyop(geometry._secondaryColorIndices.get()))),
_fogCoordBinding(geometry._fogCoordBinding),
_fogCoordArray(dynamic_cast<FloatArray*>(copyop(geometry._fogCoordArray.get()))),
_fogCoordIndices(dynamic_cast<IndexArray*>(copyop(geometry._fogCoordIndices.get()))),
_fastPath(geometry._fastPath),
2003-08-09 08:46:48 +08:00
_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(TexCoordArrayList::const_iterator titr=geometry._texCoordList.begin();
titr!=geometry._texCoordList.end();
++titr)
{
_texCoordList.push_back(*titr);
}
for(VertexAttribArrayList::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::setTexCoordArray(unsigned int unit,Array* array)
{
if (_texCoordList.size()<=unit)
_texCoordList.resize(unit+1);
_texCoordList[unit].first = array;
dirtyDisplayList();
}
Array* Geometry::getTexCoordArray(unsigned int unit)
{
if (unit<_texCoordList.size()) return _texCoordList[unit].first.get();
else return 0;
}
const Array* Geometry::getTexCoordArray(unsigned int unit) const
{
if (unit<_texCoordList.size()) return _texCoordList[unit].first.get();
else return 0;
}
void Geometry::setTexCoordIndices(unsigned int unit,IndexArray* array)
{
if (_texCoordList.size()<=unit)
_texCoordList.resize(unit+1);
_texCoordList[unit].second = array;
dirtyDisplayList();
}
IndexArray* Geometry::getTexCoordIndices(unsigned int unit)
{
if (unit<_texCoordList.size()) return _texCoordList[unit].second.get();
else return 0;
}
const IndexArray* Geometry::getTexCoordIndices(unsigned int unit) const
{
if (unit<_texCoordList.size()) return _texCoordList[unit].second.get();
else return 0;
}
#ifdef COMPILE_POSSIBLE_NEW_ARRAY_METHODS
void Geometry::setArray(AttributeType type,Array* array)
{
if (_attributeList.size()<=type)
_attributeList.resize(type+1);
_attributeList[type]._array = array;
dirtyDisplayList();
}
Array* Geometry::getArray(AttributeType type)
{
if (type<_attributeList.size()) return _attributeList[type]._array.get();
else return 0;
}
const Array* Geometry::getArray(AttributeType type) const
{
if (type<_attributeList.size()) return _attributeList[type]._array.get();
else return 0;
}
void Geometry::setIndices(AttributeType type,IndexArray* array)
{
if (_attributeList.size()<=type)
_attributeList.resize(type+1);
_attributeList[type]._indices = array;
dirtyDisplayList();
}
IndexArray* Geometry::getIndices(AttributeType type)
{
if (type<_attributeList.size()) return _attributeList[type]._indices.get();
else return 0;
}
const IndexArray* Geometry::getIndices(AttributeType type) const
{
if (type<_attributeList.size()) return _attributeList[type]._indices.get();
else return 0;
}
void Geometry::setNormalize(AttributeType type,GLboolean normalize)
{
if (_attributeList.size()<=type)
_attributeList.resize(type+1);
_attributeList[type]._normalize = normalize;
dirtyDisplayList();
}
GLboolean Geometry::getNormalize(AttributeType type) const
{
if (type<_attributeList.size()) return _attributeList[type]._normalize;
else return GL_FALSE;
}
void Geometry::setBinding(AttributeType type,AttributeBinding binding)
{
if (_attributeList.size()<=type)
_attributeList.resize(type+1);
_attributeList[type]._binding = binding;
dirtyDisplayList();
}
Geometry::AttributeBinding Geometry::getBinding(AttributeType type) const
{
if (type<_attributeList.size()) return _attributeList[type]._binding;
else return BIND_OFF;
}
#endif
2003-08-21 22:26:40 +08:00
void Geometry::setVertexAttribArray(unsigned int index,GLboolean normalize,Array* array,AttributeBinding ab)
{
if (_vertexAttribList.size()<=index)
{
_vertexAttribList.resize(index+1);
_vertexAttribBindingList.resize(index+1);
}
_vertexAttribList[index].first = normalize;
_vertexAttribList[index].second.first = array;
if( index == 0 )
{
// Force bind per vertex
_vertexAttribBindingList[index] = BIND_PER_VERTEX;
}
else
{
_vertexAttribBindingList[index] = ab;
}
computeFastPathsUsed();
dirtyDisplayList();
}
Array *Geometry::getVertexAttribArray(unsigned int index)
{
if (index<_vertexAttribList.size()) return _vertexAttribList[index].second.first.get();
else return 0;
}
const Array *Geometry::getVertexAttribArray(unsigned int index) const
{
if (index<_vertexAttribList.size()) return _vertexAttribList[index].second.first.get();
else return 0;
}
bool Geometry::getVertexAttribBinding(unsigned int index, AttributeBinding& ab) const
{
// AttributeBinding value goes in ab
// return true if index is valid, false otherwise
if (index<_vertexAttribBindingList.size())
{
ab = _vertexAttribBindingList[index];
return true;
}
else
{
return false;
}
}
bool Geometry::getVertexAttribNormalize(unsigned int index, GLboolean &ret) const
{
// normalized value goes in ret
// return true if index is valid, false otherwise
if (index<_vertexAttribList.size())
{
ret = _vertexAttribList[index].first;
return true;
}
else
{
return false;
}
}
void Geometry::setVertexAttribIndices(unsigned int index,IndexArray* array)
{
if (_vertexAttribList.size()<=index)
_vertexAttribList.resize(index+1);
_vertexAttribList[index].second.second = array;
dirtyDisplayList();
}
IndexArray* Geometry::getVertexAttribIndices(unsigned int index)
{
if (index<_vertexAttribList.size()) return _vertexAttribList[index].second.second.get();
else return 0;
}
const IndexArray* Geometry::getVertexAttribIndices(unsigned int index) const
{
if (index<_vertexAttribList.size()) return _vertexAttribList[index].second.second.get();
else return 0;
}
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."<<std::endl;
return false;
}
bool Geometry::setPrimitiveSet(unsigned int i,PrimitiveSet* primitiveset)
{
if (i<_primitives.size() && primitiveset)
{
_primitives[i] = primitiveset;
dirtyDisplayList();
dirtyBound();
return true;
}
notify(WARN)<<"Warning: invalid index i or primitiveset passed to osg::Geometry::setPrimitiveSet(i,primitiveset), ignoring call."<<std::endl;
return false;
}
bool Geometry::insertPrimitiveSet(unsigned int i,PrimitiveSet* primitiveset)
{
if (primitiveset)
{
if (i<_primitives.size())
{
_primitives.insert(_primitives.begin()+i,primitiveset);
dirtyDisplayList();
dirtyBound();
return true;
}
else if (i==_primitives.size())
{
return addPrimitiveSet(primitiveset);
}
}
notify(WARN)<<"Warning: invalid index i or primitiveset passed to osg::Geometry::insertPrimitiveSet(i,primitiveset), ignoring call."<<std::endl;
return false;
}
bool Geometry::removePrimitiveSet(unsigned int i, unsigned int numElementsToRemove)
{
if (i<_primitives.size() && numElementsToRemove>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,"<<std::endl;
notify(WARN)<<" removing on from i to the end of the list of primitive sets."<<std::endl;
_primitives.erase(_primitives.begin()+i,_primitives.end());
}
dirtyDisplayList();
dirtyBound();
return true;
}
notify(WARN)<<"Warning: invalid index i passed to osg::Geometry::removePrimitiveSet(i,numElementsToRemove), ignoring call."<<std::endl;
return false;
}
unsigned int Geometry::getPrimitiveSetIndex(const PrimitiveSet* primitiveset) const
{
for (unsigned int primitiveSetIndex=0;primitiveSetIndex<_primitives.size();++primitiveSetIndex)
{
if (_primitives[primitiveSetIndex]==primitiveset) return primitiveSetIndex;
}
return _primitives.size(); // node not found.
}
bool Geometry::computeFastPathsUsed()
{
/*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// set up normals if required.
//
if (!_normalArray.valid() ||
_normalArray->empty() ||
(_normalIndices.valid() && _normalIndices->getNumElements()==0) )
{
// switch off if not supported or have a valid data.
_normalBinding = BIND_OFF;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// set up colours..
//
if (!_colorArray.valid() ||
_colorArray->getNumElements()==0 ||
(_colorIndices.valid() && _colorIndices->getNumElements()==0) )
{
// switch off if not supported or have a valid data.
_colorBinding = BIND_OFF;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Set up secondary color if required.
//
if (!_secondaryColorArray.valid() ||
_secondaryColorArray->getNumElements()==0 ||
(_secondaryColorIndices.valid() && _secondaryColorIndices->getNumElements()==0) )
{
// switch off if not supported or have a valid data.
_secondaryColorBinding = BIND_OFF;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Set up fog coord if required.
//
if (!_fogCoordArray.valid() ||
_fogCoordArray->getNumElements()==0 ||
(_fogCoordIndices.valid() && _fogCoordIndices->getNumElements()==0) )
{
// switch off if not supported or have a valid data.
_fogCoordBinding = BIND_OFF;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Set up vertex attrib if required.
//
for( unsigned int va = 0; va < _vertexAttribList.size(); ++va )
{
const Array * array = _vertexAttribList[va].second.first.get();
const IndexArray * idxArray = _vertexAttribList[va].second.second.get();
if (!array ||
array->getNumElements()==0 ||
(idxArray && idxArray->getNumElements()==0) )
{
// switch off if not supported or have a valid data.
_vertexAttribBindingList[va] = BIND_OFF;
}
}
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// check to see if fast path can be used.
//
_fastPath = true;
if (_vertexIndices.valid()) _fastPath = false;
else if (_normalBinding==BIND_PER_PRIMITIVE || (_normalBinding==BIND_PER_VERTEX && _normalIndices.valid())) _fastPath = false;
else if (_colorBinding==BIND_PER_PRIMITIVE || (_colorBinding==BIND_PER_VERTEX && _colorIndices.valid())) _fastPath = false;
else if (_secondaryColorBinding==BIND_PER_PRIMITIVE || (_secondaryColorBinding==BIND_PER_VERTEX && _secondaryColorIndices.valid())) _fastPath = false;
else if (_fogCoordBinding==BIND_PER_PRIMITIVE || (_fogCoordBinding==BIND_PER_VERTEX && _fogCoordIndices.valid())) _fastPath = false;
else
{
for( unsigned int va = 0; va < _vertexAttribBindingList.size(); ++va )
{
if (_vertexAttribBindingList[va]==BIND_PER_PRIMITIVE)
{
_fastPath = false;
break;
}
else
{
const Array * array = _vertexAttribList[va].second.first.get();
const IndexArray * idxArray = _vertexAttribList[va].second.second.get();
if( _vertexAttribBindingList[va]==BIND_PER_VERTEX &&
array && array->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 ArrayPair& texcoordPair = _texCoordList[unit];
if (texcoordPair.first.valid() && texcoordPair.first->getNumElements()>0)
{
if (texcoordPair.second.valid())
{
if (texcoordPair.second->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( !( ( _vertexArray.valid() && _vertexArray->getNumElements() != 0 ) ||
( _vertexAttribList.size() > 0 &&
_vertexAttribList[0].second.first.valid() &&
_vertexAttribList[0].second.first->getNumElements() != 0 ) ) )
{
return;
}
if( ( _vertexIndices.valid() && _vertexIndices->getNumElements() == 0 ) ||
( _vertexAttribList.size() > 0 &&
_vertexAttribList[0].second.second.valid() &&
_vertexAttribList[0].second.second->getNumElements() == 0 ) )
{
return;
}
DrawNormal drawNormal(_normalArray.get(),_normalIndices.get());
DrawColor drawColor(_colorArray.get(),_colorIndices.get());
DrawSecondaryColor drawSecondaryColor(_secondaryColorArray.get(),_secondaryColorIndices.get(),extensions);
DrawFogCoord drawFogCoord(_fogCoordArray.get(),_fogCoordIndices.get(),extensions);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Set up secondary color if required.
//
AttributeBinding secondaryColorBinding = _secondaryColorBinding;
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 = _fogCoordBinding;
if (fogCoordBinding!=BIND_OFF && !extensions->isFogCoordSupported())
{
// switch off if not supported or have a valid data.
fogCoordBinding = BIND_OFF;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Set up vertex attrib if required.
//
if(!extensions->isVertexProgramSupported())
{
for( unsigned int va = 0; va < _vertexAttribBindingList.size(); ++va )
{
if (_vertexAttribBindingList[va]!=BIND_OFF)
{
_vertexAttribBindingList[va] = BIND_OFF;
}
}
}
unsigned int normalIndex = 0;
unsigned int colorIndex = 0;
unsigned int secondaryColorIndex = 0;
unsigned int fogCoordIndex = 0;
unsigned int vertexAttribIndex = 0;
#if USE_DEFAULT_NORMAL
// if no values are defined for normal and color provide some defaults...
if (_normalBinding==BIND_OFF) glNormal3f(0.0f,0.0f,1.0f);
#endif
#if USE_DEFAULT_COLOUR
if (_colorBinding==BIND_OFF) glColor4f(1.0f,1.0f,1.0f,1.0f);
#endif
typedef std::vector< ref_ptr<DrawVertexAttrib> > DrawVertexAttribList;
typedef std::map< Geometry::AttributeBinding, DrawVertexAttribList> DrawVertexAttribMap;
DrawVertexAttribMap drawVertexAttribMap;
bool handleVertexAttributes = (!_vertexAttribList.empty() && extensions->isVertexProgramSupported());
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 "<<buffer<<std::endl;
extensions->glGenBuffers(1, &buffer);
extensions->glBindBuffer(GL_ARRAY_BUFFER_ARB,buffer);
//std::cout << " gen VertexBuffer "<<buffer<<std::endl;
// compute total size and offsets required.
unsigned int totalSize = 0;
_vertexOffset = 0;
if (_vertexArray.valid()) totalSize += _vertexArray->getTotalDataSize();
_normalOffset = totalSize;
if (_normalArray.valid()) totalSize += _normalArray->getTotalDataSize();
_colorOffset = totalSize;
if (_colorArray.valid()) totalSize += _colorArray->getTotalDataSize();
_secondaryColorOffset = totalSize;
if (_secondaryColorArray.valid()) totalSize += _secondaryColorArray->getTotalDataSize();
_fogCoordOffset = totalSize;
if (_fogCoordArray.valid()) totalSize += _fogCoordArray->getTotalDataSize();
unsigned int unit;
for(unit=0;unit<_texCoordList.size();++unit)
{
_texCoordList[unit].offset = totalSize;
const Array* array = _texCoordList[unit].first.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].second.first.get();
const AttributeBinding ab = _vertexAttribBindingList[index];
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 "<<buffer<<" size="<<totalSize<<std::endl;
//
// copy the data
//
if( _vertexArray.valid() )
extensions->glBufferSubData(GL_ARRAY_BUFFER_ARB, _vertexOffset, _vertexArray->getTotalDataSize(),_vertexArray->getDataPointer());
if (_normalBinding==BIND_PER_VERTEX)
extensions->glBufferSubData(GL_ARRAY_BUFFER_ARB, _normalOffset, _normalArray->getTotalDataSize(),_normalArray->getDataPointer());
if (_colorBinding==BIND_PER_VERTEX)
extensions->glBufferSubData(GL_ARRAY_BUFFER_ARB, _colorOffset, _colorArray->getTotalDataSize(),_colorArray->getDataPointer());
if (secondaryColorBinding==BIND_PER_VERTEX)
extensions->glBufferSubData(GL_ARRAY_BUFFER_ARB, _secondaryColorOffset, _secondaryColorArray->getTotalDataSize(),_secondaryColorArray->getDataPointer());
if (fogCoordBinding==BIND_PER_VERTEX)
extensions->glBufferSubData(GL_ARRAY_BUFFER_ARB, _fogCoordOffset, _fogCoordArray->getTotalDataSize(),_fogCoordArray->getDataPointer());
for(unit=0;unit<_texCoordList.size();++unit)
{
const Array* array = _texCoordList[unit].first.get();
if (array)
extensions->glBufferSubData(GL_ARRAY_BUFFER_ARB, _texCoordList[unit].offset, array->getTotalDataSize(), array->getDataPointer());
}
if( handleVertexAttributes )
{
unsigned int index;
for( index = 0; index < _vertexAttribList.size(); ++index )
{
const Array* array = _vertexAttribList[index].second.first.get();
const AttributeBinding ab = _vertexAttribBindingList[index];
if( ab == BIND_PER_VERTEX && array )
{
extensions->glBufferSubData(GL_ARRAY_BUFFER_ARB, _vertexAttribList[index].second.offset, array->getTotalDataSize(), array->getDataPointer());
}
}
}
}
//std::cout << "binding VertexBuffer "<<buffer<<std::endl;
extensions->glBindBuffer(GL_ARRAY_BUFFER_ARB,buffer);
if( _vertexArray.valid() )
state.setVertexPointer(_vertexArray->getDataSize(),_vertexArray->getDataType(),0,(const GLvoid*)_vertexOffset);
else
state.disableVertexPointer();
if (_normalBinding==BIND_PER_VERTEX)
state.setNormalPointer(GL_FLOAT,0,(const GLvoid*)_normalOffset);
else
state.disableNormalPointer();
if (_colorBinding==BIND_PER_VERTEX)
state.setColorPointer(_colorArray->getDataSize(),_colorArray->getDataType(),0,(const GLvoid*)_colorOffset);
else
state.disableColorPointer();
if (secondaryColorBinding==BIND_PER_VERTEX)
state.setSecondaryColorPointer(_secondaryColorArray->getDataSize(),_secondaryColorArray->getDataType(),0,(const GLvoid*)_secondaryColorOffset);
else
state.disableSecondaryColorPointer();
if (fogCoordBinding==BIND_PER_VERTEX)
state.setFogCoordPointer(GL_FLOAT,0,(const GLvoid*)_fogCoordOffset);
else
state.disableFogCoordPointer();
unsigned int unit;
for(unit=0;unit<_texCoordList.size();++unit)
{
const Array* array = _texCoordList[unit].first.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].second.first.get();
const AttributeBinding ab = _vertexAttribBindingList[index];
if( ab == BIND_PER_VERTEX && array )
{
state.setVertexAttribPointer( index, array->getDataSize(), array->getDataType(),
_vertexAttribList[index].first, 0, (const GLvoid*)_vertexAttribList[index].second.offset );
}
else
{
if( array )
{
const IndexArray* indexArray = _vertexAttribList[index].second.second.get();
if( indexArray && indexArray->getNumElements() > 0 )
{
drawVertexAttribMap[ab].push_back(
new DrawVertexAttrib(extensions,index,_vertexAttribList[index].first,array,indexArray) );
}
else
{
drawVertexAttribMap[ab].push_back(
new DrawVertexAttrib(extensions,index,_vertexAttribList[index].first,array,0) );
}
}
state.disableVertexAttribPointer( index );
}
}
state.disableVertexAttribPointersAboveAndIncluding( index );
}
}
else
{
//std::cout << "none VertexBuffer path"<<std::endl;
//
// None Vertex Buffer Object path for defining vertex arrays.
//
if( _vertexArray.valid() )
state.setVertexPointer(_vertexArray->getDataSize(),_vertexArray->getDataType(),0,_vertexArray->getDataPointer());
else
state.disableVertexPointer();
if (_normalBinding==BIND_PER_VERTEX)
state.setNormalPointer(GL_FLOAT,0,_normalArray->getDataPointer());
else
state.disableNormalPointer();
if (_colorBinding==BIND_PER_VERTEX)
state.setColorPointer(_colorArray->getDataSize(),_colorArray->getDataType(),0,_colorArray->getDataPointer());
else
state.disableColorPointer();
if (secondaryColorBinding==BIND_PER_VERTEX)
state.setSecondaryColorPointer(_secondaryColorArray->getDataSize(),_secondaryColorArray->getDataType(),0,_secondaryColorArray->getDataPointer());
else
state.disableSecondaryColorPointer();
if (fogCoordBinding==BIND_PER_VERTEX)
state.setFogCoordPointer(GL_FLOAT,0,_fogCoordArray->getDataPointer());
else
state.disableFogCoordPointer();
unsigned int unit;
for(unit=0;unit<_texCoordList.size();++unit)
{
const Array* array = _texCoordList[unit].first.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].second.first.get();
const AttributeBinding ab = _vertexAttribBindingList[index];
if( ab == BIND_PER_VERTEX && array )
{
state.setVertexAttribPointer( index, array->getDataSize(), array->getDataType(),
_vertexAttribList[index].first, 0, array->getDataPointer() );
}
else
{
if( array )
{
const IndexArray* indexArray = _vertexAttribList[index].second.second.get();
if( indexArray && indexArray->getNumElements() > 0 )
{
drawVertexAttribMap[ab].push_back(
new DrawVertexAttrib(extensions,index,_vertexAttribList[index].first,array,indexArray) );
}
else
{
drawVertexAttribMap[ab].push_back(
new DrawVertexAttrib(extensions,index,_vertexAttribList[index].first,array,0) );
}
}
state.disableVertexAttribPointer( index );
}
}
state.disableVertexAttribPointersAboveAndIncluding( index );
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// pass the overall binding values onto OpenGL.
//
if (_normalBinding==BIND_OVERALL) drawNormal(normalIndex++);
if (_colorBinding==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] ) )(vertexAttribIndex++);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// draw the primitives themselves.
//
for(PrimitiveSetList::const_iterator itr=_primitives.begin();
itr!=_primitives.end();
++itr)
{
if (_normalBinding==BIND_PER_PRIMITIVE_SET) drawNormal(normalIndex++);
if (_colorBinding==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] ) )(vertexAttribIndex++);
}
}
(*itr)->draw();
}
if (usingVertexBufferObjects)
{
extensions->glBindBuffer(GL_ARRAY_BUFFER_ARB,0);
}
}
else
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// slow path.
//
typedef std::vector< ref_ptr<DrawMultiTexCoord> > DrawTexCoordList;
DrawTexCoordList drawTexCoordList;
drawTexCoordList.reserve(_texCoordList.size());
// fallback if multitexturing not supported.
ref_ptr<DrawTexCoord> drawTextCoord;
if (extensions->isMultiTexSupported())
{
// multitexture supported..
for(unsigned int unit=0;unit!=_texCoordList.size();++unit)
{
const ArrayPair& texcoordPair = _texCoordList[unit];
if (texcoordPair.first.valid() && texcoordPair.first->getNumElements()>0)
{
if (texcoordPair.second.valid())
{
if (texcoordPair.second->getNumElements()>0)
{
drawTexCoordList.push_back(new DrawMultiTexCoord(GL_TEXTURE0+unit,texcoordPair.first.get(),texcoordPair.second.get(),
extensions));
}
}
else
{
drawTexCoordList.push_back(new DrawMultiTexCoord(GL_TEXTURE0+unit,texcoordPair.first.get(),0,
extensions));
}
}
}
}
else
{
if (!_texCoordList.empty())
{
const ArrayPair& texcoordPair = _texCoordList[0];
if (texcoordPair.first.valid() && texcoordPair.first->getNumElements()>0)
{
if (texcoordPair.second.valid())
{
if (texcoordPair.second->getNumElements()>0)
{
drawTextCoord = new DrawTexCoord(texcoordPair.first.get(),texcoordPair.second.get());
}
}
else
{
drawTextCoord = new DrawTexCoord(texcoordPair.first.get(),0);
}
}
}
}
if(handleVertexAttributes)
{
unsigned int index;
for( index = 1; index < _vertexAttribList.size(); ++index )
{
const Array* array = _vertexAttribList[index].second.first.get();
if( array && array->getNumElements() > 0 )
{
const IndexArray* indexArray = _vertexAttribList[index].second.second.get();
if( indexArray && indexArray->getNumElements() > 0 )
{
drawVertexAttribMap[_vertexAttribBindingList[index]].push_back(
new DrawVertexAttrib(extensions,index,_vertexAttribList[index].first,array,indexArray) );
}
else
{
drawVertexAttribMap[_vertexAttribBindingList[index]].push_back(
new DrawVertexAttrib(extensions,index,_vertexAttribList[index].first,array,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 (_normalBinding==BIND_OVERALL) drawNormal(normalIndex++);
if (_colorBinding==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] ) )(vertexAttribIndex++);
}
}
// set up vertex functor.
DrawVertex drawVertex(_vertexArray.get(),_vertexIndices.get());
bool useVertexAttrib = _vertexAttribList.size() > 0 &&
_vertexAttribList[0].second.first.valid() &&
_vertexAttribList[0].second.first->getNumElements();
ref_ptr<DrawVertexAttrib> drawVertexAttribZero;
if( useVertexAttrib )
{
drawVertexAttribZero = new DrawVertexAttrib(extensions,0,
_vertexAttribList[0].first,_vertexAttribList[0].second.first.get(),
_vertexAttribList[0].second.second.get());
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// draw the primitives themselves.
//
for(PrimitiveSetList::const_iterator itr=_primitives.begin();
itr!=_primitives.end();
++itr)
{
if (_normalBinding==BIND_PER_PRIMITIVE_SET) drawNormal(normalIndex++);
if (_colorBinding==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] ) )(vertexAttribIndex++);
}
}
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<const DrawArrays*>(primitiveset);
glBegin(mode);
unsigned int primCount=0;
unsigned int indexEnd = drawArray->getFirst()+drawArray->getCount();
for(unsigned int vindex=drawArray->getFirst();
vindex<indexEnd;
++vindex,++primCount)
{
if ((primCount%primLength)==0)
{
if (_normalBinding==BIND_PER_PRIMITIVE) drawNormal(normalIndex++);
if (_colorBinding==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] ) )(vertexAttribIndex++);
}
}
}
if (_normalBinding==BIND_PER_VERTEX) drawNormal(vindex);
if (_colorBinding==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] ) )(vertexAttribIndex++);
}
}
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<const DrawArrayLengths*>(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 (_normalBinding==BIND_PER_PRIMITIVE) drawNormal(normalIndex++);
if (_colorBinding==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] ) )(vertexAttribIndex++);
}
}
}
if (_normalBinding==BIND_PER_VERTEX) drawNormal(vindex);
if (_colorBinding==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] ) )(vertexAttribIndex++);
}
}
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<const DrawElementsUByte*>(primitiveset);
glBegin(mode);
unsigned int primCount=0;
for(DrawElementsUByte::const_iterator primItr=drawElements->begin();
primItr!=drawElements->end();
++primCount,++primItr)
{
if ((primCount%primLength)==0)
{
if (_normalBinding==BIND_PER_PRIMITIVE) drawNormal(normalIndex++);
if (_colorBinding==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] ) )(vertexAttribIndex++);
}
}
}
unsigned int vindex=*primItr;
if (_normalBinding==BIND_PER_VERTEX) drawNormal(vindex);
if (_colorBinding==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] ) )(vertexAttribIndex++);
}
}
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<const DrawElementsUShort*>(primitiveset);
glBegin(mode);
unsigned int primCount=0;
for(DrawElementsUShort::const_iterator primItr=drawElements->begin();
primItr!=drawElements->end();
++primCount,++primItr)
{
if ((primCount%primLength)==0)
{
if (_normalBinding==BIND_PER_PRIMITIVE) drawNormal(normalIndex++);
if (_colorBinding==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] ) )(vertexAttribIndex++);
}
}
}
unsigned int vindex=*primItr;
if (_normalBinding==BIND_PER_VERTEX) drawNormal(vindex);
if (_colorBinding==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] ) )(vertexAttribIndex++);
}
}
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<const DrawElementsUInt*>(primitiveset);
glBegin(mode);
unsigned int primCount=0;
for(DrawElementsUInt::const_iterator primItr=drawElements->begin();
primItr!=drawElements->end();
++primCount,++primItr)
{
if ((primCount%primLength)==0)
{
if (_normalBinding==BIND_PER_PRIMITIVE) drawNormal(normalIndex++);
if (_colorBinding==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] ) )(vertexAttribIndex++);
}
}
}
unsigned int vindex=*primItr;
if (_normalBinding==BIND_PER_VERTEX) drawNormal(vindex);
if (_colorBinding==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] ) )(vertexAttribIndex++);
}
}
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())); }
2002-11-22 17:46:25 +08:00
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);
2002-11-22 17:46:25 +08:00
afav.applyArray(VERTICES,_vertexArray.get());
afav.applyArray(NORMALS,_normalArray.get());
afav.applyArray(COLORS,_colorArray.get());
for(unsigned unit=0;unit<_texCoordList.size();++unit)
{
2002-11-22 17:46:25 +08:00
afav.applyArray((AttributeType)(TEXTURE_COORDS_0+unit),_texCoordList[unit].first.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())); }
2002-11-22 17:46:25 +08:00
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);
2002-11-22 17:46:25 +08:00
afav.applyArray(VERTICES,_vertexArray.get());
afav.applyArray(NORMALS,_normalArray.get());
afav.applyArray(COLORS,_colorArray.get());
for(unsigned unit=0;unit<_texCoordList.size();++unit)
{
2002-11-22 17:46:25 +08:00
afav.applyArray((AttributeType)(TEXTURE_COORDS_0+unit),_texCoordList[unit].first.get());
}
}
void Geometry::accept(PrimitiveFunctor& functor) const
{
2003-06-24 23:40:09 +08:00
if (!_vertexArray.valid() || _vertexArray->getNumElements()==0) return;
if (!_vertexIndices.valid())
{
2003-06-24 23:40:09 +08:00
switch(_vertexArray->getType())
{
case(Array::Vec2ArrayType):
functor.setVertexArray(_vertexArray->getNumElements(),static_cast<const Vec2*>(_vertexArray->getDataPointer()));
break;
case(Array::Vec3ArrayType):
functor.setVertexArray(_vertexArray->getNumElements(),static_cast<const Vec3*>(_vertexArray->getDataPointer()));
break;
case(Array::Vec4ArrayType):
functor.setVertexArray(_vertexArray->getNumElements(),static_cast<const Vec4*>(_vertexArray->getDataPointer()));
break;
default:
notify(WARN)<<"Warning: Geometry::accept(PrimtiveFunctor&) cannot handle Vertex Array type"<<_vertexArray->getType()<<std::endl;
return;
}
for(PrimitiveSetList::const_iterator itr=_primitives.begin();
itr!=_primitives.end();
++itr)
{
(*itr)->accept(functor);
}
}
else
{
2003-06-24 23:40:09 +08:00
const Vec2Array* vec2Array = 0;
const Vec3Array* vec3Array = 0;
const Vec4Array* vec4Array = 0;
Array::Type type = _vertexArray->getType();
switch(type)
{
case(Array::Vec2ArrayType):
vec2Array = static_cast<const Vec2Array*>(_vertexArray.get());
break;
case(Array::Vec3ArrayType):
vec3Array = static_cast<const Vec3Array*>(_vertexArray.get());
break;
case(Array::Vec4ArrayType):
vec4Array = static_cast<const Vec4Array*>(_vertexArray.get());
break;
default:
notify(WARN)<<"Warning: Geometry::accept(PrimtiveFunctor&) cannot handle Vertex Array type"<<_vertexArray->getType()<<std::endl;
return;
}
for(PrimitiveSetList::const_iterator itr=_primitives.begin();
itr!=_primitives.end();
++itr)
{
const PrimitiveSet* primitiveset = itr->get();
GLenum mode=primitiveset->getMode();
switch(primitiveset->getType())
{
case(PrimitiveSet::DrawArraysPrimitiveType):
{
const DrawArrays* drawArray = static_cast<const DrawArrays*>(primitiveset);
functor.begin(mode);
unsigned int indexEnd = drawArray->getFirst()+drawArray->getCount();
for(unsigned int vindex=drawArray->getFirst();
vindex<indexEnd;
++vindex)
{
2003-06-24 23:40:09 +08:00
switch(type)
{
case(Array::Vec2ArrayType):
functor.vertex((*vec2Array)[_vertexIndices->index(vindex)]);
break;
case(Array::Vec3ArrayType):
functor.vertex((*vec3Array)[_vertexIndices->index(vindex)]);
break;
case(Array::Vec4ArrayType):
functor.vertex((*vec4Array)[_vertexIndices->index(vindex)]);
break;
default:
break;
}
}
functor.end();
break;
}
case(PrimitiveSet::DrawArrayLengthsPrimitiveType):
{
const DrawArrayLengths* drawArrayLengths = static_cast<const DrawArrayLengths*>(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)
{
2003-06-24 23:40:09 +08:00
switch(type)
{
case(Array::Vec2ArrayType):
functor.vertex((*vec2Array)[_vertexIndices->index(vindex)]);
break;
case(Array::Vec3ArrayType):
functor.vertex((*vec3Array)[_vertexIndices->index(vindex)]);
break;
case(Array::Vec4ArrayType):
functor.vertex((*vec4Array)[_vertexIndices->index(vindex)]);
break;
default:
break;
}
++vindex;
}
functor.end();
}
break;
}
case(PrimitiveSet::DrawElementsUBytePrimitiveType):
{
const DrawElementsUByte* drawElements = static_cast<const DrawElementsUByte*>(primitiveset);
functor.begin(mode);
unsigned int primCount=0;
for(DrawElementsUByte::const_iterator primItr=drawElements->begin();
primItr!=drawElements->end();
++primCount,++primItr)
{
unsigned int vindex=*primItr;
2003-06-24 23:40:09 +08:00
switch(type)
{
case(Array::Vec2ArrayType):
functor.vertex((*vec2Array)[_vertexIndices->index(vindex)]);
break;
case(Array::Vec3ArrayType):
functor.vertex((*vec3Array)[_vertexIndices->index(vindex)]);
break;
case(Array::Vec4ArrayType):
functor.vertex((*vec4Array)[_vertexIndices->index(vindex)]);
break;
default:
break;
}
}
functor.end();
break;
}
case(PrimitiveSet::DrawElementsUShortPrimitiveType):
{
const DrawElementsUShort* drawElements = static_cast<const DrawElementsUShort*>(primitiveset);
functor.begin(mode);
for(DrawElementsUShort::const_iterator primItr=drawElements->begin();
primItr!=drawElements->end();
++primItr)
{
unsigned int vindex=*primItr;
2003-06-24 23:40:09 +08:00
switch(type)
{
case(Array::Vec2ArrayType):
functor.vertex((*vec2Array)[_vertexIndices->index(vindex)]);
break;
case(Array::Vec3ArrayType):
functor.vertex((*vec3Array)[_vertexIndices->index(vindex)]);
break;
case(Array::Vec4ArrayType):
functor.vertex((*vec4Array)[_vertexIndices->index(vindex)]);
break;
default:
break;
}
}
functor.end();
break;
}
case(PrimitiveSet::DrawElementsUIntPrimitiveType):
{
const DrawElementsUInt* drawElements = static_cast<const DrawElementsUInt*>(primitiveset);
functor.begin(mode);
for(DrawElementsUInt::const_iterator primItr=drawElements->begin();
primItr!=drawElements->end();
++primItr)
{
unsigned int vindex=*primItr;
2003-06-24 23:40:09 +08:00
switch(type)
{
case(Array::Vec2ArrayType):
functor.vertex((*vec2Array)[_vertexIndices->index(vindex)]);
break;
case(Array::Vec3ArrayType):
functor.vertex((*vec3Array)[_vertexIndices->index(vindex)]);
break;
case(Array::Vec4ArrayType):
functor.vertex((*vec4Array)[_vertexIndices->index(vindex)]);
break;
default:
break;
}
}
functor.end();
break;
}
default:
{
break;
}
}
}
}
return;
}
bool Geometry::verifyBindings() const
{
switch(_normalBinding)
{
case(BIND_OFF):
if (_normalArray.valid() && _normalArray->getNumElements()>0) return false;
break;
case(BIND_OVERALL):
if (!_normalArray.valid()) return false;
if (_normalArray->getNumElements()!=1) return false;
break;
case(BIND_PER_PRIMITIVE_SET):
if (!_normalArray.valid()) return false;
if (_normalArray->getNumElements()!=_primitives.size()) return false;
break;
case(BIND_PER_PRIMITIVE):
if (!_normalArray.valid()) return false;
break;
case(BIND_PER_VERTEX):
if (_vertexArray.valid())
{
if (!_normalArray.valid()) return false;
if (_normalArray->getNumElements()!=_vertexArray->getNumElements()) return false;
}
else if (_normalArray.valid() && _normalArray->getNumElements()==0) return false;
break;
}
switch(_colorBinding)
{
case(BIND_OFF):
if (_colorArray.valid() && _colorArray->getNumElements()>0) return false;
break;
case(BIND_OVERALL):
if (!_colorArray.valid()) return false;
if (_colorArray->getNumElements()!=1) return false;
break;
case(BIND_PER_PRIMITIVE_SET):
if (!_colorArray.valid()) return false;
if (_colorArray->getNumElements()!=_primitives.size()) return false;
break;
case(BIND_PER_PRIMITIVE):
if (!_colorArray.valid()) return false;
break;
case(BIND_PER_VERTEX):
if (_vertexArray.valid())
{
if (!_colorArray.valid()) return false;
if (_colorArray->getNumElements()!=_vertexArray->getNumElements()) return false;
}
else if (_colorArray.valid() && _colorArray->getNumElements()==0) return false;
break;
}
for(TexCoordArrayList::const_iterator itr=_texCoordList.begin();
itr!=_texCoordList.end();
++itr)
{
const Array* array = itr->first.get();
if (_vertexArray.valid())
{
if (array && array->getNumElements()!=_vertexArray->getNumElements()) return false;
}
else if (array && array->getNumElements()==0) return false;
}
return true;
}
void Geometry::computeCorrectBindingsAndArraySizes()
{
if (verifyBindings()) return;
2003-06-24 23:40:09 +08:00
if (!_vertexArray.valid() || _vertexArray->getNumElements()==0)
{
// no vertex array so switch everything off.
_vertexArray = 0;
_colorArray = 0;
_colorBinding = BIND_OFF;
_normalArray = 0;
_normalBinding = BIND_OFF;
_texCoordList.clear();
notify(INFO)<<"Info: remove redundent attribute arrays from empty osg::Geometry"<<std::endl;
return;
}
switch(_normalBinding)
{
case(BIND_OFF):
if (_normalArray.valid()) _normalArray = 0;
break;
case(BIND_OVERALL):
if (!_normalArray.valid())
{
_normalBinding = BIND_OFF;
}
else if (_normalArray->getNumElements()==0)
{
_normalArray = 0;
_normalBinding = BIND_OFF;
}
else if (_normalArray->getNumElements()>1)
{
// trim the array down to 1 element long.
_normalArray->erase(_normalArray->begin()+1,_normalArray->end());
}
break;
case(BIND_PER_PRIMITIVE_SET):
if (!_normalArray.valid())
{
_normalBinding = BIND_OFF;
}
else if (_normalArray->getNumElements()<_primitives.size())
{
_normalArray = 0;
_normalBinding = BIND_OFF;
}
else if (_normalArray->getNumElements()>_primitives.size())
{
// trim the array down to size of the number of primitives.
_normalArray->erase(_normalArray->begin()+_primitives.size(),_normalArray->end());
}
break;
case(BIND_PER_PRIMITIVE):
break;
case(BIND_PER_VERTEX):
if (!_normalArray.valid())
{
_normalBinding = BIND_OFF;
}
else if (_normalArray->getNumElements()<_vertexArray->getNumElements())
{
_normalArray = 0;
_normalBinding = BIND_OFF;
}
else if (_normalArray->getNumElements()>_vertexArray->getNumElements())
{
// trim the array down to size of the number of primitives.
_normalArray->erase(_normalArray->begin()+_vertexArray->getNumElements(),_normalArray->end());
}
break;
}
// TODO colours and tex coords.
}
class ExpandIndexedArray : public osg::ConstArrayVisitor
{
public:
ExpandIndexedArray(const osg::IndexArray& indices,Array* targetArray):
_indices(indices),
_targetArray(targetArray) {}
template <class T,class I>
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<T*>(_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<indices.size();++i)
{
(*newArray)[i]= array[indices[i]];
}
return newArray;
}
template <class T>
T* create(const T& array)
{
switch(_indices.getType())
{
case(osg::Array::ByteArrayType): return create(array,static_cast<const osg::ByteArray&>(_indices));
case(osg::Array::ShortArrayType): return create(array,static_cast<const osg::ShortArray&>(_indices));
case(osg::Array::IntArrayType): return create(array,static_cast<const osg::IntArray&>(_indices));
case(osg::Array::UByteArrayType): return create(array,static_cast<const osg::UByteArray&>(_indices));
case(osg::Array::UShortArrayType): return create(array,static_cast<const osg::UShortArray&>(_indices));
case(osg::Array::UIntArrayType): return create(array,static_cast<const osg::UIntArray&>(_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;ti<getNumTexCoordArrays();++ti)
{
if (getTexCoordIndices(ti)) hasIndices = true;
}
for(unsigned int vi=0;vi<getNumVertexAttribArrays();++vi)
{
if (getVertexAttribIndices(vi)) hasIndices = true;
}
return hasIndices;
}
void Geometry::copyToAndOptimize(Geometry& target)
{
// copy over primitive sets.
target.getPrimitiveSetList() = getPrimitiveSetList();
// copy over attribute arrays.
if (getVertexIndices())
{
ExpandIndexedArray eia(*(getVertexIndices()),target.getVertexArray());
getVertexArray()->accept(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<osg::Vec3Array*>(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;ti<getNumTexCoordArrays();++ti)
{
if (getTexCoordIndices(ti))
{
ExpandIndexedArray eia(*(getTexCoordIndices(ti)),target.getTexCoordArray(ti));
getTexCoordArray(ti)->accept(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<getNumVertexAttribArrays();++vi)
{
AttributeBinding vab;
getVertexAttribBinding(vi,vab);
if (getVertexAttribIndices(vi))
{
GLboolean normalize;
ExpandIndexedArray eia(*(getVertexAttribIndices(vi)),target.getVertexAttribArray(vi));
getVertexAttribArray(vi)->accept(eia);
getVertexAttribNormalize(vi,normalize);
target.setVertexAttribArray(vi,normalize,eia._targetArray,vab);
target.setVertexAttribIndices(vi,0);
}
else if (getVertexAttribArray(vi))
{
GLboolean normalize;
getVertexAttribNormalize(vi,normalize);
target.setVertexAttribArray(vi,normalize,getVertexAttribArray(vi),vab);
}
}
}
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;
}