Files
OpenSceneGraph/src/osgPlugins/gles/glesUtil
2016-07-05 16:32:00 +02:00

396 lines
15 KiB
C++

/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */
#ifndef GLES_UTIL
#define GLES_UTIL
#include <cassert>
#include <map>
#include <vector>
#include <algorithm>
#include <osg/Array>
#include <osg/ref_ptr>
#include <osgUtil/MeshOptimizers>
#include <osg/TriangleIndexFunctor>
#include <osg/TriangleLinePointIndexFunctor>
#include <osgAnimation/MorphGeometry>
#include <osgAnimation/RigGeometry>
#include "StatLogger"
namespace glesUtil {
using namespace std;
using namespace osg;
typedef std::vector<unsigned int> IndexList;
// A helper class that gathers up all the attribute arrays of an
// osg::Geometry object that are BIND_PER_VERTEX and runs an
// ArrayVisitor on them.
struct GeometryArrayGatherer
{
typedef std::vector<osg::Array*> ArrayList;
GeometryArrayGatherer(osg::Geometry& geometry) {
add(geometry.getVertexArray());
add(geometry.getNormalArray());
add(geometry.getColorArray());
add(geometry.getSecondaryColorArray());
add(geometry.getFogCoordArray());
for(unsigned int i = 0 ; i < geometry.getNumTexCoordArrays() ; ++ i) {
add(geometry.getTexCoordArray(i));
}
for(unsigned int i = 0 ; i < geometry.getNumVertexAttribArrays() ; ++ i) {
add(geometry.getVertexAttribArray(i));
}
}
void add(osg::Array* array) {
if (array) {
_arrayList.push_back(array);
}
}
void accept(osg::ArrayVisitor& av) {
for(ArrayList::iterator itr = _arrayList.begin() ; itr != _arrayList.end(); ++ itr) {
(*itr)->accept(av);
}
}
ArrayList _arrayList;
};
// Compact the vertex attribute arrays. Also stolen from TriStripVisitor
class RemapArray : public osg::ArrayVisitor
{
public:
RemapArray(const IndexList& remapping) : _remapping(remapping)
{}
const IndexList& _remapping;
template<class T>
inline void remap(T& array) {
for(unsigned int i = 0 ; i < _remapping.size() ; ++ i) {
if(i != _remapping[i]) {
array[i] = array[_remapping[i]];
}
}
array.erase(array.begin() + _remapping.size(),
array.end());
}
virtual void apply(osg::Array&) {}
virtual void apply(osg::ByteArray& array) { remap(array); }
virtual void apply(osg::ShortArray& array) { remap(array); }
virtual void apply(osg::IntArray& array) { remap(array); }
virtual void apply(osg::UByteArray& array) { remap(array); }
virtual void apply(osg::UShortArray& array) { remap(array); }
virtual void apply(osg::UIntArray& array) { remap(array); }
virtual void apply(osg::FloatArray& array) { remap(array); }
virtual void apply(osg::DoubleArray& array) { remap(array); }
virtual void apply(osg::Vec2dArray& array) { remap(array); }
virtual void apply(osg::Vec3dArray& array) { remap(array); }
virtual void apply(osg::Vec4dArray& array) { remap(array); }
virtual void apply(osg::Vec2Array& array) { remap(array); }
virtual void apply(osg::Vec3Array& array) { remap(array); }
virtual void apply(osg::Vec4Array& array) { remap(array); }
virtual void apply(osg::Vec2iArray& array) { remap(array); }
virtual void apply(osg::Vec3iArray& array) { remap(array); }
virtual void apply(osg::Vec4iArray& array) { remap(array); }
virtual void apply(osg::Vec2uiArray& array) { remap(array); }
virtual void apply(osg::Vec3uiArray& array) { remap(array); }
virtual void apply(osg::Vec4uiArray& array) { remap(array); }
virtual void apply(osg::Vec2sArray& array) { remap(array); }
virtual void apply(osg::Vec3sArray& array) { remap(array); }
virtual void apply(osg::Vec4sArray& array) { remap(array); }
virtual void apply(osg::Vec2usArray& array) { remap(array); }
virtual void apply(osg::Vec3usArray& array) { remap(array); }
virtual void apply(osg::Vec4usArray& array) { remap(array); }
virtual void apply(osg::Vec2bArray& array) { remap(array); }
virtual void apply(osg::Vec3bArray& array) { remap(array); }
virtual void apply(osg::Vec4bArray& array) { remap(array); }
virtual void apply(osg::Vec4ubArray& array) { remap(array); }
virtual void apply(osg::Vec3ubArray& array) { remap(array); }
virtual void apply(osg::Vec2ubArray& array) { remap(array); }
virtual void apply(osg::MatrixfArray& array) { remap(array); }
protected:
RemapArray& operator= (const RemapArray&) { return *this; }
};
// Compare vertices in a mesh using all their attributes. The vertices
// are identified by their index. Extracted from TriStripVisitor.cpp
struct VertexAttribComparitor : public GeometryArrayGatherer
{
VertexAttribComparitor(osg::Geometry& geometry) : GeometryArrayGatherer(geometry)
{}
bool operator() (unsigned int lhs, unsigned int rhs) const {
for(ArrayList::const_iterator itr = _arrayList.begin(); itr != _arrayList.end(); ++ itr) {
int compare = (*itr)->compare(lhs, rhs);
if (compare == -1) { return true; }
if (compare == 1) { return false; }
}
return false;
}
int compare(unsigned int lhs, unsigned int rhs) {
for(ArrayList::iterator itr = _arrayList.begin(); itr != _arrayList.end(); ++ itr) {
int compare = (*itr)->compare(lhs, rhs);
if (compare == -1) { return -1; }
if (compare == 1) { return 1; }
}
return 0;
}
protected:
VertexAttribComparitor& operator= (const VertexAttribComparitor&) { return *this; }
};
// Move the values in an array to new positions, based on the
// remapping table. remapping[i] contains element i's new position, if
// any. Unlike RemapArray in TriStripVisitor, this code doesn't
// assume that elements only move downward in the array.
class Remapper : public osg::ArrayVisitor
{
public:
static const unsigned invalidIndex;
Remapper(const vector<unsigned>& remapping)
: _remapping(remapping), _newsize(0)
{
for (vector<unsigned>::const_iterator itr = _remapping.begin(),
end = _remapping.end();
itr != end;
++itr)
if (*itr != invalidIndex)
++_newsize;
}
const vector<unsigned>& _remapping;
size_t _newsize;
template<class T>
inline void remap(T& array)
{
ref_ptr<T> newarray = new T(_newsize);
T* newptr = newarray.get();
for (size_t i = 0; i < _remapping.size(); ++i) {
if (_remapping[i] != invalidIndex) {
(*newptr)[_remapping[i]] = array[i];
}
}
array.swap(*newptr);
}
virtual void apply(osg::Array&) {}
virtual void apply(osg::ByteArray& array) { remap(array); }
virtual void apply(osg::ShortArray& array) { remap(array); }
virtual void apply(osg::IntArray& array) { remap(array); }
virtual void apply(osg::UByteArray& array) { remap(array); }
virtual void apply(osg::UShortArray& array) { remap(array); }
virtual void apply(osg::UIntArray& array) { remap(array); }
virtual void apply(osg::FloatArray& array) { remap(array); }
virtual void apply(osg::DoubleArray& array) { remap(array); }
virtual void apply(osg::Vec2Array& array) { remap(array); }
virtual void apply(osg::Vec3Array& array) { remap(array); }
virtual void apply(osg::Vec4Array& array) { remap(array); }
virtual void apply(osg::Vec2bArray& array) { remap(array); }
virtual void apply(osg::Vec3bArray& array) { remap(array); }
virtual void apply(osg::Vec4bArray& array) { remap(array); }
virtual void apply(osg::Vec2sArray& array) { remap(array); }
virtual void apply(osg::Vec3sArray& array) { remap(array); }
virtual void apply(osg::Vec4sArray& array) { remap(array); }
virtual void apply(osg::Vec2iArray& array) { remap(array); }
virtual void apply(osg::Vec3iArray& array) { remap(array); }
virtual void apply(osg::Vec4iArray& array) { remap(array); }
virtual void apply(osg::Vec2dArray& array) { remap(array); }
virtual void apply(osg::Vec3dArray& array) { remap(array); }
virtual void apply(osg::Vec4dArray& array) { remap(array); }
virtual void apply(osg::Vec2ubArray& array) { remap(array); }
virtual void apply(osg::Vec3ubArray& array) { remap(array); }
virtual void apply(osg::Vec4ubArray& array) { remap(array); }
virtual void apply(osg::Vec2usArray& array) { remap(array); }
virtual void apply(osg::Vec3usArray& array) { remap(array); }
virtual void apply(osg::Vec4usArray& array) { remap(array); }
virtual void apply(osg::Vec2uiArray& array) { remap(array); }
virtual void apply(osg::Vec3uiArray& array) { remap(array); }
virtual void apply(osg::Vec4uiArray& array) { remap(array); }
virtual void apply(osg::MatrixfArray& array) { remap(array); }
virtual void apply(osg::MatrixdArray& array) { remap(array); }
};
// Record the order in which vertices in a Geometry are used.
struct VertexReorderOperator
{
unsigned seq;
std::vector<unsigned int> remap;
VertexReorderOperator() : seq(0)
{
}
void inline doVertex(unsigned v)
{
if (remap[v] == glesUtil::Remapper::invalidIndex) {
remap[v] = seq ++;
}
}
void operator()(unsigned p1, unsigned p2, unsigned p3)
{
doVertex(p1);
doVertex(p2);
doVertex(p3);
}
void operator()(unsigned p1, unsigned p2)
{
doVertex(p1);
doVertex(p2);
}
void operator()(unsigned p1)
{
doVertex(p1);
}
};
struct VertexReorder : public TriangleLinePointIndexFunctor<glesUtil::VertexReorderOperator>
{
VertexReorder(unsigned numVerts)
{
remap.resize(numVerts, glesUtil::Remapper::invalidIndex);
}
};
inline osg::DrawElementsUInt* reorderDrawElements(PrimitiveSet* primitive,
const vector<unsigned>& reorder)
{
osg::DrawElementsUInt* newElements = new osg::DrawElementsUInt(primitive->getMode());
for (unsigned int i = 0 ; i < primitive->getNumIndices() ; ++ i) {
newElements->addElement(static_cast<unsigned>(reorder[primitive->index(i)]));
}
newElements->setUserDataContainer(primitive->getUserDataContainer());
return newElements;
}
class VertexAccessOrderVisitor : osgUtil::VertexAccessOrderVisitor
{
struct OrderByPrimitiveMode
{
inline bool operator() (const osg::ref_ptr<osg::PrimitiveSet> prim1, const osg::ref_ptr<osg::PrimitiveSet> prim2)
{
if(prim1.get() && prim2.get()) {
return prim1->getMode() > prim2->getMode();
}
else if(prim1.get()) {
return true;
}
return false;
}
} order_by_primitive_mode;
public:
void remapTargetVertices(Remapper remapper, Geometry& geom)
{
if(osgAnimation::MorphGeometry *morphGeometry = dynamic_cast<osgAnimation::MorphGeometry*>(&geom)) {
osgAnimation::MorphGeometry::MorphTargetList targetList = morphGeometry->getMorphTargetList();
for (osgAnimation::MorphGeometry::MorphTargetList::iterator ti = targetList.begin(); ti != targetList.end(); ++ti) {
osgAnimation::MorphGeometry::MorphTarget *morphTarget = &(*ti);
osg::Geometry *target = morphTarget->getGeometry();
GeometryArrayGatherer gatherer(*target);
gatherer.accept(remapper);
}
}
}
void optimizeOrder(Geometry& geom)
{
StatLogger logger("glesUtil::VertexAccessOrderVisitor::optimizeOrder(" + geom.getName() + ")");
Array* vertArray = geom.getVertexArray();
if (!vertArray || !vertArray->getNumElements())
return;
Geometry::PrimitiveSetList& primSets = geom.getPrimitiveSetList();
// sort primitives: first triangles, then lines and finally points
std::sort(primSets.begin(), primSets.end(), order_by_primitive_mode);
glesUtil::VertexReorder vr(vertArray->getNumElements());
for (Geometry::PrimitiveSetList::iterator itr = primSets.begin(),
end = primSets.end();
itr != end;
++itr)
{
PrimitiveSet* ps = itr->get();
PrimitiveSet::Type type = ps->getType();
if (type != PrimitiveSet::DrawElementsUBytePrimitiveType
&& type != PrimitiveSet::DrawElementsUShortPrimitiveType
&& type != PrimitiveSet::DrawElementsUIntPrimitiveType)
return;
ps->accept(vr);
}
// search for UVs array shared only within the geometry
osgUtil::SharedArrayOptimizer deduplicator;
deduplicator.findDuplicatedUVs(geom);
// duplicate shared arrays as it isn't safe to rearrange vertices when arrays are shared.
if (geom.containsSharedArrays()) geom.duplicateSharedArrays();
GeometryArrayGatherer gatherer(geom);
Remapper remapper(vr.remap);
gatherer.accept(remapper);
//Remap morphGeometry target
remapTargetVertices(remapper, geom);
Geometry::PrimitiveSetList newPrimitives;
for (Geometry::PrimitiveSetList::iterator itr = primSets.begin(),
end = primSets.end();
itr != end;
++itr)
{
PrimitiveSet* ps = itr->get();
newPrimitives.push_back(reorderDrawElements(ps, vr.remap));
}
geom.setPrimitiveSetList(newPrimitives);
// deduplicate UVs array that were only shared within the geometry
deduplicator.deduplicateUVs(geom);
geom.dirtyDisplayList();
}
};
} // glesUtil namespace
#endif