Added osg::Geometry::verifyArray(std::ostream&) method to enable checks to be done on osg::Geometry to see if the arrays

are big enough to handle the primitives used in the geometry.

Added usage of verifyArray into osgfilecache so that it reports any problems on reading files in paged database.
This commit is contained in:
Robert Osfield 2011-01-03 19:41:06 +00:00
parent 25ef1a9e58
commit d644a6dfe3
3 changed files with 302 additions and 6 deletions

View File

@ -130,6 +130,40 @@ struct Extents
osg::Vec2d _max;
};
class CheckValidVisitor : public osg::NodeVisitor
{
public:
CheckValidVisitor():
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_numInvalidGeometries(0) {}
void apply(osg::Geode& geode)
{
unsigned int local_numInvalidGeometries = 0;
for(unsigned int i=0; i<geode.getNumDrawables(); ++i)
{
osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(geode.getDrawable(i));
if (geometry)
{
if (!geometry->verifyArrays(_errorReports)) ++local_numInvalidGeometries;
}
}
if (local_numInvalidGeometries)
{
_errorReports<<"Geode "<<geode.getName()<<" contains problem geometries"<<std::endl;
_numInvalidGeometries += local_numInvalidGeometries;
}
}
bool valid() const { return _numInvalidGeometries==0; }
unsigned int _numInvalidGeometries;
std::stringstream _errorReports;
};
class LoadDataVisitor : public osg::NodeVisitor
{
public:
@ -274,35 +308,47 @@ public:
osg::Node* readNodeFileAndWriteToCache(const std::string& filename)
{
osg::Node* node = 0;
if (_fileCache.valid() && osgDB::containsServerAddress(filename))
{
if (_fileCache->existsInCache(filename))
{
osg::notify(osg::NOTICE)<<"reading from FileCache: "<<filename<<std::endl;
return _fileCache->readNode(filename, osgDB::Registry::instance()->getOptions()).takeNode();
node = _fileCache->readNode(filename, osgDB::Registry::instance()->getOptions()).takeNode();
}
else
{
osg::notify(osg::NOTICE)<<"reading : "<<filename<<std::endl;
osg::Node* node = osgDB::readNodeFile(filename);
node = osgDB::readNodeFile(filename);
if (node)
{
osg::notify(osg::NOTICE)<<"write to FileCache : "<<filename<<std::endl;
_fileCache->writeNode(*node, filename, osgDB::Registry::instance()->getOptions());
}
return node;
}
}
else
{
osg::notify(osg::NOTICE)<<"reading : "<<filename<<std::endl;
return osgDB::readNodeFile(filename);
node = osgDB::readNodeFile(filename);
}
if (node)
{
CheckValidVisitor cvv;
node->accept(cvv);
if (!cvv.valid())
{
OSG_NOTICE<<"Warning, errors in geometry found in file "<<filename<<std::endl;
OSG_NOTICE<<cvv._errorReports.str()<<std::endl;
}
}
return node;
}
protected:
inline void pushMatrix(osg::Matrix& matrix) { _matrixStack.push_back(matrix); }

View File

@ -327,6 +327,7 @@ class OSG_EXPORT Geometry : public Drawable
/** Get whether fast paths should be used when supported. */
bool getFastPathHint() const { return _fastPathHint; }
/** Return true if OpenGL fast paths will be used with drawing this Geometry.
* Fast paths directly use vertex arrays, and glDrawArrays/glDrawElements so have low CPU overhead.
* With Slow paths the osg::Geometry::drawImplementation has to dynamically assemble OpenGL
@ -348,6 +349,8 @@ class OSG_EXPORT Geometry : public Drawable
void computeCorrectBindingsAndArraySizes();
/** check whether the arrays, indices, bindings and primitives all match correctly, return false is .*/
bool verifyArrays(std::ostream& out) const;
bool suitableForOptimization() const;

View File

@ -997,6 +997,14 @@ void Geometry::compileGLObjects(RenderInfo& renderInfo) const
void Geometry::drawImplementation(RenderInfo& renderInfo) const
{
#if 0
if (!validGeometry())
{
OSG_NOTICE<<"Error, osg::Geometry has invalid array/primitive set usage"<<std::endl;
return;
}
#endif
if (_internalOptimizedGeometry.valid())
{
_internalOptimizedGeometry->drawImplementation(renderInfo);
@ -2483,6 +2491,245 @@ void Geometry::computeInternalOptimizedGeometry()
}
}
class CheckArrayValidity
{
public:
CheckArrayValidity(const osg::Geometry* geometry)
{
numPrimitiveSets = geometry->getNumPrimitiveSets();
primitiveNum = 0;
maxVertexNumber = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// draw the primitives themselves.
//
for(unsigned int primitiveSetNum=0; primitiveSetNum != numPrimitiveSets; ++primitiveSetNum)
{
const PrimitiveSet* primitiveset = geometry->getPrimitiveSet(primitiveSetNum);
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 primitives 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);
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)
{
primitiveNum++;
}
}
if ((indexEnd-1) > maxVertexNumber) maxVertexNumber = (indexEnd-1);
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;
for(GLsizei primCount=0;
primCount<*primItr;
++vindex,++primCount)
{
if ((primCount%localPrimLength)==0)
{
primitiveNum++;
}
}
}
if ((vindex-1) > maxVertexNumber) maxVertexNumber = (vindex-1);
break;
}
case(PrimitiveSet::DrawElementsUBytePrimitiveType):
{
if (primLength==0) primLength=primitiveset->getNumIndices();
const DrawElementsUByte* drawElements = static_cast<const DrawElementsUByte*>(primitiveset);
unsigned int primCount=0;
for(DrawElementsUByte::const_iterator primItr=drawElements->begin();
primItr!=drawElements->end();
++primCount,++primItr)
{
if ((primCount%primLength)==0)
{
primitiveNum++;
}
unsigned int vindex = *primItr;
if (vindex > maxVertexNumber) maxVertexNumber = vindex;
}
break;
}
case(PrimitiveSet::DrawElementsUShortPrimitiveType):
{
if (primLength==0) primLength=primitiveset->getNumIndices();
const DrawElementsUShort* drawElements = static_cast<const DrawElementsUShort*>(primitiveset);
unsigned int primCount=0;
for(DrawElementsUShort::const_iterator primItr=drawElements->begin();
primItr!=drawElements->end();
++primCount,++primItr)
{
if ((primCount%primLength)==0)
{
primitiveNum++;
}
unsigned int vindex = *primItr;
if (vindex > maxVertexNumber) maxVertexNumber = vindex;
}
break;
}
case(PrimitiveSet::DrawElementsUIntPrimitiveType):
{
if (primLength==0) primLength=primitiveset->getNumIndices();
const DrawElementsUInt* drawElements = static_cast<const DrawElementsUInt*>(primitiveset);
unsigned int primCount=0;
for(DrawElementsUInt::const_iterator primItr=drawElements->begin();
primItr!=drawElements->end();
++primCount,++primItr)
{
if ((primCount%primLength)==0)
{
primitiveNum++;
}
unsigned int vindex = *primItr;
if (vindex > maxVertexNumber) maxVertexNumber = vindex;
}
break;
}
default:
{
break;
}
}
}
}
bool validArray(std::ostream& out, const osg::Geometry::ArrayData& arrayData, const char* arrayName)
{
unsigned int numRequired = 0;
switch(arrayData.binding)
{
case(osg::Geometry::BIND_OFF): numRequired = 0; break;
case(osg::Geometry::BIND_OVERALL): numRequired = 1; break;
case(osg::Geometry::BIND_PER_PRIMITIVE): numRequired = primitiveNum; break;
case(osg::Geometry::BIND_PER_PRIMITIVE_SET): numRequired = numPrimitiveSets; break;
case(osg::Geometry::BIND_PER_VERTEX): numRequired = maxVertexNumber+1; break;
}
if (arrayData.indices.valid())
{
unsigned int numIndices= arrayData.indices.valid() ? arrayData.indices->getNumElements() : 0;
if (numIndices<numRequired)
{
out<<"Not enough "<<arrayName<<" indices, numRequired="<<numRequired<<std::endl;
return false;
}
unsigned int numNormals = arrayData.array.valid() ? arrayData.array->getNumElements() : 0;
for(unsigned int i=0; i<numIndices; ++i)
{
if (arrayData.indices->index(i)>=numNormals)
{
out<<arrayName<<" index out of bounds of normal array"<<std::endl;
return false;
}
}
}
else
{
unsigned int numElements = arrayData.array.valid() ? arrayData.array->getNumElements() : 0;
if (numElements<numRequired)
{
out<<"Not enough "<<arrayName<<"s, numRequired="<<numRequired<<", but number in array="<<numElements<<std::endl;
return false;
}
}
return true;
}
unsigned int numPrimitiveSets;
unsigned int primitiveNum;
unsigned int maxVertexNumber;
};
bool Geometry::verifyArrays(std::ostream& out) const
{
CheckArrayValidity cav(this);
bool result = true;
// check _vertexData
if (_vertexData.indices.valid())
{
unsigned int numIndices= _vertexData.indices.valid() ? _vertexData.indices->getNumElements() : 0;
if (numIndices<=cav.maxVertexNumber)
{
out<<"Not enough vertex indices"<<std::endl;
result = false;
}
unsigned int numVertices = _vertexData.array.valid() ? _vertexData.array->getNumElements() : 0;
for(unsigned int i=0; i<numIndices; ++i)
{
if (_vertexData.indices->index(i)>=numVertices)
{
out<<"Vertex indice out of bounds of vertex array"<<std::endl;
result = false;
}
}
}
else
{
unsigned int numVertices = _vertexData.array.valid() ? _vertexData.array->getNumElements() : 0;
if (numVertices<cav.maxVertexNumber)
{
out<<"Not enough vertices"<<std::endl;
result = false;
}
}
// check _normalData
if (!cav.validArray(out, _normalData, "Normal")) result = false;
if (!cav.validArray(out, _colorData, "Color")) result = false;
if (!cav.validArray(out, _secondaryColorData, "SecondaryColor")) result = false;
return result;
}
Geometry* osg::createTexturedQuadGeometry(const Vec3& corner,const Vec3& widthVec,const Vec3& heightVec, float l, float b, float r, float t)
{