142 lines
5.0 KiB
C++
142 lines
5.0 KiB
C++
/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab
|
|
*
|
|
* This application is open source and may be redistributed and/or modified
|
|
* freely and without restriction, both in commercial and non commercial
|
|
* applications, as long as this copyright notice is maintained.
|
|
*
|
|
* This application 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.
|
|
*
|
|
*/
|
|
|
|
#ifndef GEOMETRY_CLEANER
|
|
#define GEOMETRY_CLEANER
|
|
|
|
#include <osg/Geometry>
|
|
#include <osgAnimation/RigGeometry>
|
|
#include <osgAnimation/MorphGeometry>
|
|
|
|
#include "GeometryMapper"
|
|
#include "SubGeometry"
|
|
|
|
|
|
class GeometryCleaner : public GeometryMapper
|
|
{
|
|
public:
|
|
|
|
const GeometryList& process(osg::Geometry& geometry) {
|
|
_clean.clear();
|
|
|
|
if(dynamic_cast<osgAnimation::MorphGeometry*>(&geometry)) {
|
|
// a morph geometry may have a degenerated primitive in one target but not all targets
|
|
// let's leave them unmodified
|
|
_clean.push_back(&geometry);
|
|
}
|
|
else if(dynamic_cast<osgAnimation::RigGeometry*>(&geometry)) {
|
|
// skipping rigged geometry for now
|
|
_clean.push_back(&geometry);
|
|
}
|
|
else {
|
|
osg::Vec3Array* positions = dynamic_cast<osg::Vec3Array*>(geometry.getVertexArray());
|
|
if (positions)
|
|
{
|
|
SubGeometry cleaned(geometry,
|
|
clean(*positions, getTriangles(geometry), 3),
|
|
clean(*positions, getLines(geometry), 2),
|
|
clean(*positions, getWireframe(geometry), 2),
|
|
clean(*positions, getPoints(geometry), 1));
|
|
_clean.push_back(cleaned.geometry());
|
|
}
|
|
}
|
|
|
|
return _clean;
|
|
}
|
|
|
|
osg::DrawElements* getTriangles(osg::Geometry& geometry) {
|
|
for(unsigned int i = 0 ; i < geometry.getNumPrimitiveSets() ; ++ i) {
|
|
osg::DrawElements* primitive = geometry.getPrimitiveSet(i)->getDrawElements();
|
|
if(primitive && primitive->getMode() == osg::PrimitiveSet::TRIANGLES) {
|
|
return primitive;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
osg::DrawElements* getLines(osg::Geometry& geometry) {
|
|
for(unsigned int i = 0 ; i < geometry.getNumPrimitiveSets() ; ++ i) {
|
|
osg::DrawElements* primitive = geometry.getPrimitiveSet(i)->getDrawElements();
|
|
if(primitive && primitive->getMode() == osg::PrimitiveSet::LINES) {
|
|
bool wireframe(false);
|
|
if(!primitive->getUserValue("wireframe", wireframe) || !wireframe)
|
|
return primitive;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
osg::DrawElements* getWireframe(osg::Geometry& geometry) {
|
|
for(unsigned int i = 0 ; i < geometry.getNumPrimitiveSets() ; ++ i) {
|
|
osg::DrawElements* primitive = geometry.getPrimitiveSet(i)->getDrawElements();
|
|
if(primitive && primitive->getMode() == osg::PrimitiveSet::LINES) {
|
|
bool wireframe(false);
|
|
if(primitive->getUserValue("wireframe", wireframe) && wireframe)
|
|
return primitive;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
osg::DrawElements* getPoints(osg::Geometry& geometry) {
|
|
for(unsigned int i = 0 ; i < geometry.getNumPrimitiveSets() ; ++ i) {
|
|
osg::DrawElements* primitive = geometry.getPrimitiveSet(i)->getDrawElements();
|
|
if(primitive && primitive->getMode() == osg::PrimitiveSet::POINTS) {
|
|
return primitive;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
std::vector<unsigned int> clean(const osg::Vec3Array& positions, osg::DrawElements* elements, const unsigned int size) {
|
|
std::vector<unsigned int> indices;
|
|
|
|
if(!elements) return indices;
|
|
|
|
for(unsigned int i = 0 ; i < elements->getNumIndices() ; i += size) {
|
|
if(size == 3) {
|
|
unsigned int v1 = elements->index(i),
|
|
v2 = elements->index(i + 1),
|
|
v3 = elements->index(i + 2);
|
|
osg::Vec3 p1 = positions[v1],
|
|
p2 = positions[v2],
|
|
p3 = positions[v3];
|
|
|
|
osg::Vec3f cross = (p2 - p1) ^ (p3 - p1);
|
|
if(cross.length()) {
|
|
indices.push_back(v1);
|
|
indices.push_back(v2);
|
|
indices.push_back(v3);
|
|
}
|
|
}
|
|
else if (size == 2) {
|
|
unsigned int v1 = elements->index(i),
|
|
v2 = elements->index(i + 1);
|
|
if(!(positions[v1] == positions[v2])) {
|
|
indices.push_back(v1);
|
|
indices.push_back(v2);
|
|
}
|
|
}
|
|
else {
|
|
indices.push_back(elements->index(i));
|
|
}
|
|
}
|
|
|
|
return indices;
|
|
}
|
|
|
|
|
|
GeometryList _clean;
|
|
};
|
|
|
|
#endif
|