Merge pull request #189 from marchelbling/master

osgjs/gles updates
This commit is contained in:
OpenSceneGraph git repository
2017-01-24 09:15:26 +00:00
committed by GitHub
19 changed files with 752 additions and 307 deletions

View File

@@ -62,7 +62,7 @@ void ComputeAABBOnBoneVisitor::computeBoundingBoxOnBones() {
}
// Compare initial and actual boundingBox if (no change) => no box on bone
if(bb == osg::BoundingBox() || bb._min.x() == bb._max.x() || bb._min.y() == bb._max.y() || bb._min.z() == bb._max.z()) {
if(bb == osg::BoundingBox() || (bb._min.x() == bb._max.x() && bb._min.y() == bb._max.y() && bb._min.z() == bb._max.z())) {
continue;
}

View File

@@ -5,9 +5,9 @@ SET(TARGET_SRC
BindPerVertexVisitor.cpp
DetachPrimitiveVisitor.cpp
GeometryIndexSplitter.cpp
GeometrySplitterVisitor.cpp
SubGeometry.cpp
OpenGLESGeometryOptimizer.cpp
RemapGeometryVisitor.cpp
RigAnimationVisitor.cpp
RigAttributesVisitor.cpp
TriangleMeshSmoother.cpp
@@ -25,9 +25,11 @@ SET(TARGET_H
DrawArrayVisitor
EdgeIndexFunctor
GeometryArray
GeometryCleaner
GeometryIndexSplitter
GeometryInspector
GeometrySplitterVisitor
GeometryMapper
RemapGeometryVisitor
GeometryUniqueVisitor
glesUtil
IndexMeshVisitor

View File

@@ -0,0 +1,138 @@
/* -*-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());
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

View File

@@ -25,15 +25,81 @@
#include <osgAnimation/RigGeometry>
#include "glesUtil"
#include "GeometryMapper"
#include "GeometryArray"
#include "TriangleMeshGraph"
#include "SubGeometry"
#include "Line"
class GeometryIndexSplitter
class GeometryIndexSplitter : public GeometryMapper
{
protected:
class Cluster {
public:
Cluster(unsigned int maxAllowedIndex):
maxIndex(maxAllowedIndex)
{
}
bool full() const {
return subvertices.size() >= maxIndex;
}
bool fullOfTriangles() const {
// consider worse case i.e. no triangle vertex is already in the cluster
// so need room for 3 indices
return subvertices.size() + 3 >= maxIndex;
}
bool fullOfLines() const {
return subvertices.size() + 2 >= maxIndex;
}
bool contains(unsigned int v1, unsigned int v2) const {
return contains(v1) && contains(v2);
}
bool contains(unsigned int v1) const {
return subvertices.count(v1);
}
void addTriangle(unsigned int v1, unsigned int v2, unsigned v3) {
subtriangles.push_back(v1);
subtriangles.push_back(v2);
subtriangles.push_back(v3);
subvertices.insert(v1);
subvertices.insert(v2);
subvertices.insert(v3);
}
void addLine(unsigned int v1, unsigned int v2) {
sublines.push_back(v1);
sublines.push_back(v2);
subvertices.insert(v1);
subvertices.insert(v2);
}
void addPoint(unsigned int v1) {
subpoints.push_back(v1);
subvertices.insert(v1);
}
void addWire(unsigned int v1, unsigned int v2) {
subwireframe.push_back(v1);
subwireframe.push_back(v2);
}
public:
const unsigned int maxIndex;
IndexVector subtriangles, subwireframe, sublines, subpoints;
IndexSet subvertices;
};
class IndexCache : public IndexDeque {
public:
IndexCache(unsigned int size=64) : _size(size)
@@ -48,18 +114,29 @@ protected:
};
public:
typedef std::vector< osg::ref_ptr<osg::Geometry> > GeometryList;
GeometryIndexSplitter(unsigned int maxAllowedIndex):
_maxAllowedIndex(maxAllowedIndex)
{}
const GeometryList& process(osg::Geometry& geometry) {
_geometryList.clear();
split(geometry);
return _geometryList;
}
bool split(osg::Geometry&);
unsigned int findCandidate(const IndexVector&);
unsigned int findCandidate(const IndexVector&, const IndexVector&);
void setTriangleCluster(const TriangleMeshGraph&, unsigned int, unsigned int, IndexVector&, IndexSet&, unsigned int&);
void extract_primitives(const IndexSet&, const osg::DrawElements*, IndexVector&, unsigned int);
template<typename C>
typename C::value_type getNext(C& primitives, typename C::value_type default_value) {
if(primitives.empty()) {
return default_value;
}
typename C::value_type next = *primitives.begin();
primitives.erase(primitives.begin());
return next;
}
unsigned int findCandidate(IndexSet&, const IndexCache&, const TriangleMeshGraph&);
protected:
bool needToSplit(const osg::Geometry&) const;
@@ -68,7 +145,6 @@ protected:
template<typename T>
void setBufferBoundingBox(T*) const;
void setValidIndices(std::set<unsigned int>&, const osg::DrawElements*) const;
public:
const unsigned int _maxAllowedIndex;

View File

@@ -11,8 +11,8 @@ bool GeometryIndexSplitter::split(osg::Geometry& geometry) {
attachBufferBoundingBox(geometry);
osg::DrawElements *wire_primitive = 0,
*line_primitive = 0,
*point_primitive = 0;
*line_primitive = 0,
*point_primitive = 0;
for(unsigned int i = 0 ; i < geometry.getNumPrimitiveSets() ; ++ i) {
osg::DrawElements* primitive = (geometry.getPrimitiveSet(i) ? geometry.getPrimitiveSet(i)->getDrawElements() : 0);
if(primitive) {
@@ -31,29 +31,34 @@ bool GeometryIndexSplitter::split(osg::Geometry& geometry) {
}
}
TriangleMeshGraph graph(geometry, false);
// only wireframe can be processed directly as they simply "duplicate" triangle or edge data;
// lines/points may reference points not used for triangles so we keep a set of primitives
// that remain to process
LineSet source_lines;
IndexSet source_points;
IndexSet triangles;
LineSet lines, wires;
IndexSet points;
for(unsigned int i = 0 ; i < graph.getNumTriangles() ; ++ i) {
triangles.insert(i);
}
if(line_primitive) {
for(unsigned int i = 0 ; i < line_primitive->getNumIndices() ; i += 2) {
source_lines.insert(Line(line_primitive->index(i), line_primitive->index(i + 1)));
lines.insert(Line(line_primitive->index(i), line_primitive->index(i + 1)));
}
}
if(wire_primitive) {
for(unsigned int i = 0 ; i < wire_primitive->getNumIndices() ; i += 2) {
wires.insert(Line(wire_primitive->index(i), wire_primitive->index(i + 1)));
}
}
if(point_primitive) {
for(unsigned int i = 0 ; i < point_primitive->getNumIndices() ; ++ i) {
source_points.insert(point_primitive->index(i));
points.insert(point_primitive->index(i));
}
}
TriangleMeshGraph graph(geometry, false);
unsigned int remaining_triangles = graph.getNumTriangles(),
cluster = 0;
IndexVector clusters(remaining_triangles, 0);
IndexCache cache;
// assign a cluster id for each triangle
// 1. bootstrap cluster by selecting first remaining triangle
// 2. while cluster size is < max cluster size
@@ -64,95 +69,75 @@ bool GeometryIndexSplitter::split(osg::Geometry& geometry) {
// 3. insert wireframe edges corresponding to selected triangles
// 4. extract subgeometry
while(remaining_triangles || !source_lines.empty() || !source_points.empty()) {
IndexVector subtriangles, subwireframe, sublines, subpoints;
IndexSet cluster_vertices;
while(triangles.size() || lines.size() || points.size()) {
Cluster cluster(_maxAllowedIndex);
IndexCache cache;
unsigned int candidate = std::numeric_limits<unsigned int>::max();
++ cluster;
// let's consider that every insert needs the place for a full new primitive for simplicity
while(!cluster.fullOfTriangles() &&
(candidate = findCandidate(triangles, cache, graph)) != std::numeric_limits<unsigned int>::max()) {
cache.push_back(candidate);
Triangle t = graph.triangle(candidate);
cluster.addTriangle(t.v1(), t.v2(), t.v3());
}
if(remaining_triangles) {
// find first unmarked triangle (as remaining_triangles > 0 there *must* be at least one)
cache.push_back(findCandidate(clusters));
setTriangleCluster(graph, cache.back(), cluster, clusters, cluster_vertices, remaining_triangles);
while(!cluster.fullOfLines() && lines.size()) {
Line line = getNext(lines, Line(std::numeric_limits<unsigned int>::max(), std::numeric_limits<unsigned int>::max()));
cluster.addLine(line._a, line._b);
}
while(remaining_triangles && cluster_vertices.size() < _maxAllowedIndex) {
unsigned int candidate = std::numeric_limits<unsigned int>::max();
while(!cluster.full() && points.size()) {
unsigned int point = getNext(points, std::numeric_limits<unsigned int>::max());
cluster.addPoint(point);
}
for(IndexCache::const_reverse_iterator cached = cache.rbegin() ; cached != cache.rend() ; ++ cached) {
candidate = findCandidate(graph.triangleNeighbors(*cached), clusters);
if(candidate != std::numeric_limits<unsigned int>::max()) break;
// update lines/points: if all vertices referenced by a point/line primitive are
// already extracted, let's insert it in the subgeometry and update the set of
// primitives still remaining Lines may e.g. reference one vertex in cluster A and
// the other in cluster B hence need specific care
if(line_primitive) {
for(LineSet::iterator line = lines.begin() ; line != lines.end() ; ) {
if(cluster.contains(line->_a, line->_b)) {
cluster.addLine(line->_a, line->_b);
lines.erase(line ++);
}
if(candidate == std::numeric_limits<unsigned int>::max()) {
// do we have room for a triangle having all vertices not in the cluster?
if(!(cluster_vertices.size() + 2 < _maxAllowedIndex)) {
break;
}
candidate = findCandidate(clusters);
}
cache.push_back(candidate);
setTriangleCluster(graph, candidate, cluster, clusters, cluster_vertices, remaining_triangles);
}
// build list of cluster triangles
for(unsigned int triangle = 0 ; triangle < clusters.size() ; ++ triangle) {
if(clusters[triangle] == cluster) {
const Triangle& t = graph.triangle(triangle);
subtriangles.push_back(t.v1());
subtriangles.push_back(t.v2());
subtriangles.push_back(t.v3());
}
}
// update lines/points: if all vertices referenced by a point/line primitive are
// already extracted, let's insert it in the subgeometry and update the set of
// primitives still remaining Lines may e.g. reference one vertex in cluster A and
// the other in cluster B hence need specific care
if(line_primitive) {
extract_primitives(cluster_vertices, line_primitive, sublines, 2);
for(unsigned int i = 0 ; i < sublines.size() / 2 ; i += 2) {
source_lines.erase(Line(sublines[i], sublines[i + 1]));
}
}
if(point_primitive) {
extract_primitives(cluster_vertices, point_primitive, subpoints, 1);
for(unsigned int i = 0 ; i < subpoints.size() ; ++ i) {
source_points.erase(subpoints[i]);
else {
++ line;
}
}
}
// let's consider that every new lines adds 2 vertices for simplicity
while(!source_lines.empty() && cluster_vertices.size() - 1 < _maxAllowedIndex) {
Line line = *source_lines.begin();
source_lines.erase(source_lines.begin());
cluster_vertices.insert(line._a);
cluster_vertices.insert(line._b);
sublines.push_back(line._a);
sublines.push_back(line._b);
}
while(!source_points.empty() && cluster_vertices.size() < _maxAllowedIndex) {
unsigned int point = *source_points.begin();
source_points.erase(source_points.begin());
cluster_vertices.insert(point);
subpoints.push_back(point);
if(point_primitive) {
// find all cluster vertices that should also have a point primitive
for(IndexSet::iterator subvertex = cluster.subvertices.begin() ; subvertex != cluster.subvertices.end() ; ++ subvertex) {
unsigned int index = *subvertex;
if(points.find(index) != points.end()) {
cluster.addPoint(index);
points.erase(index);
}
}
}
// finally extract wireframe (may originate from triangles or lines but necessarily have
// to reference vertices that are *all* in the geometry)
if(wire_primitive) {
extract_primitives(cluster_vertices, wire_primitive, subwireframe, 2);
for(LineSet::iterator wire = wires.begin() ; wire != wires.end() ; ) {
if(cluster.contains(wire->_a, wire->_b)) {
cluster.addWire(wire->_a, wire->_b);
wires.erase(wire ++);
}
else {
++ wire;
}
}
}
_geometryList.push_back(SubGeometry(geometry,
subtriangles,
sublines,
subwireframe,
subpoints).geometry());
cluster.subtriangles,
cluster.sublines,
cluster.subwireframe,
cluster.subpoints).geometry());
}
osg::notify(osg::NOTICE) << "geometry " << &geometry << " " << geometry.getName()
@@ -164,60 +149,20 @@ bool GeometryIndexSplitter::split(osg::Geometry& geometry) {
}
unsigned int GeometryIndexSplitter::findCandidate(const IndexVector& clusters) {
for(unsigned int i = 0 ; i < clusters.size() ; ++ i) {
if(!clusters[i]) {
return i;
}
}
return std::numeric_limits<unsigned int>::max();
}
unsigned int GeometryIndexSplitter::findCandidate(const IndexVector& candidates, const IndexVector& clusters) {
for(IndexVector::const_iterator candidate = candidates.begin() ; candidate != candidates.end() ; ++ candidate) {
if(!clusters[*candidate]) {
return *candidate;
}
}
return std::numeric_limits<unsigned int>::max();
}
void GeometryIndexSplitter::setTriangleCluster(const TriangleMeshGraph& graph,
unsigned int triangle,
unsigned int cluster,
IndexVector& clusters,
IndexSet& cluster_vertices,
unsigned int& remaining) {
clusters[triangle] = cluster;
const Triangle& t = graph.triangle(triangle);
cluster_vertices.insert(t.v1());
cluster_vertices.insert(t.v2());
cluster_vertices.insert(t.v3());
remaining --;
}
void GeometryIndexSplitter::extract_primitives(const IndexSet& vertices,
const osg::DrawElements* elements,
IndexVector& indices,
unsigned int primitive_size) {
for(unsigned int i = 0 ; i < elements->getNumIndices() ; i += primitive_size) {
bool is_included = true;
for(unsigned int j = 0 ; j < primitive_size ; ++ j) {
if(!vertices.count(elements->index(i + j))) {
is_included = false;
break;
}
}
if(is_included) {
for(unsigned int j = 0 ; j < primitive_size ; ++ j) {
indices.push_back(elements->index(i + j));
unsigned int GeometryIndexSplitter::findCandidate(IndexSet& triangles, const IndexCache& cache, const TriangleMeshGraph& graph) {
// look for unclustered neighboring triangles
for(IndexCache::const_reverse_iterator cached = cache.rbegin() ; cached != cache.rend() ; ++ cached) {
IndexVector candidates = graph.triangleNeighbors(*cached);
for(IndexVector::const_iterator candidate = candidates.begin() ; candidate != candidates.end() ; ++ candidate) {
if(triangles.count(*candidate)) {
triangles.erase(*candidate);
return *candidate;
}
}
}
//fallback on any unclustered triangle
return getNext(triangles, std::numeric_limits<unsigned int>::max());
}
@@ -276,10 +221,3 @@ void GeometryIndexSplitter::setBufferBoundingBox(T* buffer) const {
buffer->setUserValue("ufr", ufr);
}
}
void GeometryIndexSplitter::setValidIndices(std::set<unsigned int>& indices, const osg::DrawElements* primitive) const {
for(unsigned int j = 0 ; j < primitive->getNumIndices() ; ++ j) {
indices.insert(primitive->index(j));
}
}

View File

@@ -7,6 +7,7 @@
#include <sstream>
#include "GeometryUniqueVisitor"
#include "glesUtil"
#include <osg/Geode>
#include <osgDB/ReaderWriter>
@@ -34,8 +35,7 @@ public:
osgAnimation::MorphGeometry::MorphTargetList targets = morphGeometry.getMorphTargetList();
unsigned int count = 0;
for(osgAnimation::MorphGeometry::MorphTargetList::iterator target = targets.begin() ; target != targets.end() ; ++ target, ++ count) {
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry(*target->getGeometry());
geometry->setPrimitiveSetList(morphGeometry.getPrimitiveSetList());
glesUtil::TargetGeometry geometry(*target, morphGeometry);
std::ostringstream oss;
if(geometry->getName().empty()) {
oss << "/tmp/noname_" << _processed.size();

View File

@@ -0,0 +1,31 @@
/* -*-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_MAPPER
#define GEOMETRY_MAPPER
#include <vector>
#include <osg/ref_ptr>
#include <osg/Geometry>
typedef std::vector< osg::ref_ptr<osg::Geometry> > GeometryList;
class GeometryMapper {
public:
// map one geometry to a list of geometries
// to be used with RemapGeometryVisitor
virtual const GeometryList& process(osg::Geometry&) = 0;
};
#endif

View File

@@ -16,26 +16,32 @@
#include <osg/Node>
#include <algorithm> //std::max
#include "AnimationCleanerVisitor"
#include "RigAnimationVisitor"
//animation:
#include "AABBonBoneVisitor"
#include "AnimationCleanerVisitor"
#include "DisableAnimationVisitor"
#include "LimitMorphTargetCount"
#include "MostInfluencedGeometryByBone"
#include "RigAnimationVisitor"
#include "RigAttributesVisitor"
// geometry:
#include "BindPerVertexVisitor"
#include "DetachPrimitiveVisitor"
#include "DrawArrayVisitor"
#include "GeometrySplitterVisitor"
#include "IndexMeshVisitor"
#include "PreTransformVisitor"
#include "RemapGeometryVisitor"
#include "SmoothNormalVisitor"
#include "TangentSpaceVisitor"
#include "TriangleStripVisitor"
#include "UnIndexMeshVisitor"
#include "WireframeVisitor"
#include "AABBonBoneVisitor"
#include "AnimationCleanerVisitor"
#include "MostInfluencedGeometryByBone"
#include "LimitMorphTargetCount"
#include "RigAttributesVisitor"
#include "GeometryIndexSplitter"
#include "GeometryCleaner"
// debug
#include "GeometryInspector"
@@ -165,6 +171,12 @@ protected:
node->accept(indexer);
}
void makeCleanGeometry(osg::Node* node) {
GeometryCleaner cleaner;
RemapGeometryVisitor remapper(cleaner, _exportNonGeometryDrawables);
node->accept(remapper);
}
void makeSmoothNormal(osg::Node* node) {
SmoothNormalVisitor smoother(osg::PI / 4.f, true);
node->accept(smoother);
@@ -176,8 +188,9 @@ protected:
}
void makeSplit(osg::Node* node) {
GeometrySplitterVisitor splitter(_maxIndexValue, _exportNonGeometryDrawables );
node->accept(splitter);
GeometryIndexSplitter splitter(_maxIndexValue);
RemapGeometryVisitor remapper(splitter, _exportNonGeometryDrawables);
node->accept(remapper);
}
void makeTriStrip(osg::Node* node) {

View File

@@ -26,6 +26,12 @@ osg::Node* OpenGLESGeometryOptimizer::optimize(osg::Node& node) {
// index (merge exact duplicates + uses simple triangles & lines i.e. no strip/fan/loop)
makeIndexMesh(model.get());
// clean (remove degenerated data)
std::string authoringTool;
if(model->getUserValue("authoring_tool", authoringTool) && authoringTool == "Tilt Brush") {
makeCleanGeometry(model.get());
}
// smooth vertex normals (if geometry has no normal compute smooth normals)
makeSmoothNormal(model.get());

View File

@@ -0,0 +1,51 @@
/* -*-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 REMAP_GEOMETRY_VISITOR
#define REMAP_GEOMETRY_VISITOR
#include <map>
#include <osg/ref_ptr>
#include <osg/Geometry>
#include <osgAnimation/RigGeometry>
#include "GeometryUniqueVisitor"
#include "GeometryMapper"
class RemapGeometryVisitor : public GeometryUniqueVisitor {
public:
typedef std::vector< osg::ref_ptr<osg::Geometry> > GeometryList;
typedef std::vector< osg::ref_ptr<osg::Drawable> > DrawableList;
typedef std::map<osg::Geometry*, GeometryList> GeometryMap;
RemapGeometryVisitor(GeometryMapper& mapper, bool exportNonGeometryDrawables=false):
GeometryUniqueVisitor("RemapGeometryVisitor"),
_mapper(mapper),
_exportNonGeometryDrawables(exportNonGeometryDrawables)
{}
void apply(osg::Geode&);
void process(osg::Geometry&);
protected:
bool isProcessed(osg::Geometry*);
void setProcessed(osg::Geometry*, const GeometryList&);
protected:
GeometryMapper& _mapper;
std::map<osg::Geometry*, GeometryList> _remap;
bool _exportNonGeometryDrawables;
};
#endif

View File

@@ -0,0 +1,72 @@
#include "RemapGeometryVisitor"
#include "glesUtil"
void RemapGeometryVisitor::apply(osg::Geode& geode) {
GeometryUniqueVisitor::apply(geode);
GeometryList remappedGeometries;
DrawableList nonGeometryDrawables;
for(unsigned int i = 0 ; i < geode.getNumDrawables() ; ++ i) {
osg::Geometry* geometry = geode.getDrawable(i)->asGeometry();
if(geometry) {
if(osgAnimation::RigGeometry* rigGeometry = dynamic_cast<osgAnimation::RigGeometry*>(geometry)) {
GeometryMap::iterator lookup = _remap.find(rigGeometry->getSourceGeometry());
if(lookup != _remap.end() && !lookup->second.empty()) {
// convert now static rigGeometry into simple Geometry
for(GeometryList::iterator mapped = lookup->second.begin() ; mapped != lookup->second.end() ; ++ mapped) {
if(glesUtil::hasPositiveWeights(mapped->get())) {
osgAnimation::RigGeometry* mappedRig = new osgAnimation::RigGeometry(*rigGeometry);
mappedRig->setSourceGeometry(mapped->get());
remappedGeometries.push_back(mappedRig);
}
else {
remappedGeometries.push_back(mapped->get());
}
}
}
}
else {
GeometryMap::iterator lookup = _remap.find(geometry);
if(lookup != _remap.end() && !lookup->second.empty()) {
remappedGeometries.insert(remappedGeometries.end(), lookup->second.begin(), lookup->second.end());
}
}
}
else {
nonGeometryDrawables.push_back(geode.getDrawable(i));
}
}
// remove all drawables
geode.removeDrawables(0, geode.getNumDrawables());
// insert splitted geometries
for(unsigned int i = 0 ; i < remappedGeometries.size() ; ++ i) {
geode.addDrawable(remappedGeometries[i].get());
}
if(_exportNonGeometryDrawables) {
// insert other drawables (e.g. osgText)
for(unsigned int i = 0 ; i < nonGeometryDrawables.size() ; ++ i) {
geode.addDrawable(nonGeometryDrawables[i].get());
}
}
}
void RemapGeometryVisitor::process(osg::Geometry& geometry) {
const GeometryList& mapped = _mapper.process(geometry);
setProcessed(&geometry, mapped);
}
bool RemapGeometryVisitor::isProcessed(osg::Geometry* node) {
return _remap.find(node) != _remap.end();
}
void RemapGeometryVisitor::setProcessed(osg::Geometry* node, const GeometryList& list) {
_remap.insert(std::pair<osg::Geometry*, GeometryList>(node, GeometryList(list)));
}

View File

@@ -5,6 +5,7 @@
#include "GeometryUniqueVisitor"
#include "TriangleMeshSmoother"
#include "glesUtil"
class SmoothNormalVisitor : public GeometryUniqueVisitor {
@@ -25,20 +26,41 @@ public:
}
void process(osgAnimation::MorphGeometry& morphGeometry) {
TriangleMeshSmoother(morphGeometry, 0, true, TriangleMeshSmoother::smooth_all);
osgAnimation::MorphGeometry::MorphTargetList targets = morphGeometry.getMorphTargetList();
for(osgAnimation::MorphGeometry::MorphTargetList::iterator target = targets.begin() ; target != targets.end() ; ++ target) {
// check normal orientation using the same primitives as parent geometry
osg::Geometry::PrimitiveSetList& primitives = target->getGeometry()->getPrimitiveSetList();
target->getGeometry()->setPrimitiveSetList(morphGeometry.getPrimitiveSetList());
bool needSmoothing = needMorphGeometrySmoothing(morphGeometry);
TriangleMeshSmoother(*target->getGeometry(), 0, true, TriangleMeshSmoother::smooth_all);
if(needSmoothing) {
TriangleMeshSmoother(morphGeometry, 0, true, TriangleMeshSmoother::smooth_all);
target->getGeometry()->setPrimitiveSetList(primitives);
osgAnimation::MorphGeometry::MorphTargetList targets = morphGeometry.getMorphTargetList();
for(osgAnimation::MorphGeometry::MorphTargetList::iterator target = targets.begin() ; target != targets.end() ; ++ target) {
// check normal orientation using the same primitives as parent geometry
glesUtil::TargetGeometry geometry(*target, morphGeometry);
if(geometry && !geometry->getNormalArray()) {
TriangleMeshSmoother(*geometry, 0, true, TriangleMeshSmoother::smooth_all);
}
}
}
}
protected:
bool needMorphGeometrySmoothing(osgAnimation::MorphGeometry& morphGeometry) {
if(!morphGeometry.getNormalArray()) {
return true;
}
osgAnimation::MorphGeometry::MorphTargetList targets = morphGeometry.getMorphTargetList();
for(osgAnimation::MorphGeometry::MorphTargetList::iterator target = targets.begin() ; target != targets.end() ; ++ target) {
osg::Geometry* geometry = target->getGeometry();
if(geometry && !geometry->getNormalArray()) {
return true;
}
}
return false;
}
float _creaseAngle;
bool _comparePosition;
};

View File

@@ -1,26 +1,13 @@
#include "TangentSpaceVisitor"
#include "glesUtil"
void TangentSpaceVisitor::process(osgAnimation::MorphGeometry& morphGeometry) {
process(static_cast<osg::Geometry&>(morphGeometry));
osgAnimation::MorphGeometry::MorphTargetList& targets = morphGeometry.getMorphTargetList();
for(osgAnimation::MorphGeometry::MorphTargetList::iterator target = targets.begin() ; target != targets.end() ; ++ target) {
osg::Geometry* geometry = target->getGeometry();
bool useParentMorphTexCoord = geometry->getTexCoordArrayList().empty();
if(useParentMorphTexCoord) {
// tangent space require tex coords; in case a target has no tex coords, we try to
// bind the parent geometry tex coords
geometry->setTexCoordArrayList(morphGeometry.getTexCoordArrayList());
}
glesUtil::TargetGeometry geometry(*target, morphGeometry);
process(*geometry);
if(useParentMorphTexCoord) {
// drop parent tex coords after tangent space computation
geometry->setTexCoordArrayList(osg::Geometry::ArrayList());
}
}
}
@@ -36,6 +23,9 @@ void TangentSpaceVisitor::process(osg::Geometry& geometry) {
geometry.getVertexAttribArray(tangentIndex)->setUserValue("tangent", true);
return;
}
else {
OSG_WARN << "Anomaly: [TangentSpaceVisitor] Missing tangent array at specificied index." << std::endl;
}
}
if (!geometry.getTexCoordArray(_textureUnit)){
@@ -56,21 +46,6 @@ void TangentSpaceVisitor::process(osg::Geometry& geometry) {
osg::ref_ptr<osgUtil::TangentSpaceGenerator> generator = new osgUtil::TangentSpaceGenerator;
generator->generate(&geometry, _textureUnit);
// keep original normal array
if (!geometry.getNormalArray()) {
if (generator->getNormalArray()) {
osg::Vec3Array* vec3Normals = new osg::Vec3Array();
osg::Vec4Array* vec4Normals = generator->getNormalArray();
for (unsigned int i = 0; i < vec4Normals->size(); i++) {
osg::Vec3 n = osg::Vec3((*vec4Normals)[i][0],
(*vec4Normals)[i][1],
(*vec4Normals)[i][2]);
vec3Normals->push_back(n);
}
geometry.setNormalArray(vec3Normals, osg::Array::BIND_PER_VERTEX);
}
}
if (generator->getTangentArray()) {
osg::Vec4Array* normal = generator->getNormalArray();
osg::Vec4Array* tangent = generator->getTangentArray();

View File

@@ -244,14 +244,16 @@ void TriangleMeshSmoother::updateGeometryPrimitives() {
}
}
osg::DrawElementsUInt* triangles = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES);
for(unsigned int i = 0 ; i < _graph->getNumTriangles() ; ++ i) {
const Triangle& triangle = _graph->triangle(i);
triangles->push_back(triangle.v1());
triangles->push_back(triangle.v2());
triangles->push_back(triangle.v3());
if(_graph->getNumTriangles()) {
osg::DrawElementsUInt* triangles = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES);
for(unsigned int i = 0 ; i < _graph->getNumTriangles() ; ++ i) {
const Triangle& triangle = _graph->triangle(i);
triangles->push_back(triangle.v1());
triangles->push_back(triangle.v2());
triangles->push_back(triangle.v3());
}
primitives.push_back(triangles);
}
primitives.push_back(triangles);
_geometry.setPrimitiveSetList(primitives);
}

View File

@@ -25,7 +25,7 @@ namespace glesUtil {
using namespace std;
using namespace osg;
typedef std::vector<unsigned int> IndexList;
typedef osgAnimation::MorphGeometry::MorphTargetList MorphTargetList;
inline bool hasPositiveWeights(const osg::Geometry* geometry) {
const osg::Vec4Array* weights = 0;
@@ -53,6 +53,52 @@ namespace glesUtil {
}
class TargetGeometry {
public:
TargetGeometry(osgAnimation::MorphGeometry::MorphTarget& target,
osgAnimation::MorphGeometry& morph):
_geometry(0)
{
_geometry = target.getGeometry();
_geometry->setPrimitiveSetList(morph.getPrimitiveSetList());
_hasTexCoord = _geometry->getTexCoordArrayList().size();
if(!_hasTexCoord) {
_geometry->setTexCoordArrayList(morph.getTexCoordArrayList());
}
}
osg::Geometry* operator->() {
return _geometry;
}
operator osg::Geometry*() {
return _geometry;
}
operator osg::Geometry&() {
return *_geometry;
}
operator bool() {
return _geometry != 0;
}
~TargetGeometry() {
if(!_hasTexCoord) {
// drop parent tex coords after tangent space computation
_geometry->setTexCoordArrayList(osg::Geometry::ArrayList());
}
_geometry->setPrimitiveSetList(osg::Geometry::PrimitiveSetList());
}
protected:
osg::Geometry* _geometry;
bool _hasTexCoord;
};
// 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.
@@ -61,6 +107,20 @@ namespace glesUtil {
typedef std::vector<osg::Array*> ArrayList;
GeometryArrayGatherer(osg::Geometry& geometry) {
addGeometryVertexAttributes(geometry);
_targetAttributesIndex = _arrayList.size();
if(osgAnimation::MorphGeometry* morphGeometry = dynamic_cast<osgAnimation::MorphGeometry*>(&geometry)) {
MorphTargetList targets = morphGeometry->getMorphTargetList();
for (MorphTargetList::iterator iterator = targets.begin(); iterator != targets.end(); ++ iterator) {
if(iterator->getGeometry()) {
addTargetVertexAttributes(*iterator->getGeometry());
}
}
}
}
void addGeometryVertexAttributes(osg::Geometry& geometry) {
add(geometry.getVertexArray());
add(geometry.getNormalArray());
add(geometry.getColorArray());
@@ -74,6 +134,10 @@ namespace glesUtil {
}
}
void addTargetVertexAttributes(osg::Geometry& target) {
add(target.getVertexArray());
}
void add(osg::Array* array) {
if (array) {
_arrayList.push_back(array);
@@ -81,12 +145,16 @@ namespace glesUtil {
}
void accept(osg::ArrayVisitor& av) {
for(ArrayList::iterator itr = _arrayList.begin() ; itr != _arrayList.end(); ++ itr) {
unsigned int geometryAttributesIndex = 0;
for(ArrayList::iterator itr = _arrayList.begin() ;
geometryAttributesIndex < _targetAttributesIndex && itr != _arrayList.end();
++ geometryAttributesIndex, ++ itr) {
(*itr)->accept(av);
}
}
ArrayList _arrayList;
unsigned int _targetAttributesIndex;
};
@@ -349,8 +417,8 @@ namespace glesUtil {
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) {
MorphTargetList targetList = morphGeometry->getMorphTargetList();
for (MorphTargetList::iterator ti = targetList.begin(); ti != targetList.end(); ++ti) {
osgAnimation::MorphGeometry::MorphTarget *morphTarget = &(*ti);
osg::Geometry *target = morphTarget->getGeometry();
GeometryArrayGatherer gatherer(*target);

View File

@@ -45,7 +45,7 @@ bool addJSONChannel(const std::string& channelType, T* channel, bool packByCoord
osg::ref_ptr<JSONObject> json = new JSONObject;
std::string jsonType = channelType + (packByCoords ? "Packed" : "");
translateObject(json.get(), channel);
writer->translateObject(json.get(), channel);
json->getMaps()["Name"] = new JSONValue<std::string>(channel->getName());
json->getMaps()["TargetName"] = new JSONValue<std::string>(channel->getTargetName());

View File

@@ -125,7 +125,7 @@ public:
writer.setBaseName(basename);
writer.useExternalBinaryArray(options.useExternalBinaryArray);
writer.mergeAllBinaryFiles(options.mergeAllBinaryFiles);
writer.inlineImages(options.inlineImages);
writer.setInlineImages(options.inlineImages);
writer.setMaxTextureDimension(options.resizeTextureUpToPowerOf2);
writer.setVarint(options.varint);
writer.setBaseLodURL(options.baseLodURL);

View File

@@ -29,8 +29,10 @@
#include <osgAnimation/Bone>
#include <osgAnimation/UpdateBone>
#include <osgSim/ShapeAttribute>
#include <osgText/Text>
#
#include <fstream>
#include <sstream>
#include <vector>
@@ -47,8 +49,9 @@
#define WRITER_VERSION 9
class WriteVisitor;
osg::Array* getTangentSpaceArray(osg::Geometry& geometry);
void translateObject(JSONObject* json, osg::Object* osg);
void getStringifiedUserValue(osg::Object* o, std::string& name, std::string& value);
template<typename T>
bool getStringifiedUserValue(osg::Object* o, std::string& name, std::string& value);
@@ -59,8 +62,9 @@ class WriteVisitor : public osg::NodeVisitor
public:
typedef std::vector<osg::ref_ptr<osg::StateSet> > StateSetStack;
typedef std::pair<std::string, std::string> KeyValue;
typedef std::map<osg::ref_ptr<osg::Object>, osg::ref_ptr<JSONObject> > OsgObjectToJSONObject;
std::map<osg::ref_ptr<osg::Object>, osg::ref_ptr<JSONObject> > _maps;
OsgObjectToJSONObject _maps;
std::vector<osg::ref_ptr<JSONObject> > _parents;
osg::ref_ptr<JSONObject> _root;
StateSetStack _stateset;
@@ -74,6 +78,20 @@ public:
std::map<KeyValue, std::string> _specificBuffers;
std::map<std::string, std::ofstream*> _buffers;
JSONObject* getJSON(osg::Object* object) const {
OsgObjectToJSONObject::const_iterator lookup = _maps.find(object);
if(lookup != _maps.end()) {
return lookup->second->getShadowObject();
}
return 0;
}
void setJSON(osg::Object* object, JSONObject* json) {
if(json) {
_maps[object] = json;
}
}
std::ofstream& getBufferFile(const std::string& name) {
if(_buffers.find(name) == _buffers.end()) {
_buffers[name] = new std::ofstream(name.c_str(), std::ios::binary);
@@ -238,6 +256,10 @@ public:
return getBinaryFilename(flag);
}
void translateObject(JSONObject* json, osg::Object* osg);
JSONObject* createJSONOsgSimUserData(osgSim::ShapeAttributeList*);
JSONObject* createJSONUserDataContainer(osg::UserDataContainer*);
JSONObject* createJSONPagedLOD(osg::PagedLOD* plod);
JSONObject* createJSONStateSet(osg::StateSet* ss);
JSONObject* createJSONTexture(osg::Texture* sa);
@@ -650,10 +672,14 @@ public:
_parents.pop_back();
}
std::string getBaseName() const { return _baseName; }
bool getInlineImages() const { return _inlineImages; }
int getMaxTextureDimension() const { return _maxTextureDimension; }
void setBaseName(const std::string& basename) { _baseName = basename; }
void useExternalBinaryArray(bool use) { _useExternalBinaryArray = use; }
void mergeAllBinaryFiles(bool use) { _mergeAllBinaryFiles = use; }
void inlineImages(bool use) { _inlineImages = use; }
void setInlineImages(bool use) { _inlineImages = use; }
void setVarint(bool use) { _varint = use; }
void setMaxTextureDimension(int use) { _maxTextureDimension = use; }
void addSpecificBuffer(const std::string& bufferFlag) {

View File

@@ -11,8 +11,6 @@
#include <osg/Material>
#include <osg/BlendFunc>
#include <osgSim/ShapeAttribute>
#include <osgText/Text>
#include <osgAnimation/MorphGeometry>
@@ -76,82 +74,6 @@ osg::ref_ptr<JSONObject> buildRigBoneMap(osgAnimation::RigGeometry& rigGeometry)
}
void translateObject(JSONObject* json, osg::Object* osg)
{
if (!osg->getName().empty()) {
json->getMaps()["Name"] = new JSONValue<std::string>(osg->getName());
}
osgSim::ShapeAttributeList* osgSim_userdata = dynamic_cast<osgSim::ShapeAttributeList* >(osg->getUserData());
if (osgSim_userdata) {
JSONObject* jsonUDC = new JSONObject();
jsonUDC->addUniqueID();
JSONArray* jsonUDCArray = new JSONArray();
jsonUDC->getMaps()["Values"] = jsonUDCArray;
for (unsigned int i = 0; i < osgSim_userdata->size(); i++) {
const osgSim::ShapeAttribute& attr = (*osgSim_userdata)[i];
JSONObject* jsonEntry = new JSONObject();
jsonEntry->getMaps()["Name"] = new JSONValue<std::string>(attr.getName());
osg::ref_ptr<JSONValue<std::string> > value;
switch(attr.getType()) {
case osgSim::ShapeAttribute::INTEGER:
{
std::stringstream ss;
ss << attr.getInt();
value = new JSONValue<std::string>(ss.str());
}
break;
case osgSim::ShapeAttribute::DOUBLE:
{
std::stringstream ss;
ss << attr.getDouble();
value = new JSONValue<std::string>(ss.str());
}
break;
case osgSim::ShapeAttribute::STRING:
{
std::stringstream ss;
ss << attr.getString();
value = new JSONValue<std::string>(ss.str());
}
break;
case osgSim::ShapeAttribute::UNKNOWN:
default:
break;
}
jsonEntry->getMaps()["Value"] = value;
jsonUDCArray->getArray().push_back(jsonEntry);
}
json->getMaps()["UserDataContainer"] = jsonUDC;
} else if (osg->getUserDataContainer()) {
JSONObject* jsonUDC = new JSONObject();
jsonUDC->addUniqueID();
if (!osg->getUserDataContainer()->getName().empty()) {
jsonUDC->getMaps()["Name"] = new JSONValue<std::string>(osg->getUserDataContainer()->getName());
}
JSONArray* jsonUDCArray = new JSONArray();
jsonUDC->getMaps()["Values"] = jsonUDCArray;
for (unsigned int i = 0; i < osg->getUserDataContainer()->getNumUserObjects(); i++) {
osg::Object* o = osg->getUserDataContainer()->getUserObject(i);
std::string name, value;
getStringifiedUserValue(o, name, value);
if(!name.empty() && !value.empty())
{
JSONObject* jsonEntry = new JSONObject();
jsonEntry->getMaps()["Name"] = new JSONValue<std::string>(name);
jsonEntry->getMaps()["Value"] = new JSONValue<std::string>(value);
jsonUDCArray->getArray().push_back(jsonEntry);
}
}
json->getMaps()["UserDataContainer"] = jsonUDC;
}
}
void getStringifiedUserValue(osg::Object* o, std::string& name, std::string& value) {
if(getStringifiedUserValue<std::string>(o, name, value)) return;
if(getStringifiedUserValue<char>(o, name, value)) return;
@@ -352,6 +274,108 @@ JSONObject* createImage(osg::Image* image, bool inlineImages, int maxTextureDime
}
JSONObject* WriteVisitor::createJSONOsgSimUserData(osgSim::ShapeAttributeList* osgSimData) {
JSONObject* jsonUDC = new JSONObject();
jsonUDC->addUniqueID();
JSONArray* jsonUDCArray = new JSONArray();
jsonUDC->getMaps()["Values"] = jsonUDCArray;
for (unsigned int i = 0; i < osgSimData->size(); i++) {
const osgSim::ShapeAttribute& attr = (*osgSimData)[i];
JSONObject* jsonEntry = new JSONObject();
jsonEntry->getMaps()["Name"] = new JSONValue<std::string>(attr.getName());
osg::ref_ptr<JSONValue<std::string> > value;
switch(attr.getType()) {
case osgSim::ShapeAttribute::INTEGER:
{
std::stringstream ss;
ss << attr.getInt();
value = new JSONValue<std::string>(ss.str());
}
break;
case osgSim::ShapeAttribute::DOUBLE:
{
std::stringstream ss;
ss << attr.getDouble();
value = new JSONValue<std::string>(ss.str());
}
break;
case osgSim::ShapeAttribute::STRING:
{
std::stringstream ss;
ss << attr.getString();
value = new JSONValue<std::string>(ss.str());
}
break;
case osgSim::ShapeAttribute::UNKNOWN:
default:
break;
}
jsonEntry->getMaps()["Value"] = value;
jsonUDCArray->getArray().push_back(jsonEntry);
}
return jsonUDC;
}
JSONObject* WriteVisitor::createJSONUserDataContainer(osg::UserDataContainer* container) {
JSONObject* jsonUDC = new JSONObject();
jsonUDC->addUniqueID();
if (!container->getName().empty()) {
jsonUDC->getMaps()["Name"] = new JSONValue<std::string>(container->getName());
}
JSONArray* jsonUDCArray = new JSONArray();
jsonUDC->getMaps()["Values"] = jsonUDCArray;
for (unsigned int i = 0; i < container->getNumUserObjects(); i++) {
osg::Object* o = container->getUserObject(i);
std::string name, value;
getStringifiedUserValue(o, name, value);
if(!name.empty() && !value.empty())
{
JSONObject* jsonEntry = new JSONObject();
jsonEntry->getMaps()["Name"] = new JSONValue<std::string>(name);
jsonEntry->getMaps()["Value"] = new JSONValue<std::string>(value);
jsonUDCArray->getArray().push_back(jsonEntry);
}
}
return jsonUDC;
}
void WriteVisitor::translateObject(JSONObject* json, osg::Object* osg)
{
if (!osg->getName().empty()) {
json->getMaps()["Name"] = new JSONValue<std::string>(osg->getName());
}
JSONObject* jsonUDC = 0;
osgSim::ShapeAttributeList* osgSimData = dynamic_cast<osgSim::ShapeAttributeList* >(osg->getUserData());
if (osgSimData) {
jsonUDC = this->getJSON(osgSimData);
if(!jsonUDC) {
jsonUDC = createJSONOsgSimUserData(osgSimData);
this->setJSON(osgSimData, jsonUDC);
}
}
else if (osg::UserDataContainer* container = osg->getUserDataContainer()) {
jsonUDC = this->getJSON(container);
if(!jsonUDC) {
jsonUDC = createJSONUserDataContainer(container);
this->setJSON(container, jsonUDC);
}
}
if(jsonUDC) {
json->getMaps()["UserDataContainer"] = jsonUDC;
}
}
JSONObject* WriteVisitor::createJSONBufferArray(osg::Array* array, osg::Object* parent)
{
if (_maps.find(array) != _maps.end())
@@ -765,12 +789,16 @@ JSONObject* WriteVisitor::createJSONLight(osg::Light* light)
return jsonLight.release();
}
template <class T> JSONObject* createImageFromTexture(osg::Texture* texture, JSONObject* jsonTexture, bool inlineImages,
int maxTextureDimension, const std::string &baseName = "")
template <class T>
JSONObject* createImageFromTexture(osg::Texture* texture, JSONObject* jsonTexture, WriteVisitor* writer)
{
bool inlineImages = writer->getInlineImages();
int maxTextureDimension = writer->getMaxTextureDimension();
const std::string baseName = writer->getBaseName();
T* text = dynamic_cast<T*>( texture);
if (text) {
translateObject(jsonTexture,text);
writer->translateObject(jsonTexture,text);
JSONObject* image = createImage(text->getImage(), inlineImages, maxTextureDimension, baseName);
if (image)
jsonTexture->getMaps()["File"] = image;
@@ -902,24 +930,21 @@ JSONObject* WriteVisitor::createJSONTexture(osg::Texture* texture)
{
JSONObject* obj = createImageFromTexture<osg::Texture1D>(texture, jsonTexture.get(), this->_inlineImages,
this->_maxTextureDimension, this->_baseName);
JSONObject* obj = createImageFromTexture<osg::Texture1D>(texture, jsonTexture.get(), this);
if (obj) {
return obj;
}
}
{
JSONObject* obj = createImageFromTexture<osg::Texture2D>(texture, jsonTexture.get(), this->_inlineImages,
this->_maxTextureDimension, this->_baseName);
JSONObject* obj = createImageFromTexture<osg::Texture2D>(texture, jsonTexture.get(), this);
if (obj) {
return obj;
}
}
{
JSONObject* obj = createImageFromTexture<osg::TextureRectangle>(texture, jsonTexture.get(), this->_inlineImages,
this->_maxTextureDimension, this->_baseName);
JSONObject* obj = createImageFromTexture<osg::TextureRectangle>(texture, jsonTexture.get(), this);
if (obj) {
return obj;
}