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:
parent
25ef1a9e58
commit
d644a6dfe3
@ -130,6 +130,40 @@ struct Extents
|
|||||||
osg::Vec2d _max;
|
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
|
class LoadDataVisitor : public osg::NodeVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -274,35 +308,47 @@ public:
|
|||||||
|
|
||||||
osg::Node* readNodeFileAndWriteToCache(const std::string& filename)
|
osg::Node* readNodeFileAndWriteToCache(const std::string& filename)
|
||||||
{
|
{
|
||||||
|
osg::Node* node = 0;
|
||||||
if (_fileCache.valid() && osgDB::containsServerAddress(filename))
|
if (_fileCache.valid() && osgDB::containsServerAddress(filename))
|
||||||
{
|
{
|
||||||
if (_fileCache->existsInCache(filename))
|
if (_fileCache->existsInCache(filename))
|
||||||
{
|
{
|
||||||
osg::notify(osg::NOTICE)<<"reading from FileCache: "<<filename<<std::endl;
|
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
|
else
|
||||||
{
|
{
|
||||||
osg::notify(osg::NOTICE)<<"reading : "<<filename<<std::endl;
|
osg::notify(osg::NOTICE)<<"reading : "<<filename<<std::endl;
|
||||||
|
|
||||||
osg::Node* node = osgDB::readNodeFile(filename);
|
node = osgDB::readNodeFile(filename);
|
||||||
if (node)
|
if (node)
|
||||||
{
|
{
|
||||||
osg::notify(osg::NOTICE)<<"write to FileCache : "<<filename<<std::endl;
|
osg::notify(osg::NOTICE)<<"write to FileCache : "<<filename<<std::endl;
|
||||||
|
|
||||||
_fileCache->writeNode(*node, filename, osgDB::Registry::instance()->getOptions());
|
_fileCache->writeNode(*node, filename, osgDB::Registry::instance()->getOptions());
|
||||||
}
|
}
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
osg::notify(osg::NOTICE)<<"reading : "<<filename<<std::endl;
|
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:
|
protected:
|
||||||
|
|
||||||
inline void pushMatrix(osg::Matrix& matrix) { _matrixStack.push_back(matrix); }
|
inline void pushMatrix(osg::Matrix& matrix) { _matrixStack.push_back(matrix); }
|
||||||
|
@ -327,6 +327,7 @@ class OSG_EXPORT Geometry : public Drawable
|
|||||||
/** Get whether fast paths should be used when supported. */
|
/** Get whether fast paths should be used when supported. */
|
||||||
bool getFastPathHint() const { return _fastPathHint; }
|
bool getFastPathHint() const { return _fastPathHint; }
|
||||||
|
|
||||||
|
|
||||||
/** Return true if OpenGL fast paths will be used with drawing this Geometry.
|
/** 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.
|
* 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
|
* With Slow paths the osg::Geometry::drawImplementation has to dynamically assemble OpenGL
|
||||||
@ -348,6 +349,8 @@ class OSG_EXPORT Geometry : public Drawable
|
|||||||
|
|
||||||
void computeCorrectBindingsAndArraySizes();
|
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;
|
bool suitableForOptimization() const;
|
||||||
|
|
||||||
|
@ -997,6 +997,14 @@ void Geometry::compileGLObjects(RenderInfo& renderInfo) const
|
|||||||
|
|
||||||
void Geometry::drawImplementation(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())
|
if (_internalOptimizedGeometry.valid())
|
||||||
{
|
{
|
||||||
_internalOptimizedGeometry->drawImplementation(renderInfo);
|
_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)
|
Geometry* osg::createTexturedQuadGeometry(const Vec3& corner,const Vec3& widthVec,const Vec3& heightVec, float l, float b, float r, float t)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user