From 6fd972fa429fc2d8eac77984e7d0f967d3d85ae0 Mon Sep 17 00:00:00 2001 From: Marc Helbling Date: Tue, 5 Jul 2016 16:32:00 +0200 Subject: [PATCH 1/3] Fixes gles coverity defects --- src/osgPlugins/gles/AABBonBoneVisitor | 285 ++++++++++-------- src/osgPlugins/gles/AnimationCleanerVisitor | 22 +- src/osgPlugins/gles/GeometryArray | 23 +- src/osgPlugins/gles/GeometryInspector | 5 +- src/osgPlugins/gles/GeometrySplitterVisitor | 3 +- src/osgPlugins/gles/LimitMorphTargetCount | 4 +- src/osgPlugins/gles/Line | 2 + src/osgPlugins/gles/OpenGLESGeometryOptimizer | 1 + src/osgPlugins/gles/PrimitiveIndexors | 2 + src/osgPlugins/gles/RigAnimationVisitor | 2 +- src/osgPlugins/gles/RigAttributesVisitor | 4 +- src/osgPlugins/gles/SmoothNormalVisitor | 13 +- src/osgPlugins/gles/StatLogger | 2 + src/osgPlugins/gles/SubGeometry | 15 +- src/osgPlugins/gles/TriangleMeshGraph | 12 +- src/osgPlugins/gles/glesUtil | 2 + 16 files changed, 219 insertions(+), 178 deletions(-) diff --git a/src/osgPlugins/gles/AABBonBoneVisitor b/src/osgPlugins/gles/AABBonBoneVisitor index dcb9f01aa..b2857c7af 100644 --- a/src/osgPlugins/gles/AABBonBoneVisitor +++ b/src/osgPlugins/gles/AABBonBoneVisitor @@ -1,4 +1,4 @@ -/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson +/* -*-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 @@ -36,90 +36,6 @@ public: typedef std::vector RigGeometryList; - osg::Geometry* createBox(const osg::BoundingBox &bb, const osg::Matrix &transform, - float ratio=1.0, osg::Vec4 color=osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f)) { - osg::Geometry *cube = new osg::Geometry; - - osg::Vec3 center = bb.center(); - double halfLenghtX = (bb._max.x() - bb._min.x()) * 0.50; - double halfLenghtY = (bb._max.y() - bb._min.y()) * 0.50; - double halfLenghtZ = (bb._max.z() - bb._min.z()) * 0.50; - - halfLenghtX *= ratio; - halfLenghtY *= ratio; - halfLenghtZ *= ratio; - - osg::Vec3Array *cubeVertices = new osg::Vec3Array; - cubeVertices->push_back(osg::Vec3(center.x() - halfLenghtX, center.y() + halfLenghtY, center.z() + halfLenghtZ) * transform); - cubeVertices->push_back(osg::Vec3(center.x() - halfLenghtX, center.y() + halfLenghtY, center.z() - halfLenghtZ) * transform); - cubeVertices->push_back(osg::Vec3(center.x() - halfLenghtX, center.y() - halfLenghtY, center.z() - halfLenghtZ) * transform); - cubeVertices->push_back(osg::Vec3(center.x() - halfLenghtX, center.y() - halfLenghtY, center.z() + halfLenghtZ) * transform); - - cubeVertices->push_back(osg::Vec3(center.x() + halfLenghtX, center.y() + halfLenghtY, center.z() + halfLenghtZ) * transform); - cubeVertices->push_back(osg::Vec3(center.x() + halfLenghtX, center.y() + halfLenghtY, center.z() - halfLenghtZ) * transform); - cubeVertices->push_back(osg::Vec3(center.x() + halfLenghtX, center.y() - halfLenghtY, center.z() - halfLenghtZ) * transform); - cubeVertices->push_back(osg::Vec3(center.x() + halfLenghtX, center.y() - halfLenghtY, center.z() + halfLenghtZ) * transform); - - cube->setVertexArray(cubeVertices); - - osg::DrawElementsUInt* up = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); - up->push_back(4); - up->push_back(5); - up->push_back(1); - up->push_back(0); - cube->addPrimitiveSet(up); - - osg::DrawElementsUInt* down = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); - down->push_back(2); - down->push_back(6); - down->push_back(7); - down->push_back(3); - cube->addPrimitiveSet(down); - - osg::DrawElementsUInt* left = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); - left->push_back(2); - left->push_back(3); - left->push_back(0); - left->push_back(1); - cube->addPrimitiveSet(left); - - osg::DrawElementsUInt* right = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); - right->push_back(7); - right->push_back(6); - right->push_back(5); - right->push_back(4); - cube->addPrimitiveSet(right); - - osg::DrawElementsUInt* front = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); - front->push_back(3); - front->push_back(7); - front->push_back(4); - front->push_back(0); - cube->addPrimitiveSet(front); - - osg::DrawElementsUInt* back = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); - back->push_back(6); - back->push_back(2); - back->push_back(1); - back->push_back(5); - cube->addPrimitiveSet(back); - - osg::Vec4Array* colors = new osg::Vec4Array; - colors->push_back(color); - colors->push_back(color); - colors->push_back(color); - colors->push_back(color); - colors->push_back(color); - colors->push_back(color); - colors->push_back(color); - colors->push_back(color); - - cube->setColorArray(colors); - cube->setColorBinding(osg::Geometry::BIND_PER_VERTEX); - - return cube; - } - ComputeAABBOnBoneVisitor(bool createGeometry): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _root(0), @@ -149,59 +65,28 @@ public: _rigGeometries.push_back(&rig); } - void serializeBoundingBox(const osg::BoundingBox &bb, const osg::Matrix &transform, osgAnimation::Bone &b, float ratio = 1.0) { - osg::Vec3 center = bb.center(); - double halfLenghtX = (bb._max.x() - bb._min.x()) * 0.50; - double halfLenghtY = (bb._max.y() - bb._min.y()) * 0.50; - double halfLenghtZ = (bb._max.z() - bb._min.z()) * 0.50; - - halfLenghtX *= ratio; - halfLenghtY *= ratio; - halfLenghtZ *= ratio; - - osg::BoundingBox serializedBB; - - serializedBB.expandBy(osg::Vec3(center.x() - halfLenghtX, center.y() + halfLenghtY, center.z() + halfLenghtZ) * transform); - serializedBB.expandBy(osg::Vec3(center.x() - halfLenghtX, center.y() + halfLenghtY, center.z() - halfLenghtZ) * transform); - serializedBB.expandBy(osg::Vec3(center.x() - halfLenghtX, center.y() - halfLenghtY, center.z() - halfLenghtZ) * transform); - serializedBB.expandBy(osg::Vec3(center.x() - halfLenghtX, center.y() - halfLenghtY, center.z() + halfLenghtZ) * transform); - serializedBB.expandBy(osg::Vec3(center.x() + halfLenghtX, center.y() + halfLenghtY, center.z() + halfLenghtZ) * transform); - serializedBB.expandBy(osg::Vec3(center.x() + halfLenghtX, center.y() + halfLenghtY, center.z() - halfLenghtZ) * transform); - serializedBB.expandBy(osg::Vec3(center.x() + halfLenghtX, center.y() - halfLenghtY, center.z() - halfLenghtZ) * transform); - serializedBB.expandBy(osg::Vec3(center.x() + halfLenghtX, center.y() - halfLenghtY, center.z() + halfLenghtZ) * transform); - - b.setUserValue("AABBonBone_min", serializedBB._min); - b.setUserValue("AABBonBone_max", serializedBB._max); - } - void computeBoundingBoxOnBones() { //Perform Updates - - //Update Bones - osgUtil::UpdateVisitor up; - _root->accept(up); - - //Update rigGeometries - for (unsigned int i = 0, size = _rigGeometries.size(); i < size; i++) { - osgAnimation::RigGeometry * rig = _rigGeometries.at(i); - osg::Drawable::UpdateCallback * up = dynamic_cast(rig->getUpdateCallback()); - if(up) up->update(0, rig); - } + updateBones(); + updateRigGeometries(); //We have our T pose, we can compute an AABB for each bone for (BoneList::iterator bone = _bones.begin(); bone != _bones.end(); ++ bone) { osg::BoundingBox bb; //For each geometry - for (RigGeometryList::iterator rigGeometry = _rigGeometries.begin(); rigGeometry != _rigGeometries.end(); ++ rigGeometry) { - osg::Matrix mtxLocalToSkl = (*rigGeometry)->getWorldMatrices(_root).at(0); + for (RigGeometryList::iterator iterator = _rigGeometries.begin(); iterator != _rigGeometries.end(); ++ iterator) { + osgAnimation::RigGeometry* rigGeometry = *iterator; + if(!rigGeometry) continue; + + osg::Matrix mtxLocalToSkl = rigGeometry->getWorldMatrices(_root).at(0); //For each Vertex influence - osgAnimation::VertexInfluenceMap * infMap = (*rigGeometry)->getInfluenceMap(); + osgAnimation::VertexInfluenceMap * infMap = rigGeometry->getInfluenceMap(); osgAnimation::VertexInfluenceMap::iterator itMap = infMap->find((*bone)->getName()); if(itMap == infMap->end()) continue; osgAnimation::VertexInfluence vxtInf = (*itMap).second; - osg::Vec3Array *vertices = dynamic_cast((*rigGeometry)->getVertexArray()); + osg::Vec3Array *vertices = dynamic_cast(rigGeometry->getVertexArray()); //Expand the boundingBox with each vertex for(unsigned int j = 0; j < vxtInf.size(); j++) { @@ -230,14 +115,154 @@ public: } //Clear geometries - for (RigGeometryList::iterator rigGeometry = _rigGeometries.begin(); rigGeometry != _rigGeometries.end(); ++ rigGeometry) { - (*rigGeometry)->copyFrom(*(*rigGeometry)->getSourceGeometry()); - (*rigGeometry)->setRigTransformImplementation(0); + for (RigGeometryList::iterator iterator = _rigGeometries.begin(); iterator != _rigGeometries.end(); ++ iterator) { + osgAnimation::RigGeometry* rigGeometry = *iterator; + if(rigGeometry) { + rigGeometry->copyFrom(*rigGeometry->getSourceGeometry()); + rigGeometry->setRigTransformImplementation(0); + } } } - std::vector _bones; - std::vector _rigGeometries; +protected: + osg::Geometry* createBox(const osg::BoundingBox &bb, const osg::Matrix &transform, + float ratio=1.0, osg::Vec4 color=osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f)) { + osg::Geometry *cube = new osg::Geometry; + + osg::Vec3 center = bb.center(); + double halfLenghtX = (bb._max.x() - bb._min.x()) * 0.50; + double halfLenghtY = (bb._max.y() - bb._min.y()) * 0.50; + double halfLenghtZ = (bb._max.z() - bb._min.z()) * 0.50; + + halfLenghtX *= ratio; + halfLenghtY *= ratio; + halfLenghtZ *= ratio; + + osg::Vec3Array *cubeVertices = new osg::Vec3Array; + cubeVertices->push_back(osg::Vec3(center.x() - halfLenghtX, center.y() + halfLenghtY, center.z() + halfLenghtZ) * transform); + cubeVertices->push_back(osg::Vec3(center.x() - halfLenghtX, center.y() + halfLenghtY, center.z() - halfLenghtZ) * transform); + cubeVertices->push_back(osg::Vec3(center.x() - halfLenghtX, center.y() - halfLenghtY, center.z() - halfLenghtZ) * transform); + cubeVertices->push_back(osg::Vec3(center.x() - halfLenghtX, center.y() - halfLenghtY, center.z() + halfLenghtZ) * transform); + + cubeVertices->push_back(osg::Vec3(center.x() + halfLenghtX, center.y() + halfLenghtY, center.z() + halfLenghtZ) * transform); + cubeVertices->push_back(osg::Vec3(center.x() + halfLenghtX, center.y() + halfLenghtY, center.z() - halfLenghtZ) * transform); + cubeVertices->push_back(osg::Vec3(center.x() + halfLenghtX, center.y() - halfLenghtY, center.z() - halfLenghtZ) * transform); + cubeVertices->push_back(osg::Vec3(center.x() + halfLenghtX, center.y() - halfLenghtY, center.z() + halfLenghtZ) * transform); + + cube->setVertexArray(cubeVertices); + + { + osg::DrawElementsUInt* up = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); + up->push_back(4); + up->push_back(5); + up->push_back(1); + up->push_back(0); + cube->addPrimitiveSet(up); + } + + { + osg::DrawElementsUInt* down = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); + down->push_back(2); + down->push_back(6); + down->push_back(7); + down->push_back(3); + cube->addPrimitiveSet(down); + } + + { + osg::DrawElementsUInt* left = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); + left->push_back(2); + left->push_back(3); + left->push_back(0); + left->push_back(1); + cube->addPrimitiveSet(left); + } + + { + osg::DrawElementsUInt* right = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); + right->push_back(7); + right->push_back(6); + right->push_back(5); + right->push_back(4); + cube->addPrimitiveSet(right); + } + + { + osg::DrawElementsUInt* front = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); + front->push_back(3); + front->push_back(7); + front->push_back(4); + front->push_back(0); + cube->addPrimitiveSet(front); + } + + { + osg::DrawElementsUInt* back = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); + back->push_back(6); + back->push_back(2); + back->push_back(1); + back->push_back(5); + cube->addPrimitiveSet(back); + } + + osg::Vec4Array* colors = new osg::Vec4Array; + colors->push_back(color); + colors->push_back(color); + colors->push_back(color); + colors->push_back(color); + colors->push_back(color); + colors->push_back(color); + colors->push_back(color); + colors->push_back(color); + + cube->setColorArray(colors); + cube->setColorBinding(osg::Geometry::BIND_PER_VERTEX); + + return cube; + } + + void serializeBoundingBox(const osg::BoundingBox &bb, const osg::Matrix &transform, osgAnimation::Bone &b, float ratio = 1.0) { + osg::Vec3 center = bb.center(); + double halfLenghtX = (bb._max.x() - bb._min.x()) * 0.50; + double halfLenghtY = (bb._max.y() - bb._min.y()) * 0.50; + double halfLenghtZ = (bb._max.z() - bb._min.z()) * 0.50; + + halfLenghtX *= ratio; + halfLenghtY *= ratio; + halfLenghtZ *= ratio; + + osg::BoundingBox serializedBB; + + serializedBB.expandBy(osg::Vec3(center.x() - halfLenghtX, center.y() + halfLenghtY, center.z() + halfLenghtZ) * transform); + serializedBB.expandBy(osg::Vec3(center.x() - halfLenghtX, center.y() + halfLenghtY, center.z() - halfLenghtZ) * transform); + serializedBB.expandBy(osg::Vec3(center.x() - halfLenghtX, center.y() - halfLenghtY, center.z() - halfLenghtZ) * transform); + serializedBB.expandBy(osg::Vec3(center.x() - halfLenghtX, center.y() - halfLenghtY, center.z() + halfLenghtZ) * transform); + serializedBB.expandBy(osg::Vec3(center.x() + halfLenghtX, center.y() + halfLenghtY, center.z() + halfLenghtZ) * transform); + serializedBB.expandBy(osg::Vec3(center.x() + halfLenghtX, center.y() + halfLenghtY, center.z() - halfLenghtZ) * transform); + serializedBB.expandBy(osg::Vec3(center.x() + halfLenghtX, center.y() - halfLenghtY, center.z() - halfLenghtZ) * transform); + serializedBB.expandBy(osg::Vec3(center.x() + halfLenghtX, center.y() - halfLenghtY, center.z() + halfLenghtZ) * transform); + + b.setUserValue("AABBonBone_min", serializedBB._min); + b.setUserValue("AABBonBone_max", serializedBB._max); + } + + void updateBones() { + osgUtil::UpdateVisitor update; + _root->accept(update); + } + + void updateRigGeometries() { + for (unsigned int i = 0, size = _rigGeometries.size(); i < size; i++) { + osgAnimation::RigGeometry * rig = _rigGeometries.at(i); + osg::Drawable::UpdateCallback * callback = dynamic_cast(rig->getUpdateCallback()); + if(callback) { + callback->update(0, rig); + } + } + } + + BoneList _bones; + RigGeometryList _rigGeometries; osgAnimation::Skeleton *_root; bool _createGeometry; }; diff --git a/src/osgPlugins/gles/AnimationCleanerVisitor b/src/osgPlugins/gles/AnimationCleanerVisitor index 38e217621..9d91e6a07 100644 --- a/src/osgPlugins/gles/AnimationCleanerVisitor +++ b/src/osgPlugins/gles/AnimationCleanerVisitor @@ -65,7 +65,7 @@ public: geometry(false) {} - void apply(osg::Geometry& object) { + void apply(osg::Geometry& /*object*/) { geometry = true; } @@ -266,18 +266,16 @@ public: // Replace rig geometries by static geometries if: // * empty or inexistant vertex influence map // * no *strictly* positive influence coefficient - - RigGeometryList::iterator rigGeometry = _rigGeometries.begin(); - while(rigGeometry != _rigGeometries.end()) { - if(rigGeometry->valid()) { - if(!hasPositiveWeights((*rigGeometry)->getSourceGeometry())) { - OSG_WARN << "Monitor: animation.invalid_riggeometry" << std::endl; - replaceRigGeometryBySource(*(rigGeometry->get())); - _rigGeometries.erase(rigGeometry); - continue; // skip iterator increment - } + for(RigGeometryList::iterator iterator = _rigGeometries.begin() ; iterator != _rigGeometries.end() ; ) { + osg::ref_ptr rigGeometry = *iterator; + if(rigGeometry.valid() && !hasPositiveWeights(rigGeometry->getSourceGeometry())) { + OSG_WARN << "Monitor: animation.invalid_riggeometry" << std::endl; + replaceRigGeometryBySource(*rigGeometry.get()); + _rigGeometries.erase(iterator); + } + else { + ++ iterator; } - ++ rigGeometry; } } diff --git a/src/osgPlugins/gles/GeometryArray b/src/osgPlugins/gles/GeometryArray index eaf97e227..0cc6d60a4 100644 --- a/src/osgPlugins/gles/GeometryArray +++ b/src/osgPlugins/gles/GeometryArray @@ -1,4 +1,5 @@ -/* -*-c++-*- */ +/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson */ + #ifndef GEOMETRY_ARRAY_UTILS_H #define GEOMETRY_ARRAY_UTILS_H @@ -98,7 +99,7 @@ struct GeometryArrayList { template bool arrayAppendElement(osg::Array* src, unsigned int index, osg::Array* dst) { T* array = dynamic_cast(src); - if (array) { + if (array && dst) { T* arrayDst = dynamic_cast(dst); arrayDst->push_back((*array)[index]); return true; @@ -140,15 +141,6 @@ struct GeometryArrayList { if (arrayAppendElement(src, index, dst)) return; - if (arrayAppendElement(src, index, dst)) - return; - - if (arrayAppendElement(src, index, dst)) - return; - - if (arrayAppendElement(src, index, dst)) - return; - if (arrayAppendElement(src, index, dst)) return; @@ -266,15 +258,6 @@ struct GeometryArrayList { if (arraySetNumElements(array, numElements)) return; - if (arraySetNumElements(array, numElements)) - return; - - if (arraySetNumElements(array, numElements)) - return; - - if (arraySetNumElements(array, numElements)) - return; - if (arraySetNumElements(array, numElements)) return; diff --git a/src/osgPlugins/gles/GeometryInspector b/src/osgPlugins/gles/GeometryInspector index 2e8f822c4..beea59194 100644 --- a/src/osgPlugins/gles/GeometryInspector +++ b/src/osgPlugins/gles/GeometryInspector @@ -1,3 +1,5 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */ + #ifndef GEOMETRY_INSPECTOR #define GEOMETRY_INSPECTOR @@ -17,7 +19,8 @@ class GeometryInspector : public GeometryUniqueVisitor { public: - void process(osg::Geometry& geometry) {} + void process(osg::Geometry& /*geometry*/) {} + void process(osgAnimation::RigGeometry& rigGeometry) { osgAnimation::MorphGeometry* morph = dynamic_cast(rigGeometry.getSourceGeometry()); if(morph) { diff --git a/src/osgPlugins/gles/GeometrySplitterVisitor b/src/osgPlugins/gles/GeometrySplitterVisitor index e238ec836..5de2118ca 100644 --- a/src/osgPlugins/gles/GeometrySplitterVisitor +++ b/src/osgPlugins/gles/GeometrySplitterVisitor @@ -133,7 +133,8 @@ public: setTriangleCluster(graph, cache.back(), cluster, clusters, cluster_vertices, remaining_triangles); while(remaining_triangles && cluster_vertices.size() < _maxAllowedIndex) { - unsigned int candidate; + unsigned int candidate = std::numeric_limits::max(); + for(IndexCache::const_reverse_iterator cached = cache.rbegin() ; cached != cache.rend() ; ++ cached) { candidate = findCandidate(graph.triangleNeighbors(*cached), clusters); if(candidate != std::numeric_limits::max()) break; diff --git a/src/osgPlugins/gles/LimitMorphTargetCount b/src/osgPlugins/gles/LimitMorphTargetCount index 6e0a10da4..38e25656a 100644 --- a/src/osgPlugins/gles/LimitMorphTargetCount +++ b/src/osgPlugins/gles/LimitMorphTargetCount @@ -1,8 +1,8 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */ + #ifndef LIMIT_MORPH_TARGET_COUNT_VISITOR #define LIMIT_MORPH_TARGET_COUNT_VISITOR -/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */ - #include "GeometryUniqueVisitor" diff --git a/src/osgPlugins/gles/Line b/src/osgPlugins/gles/Line index b27fd4b3a..9079f67a0 100644 --- a/src/osgPlugins/gles/Line +++ b/src/osgPlugins/gles/Line @@ -1,3 +1,5 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */ + #ifndef GLES_LINE #define GLES_LINE diff --git a/src/osgPlugins/gles/OpenGLESGeometryOptimizer b/src/osgPlugins/gles/OpenGLESGeometryOptimizer index 9eb36c74b..751a9f2bd 100644 --- a/src/osgPlugins/gles/OpenGLESGeometryOptimizer +++ b/src/osgPlugins/gles/OpenGLESGeometryOptimizer @@ -49,6 +49,7 @@ public: _disableMergeTriStrip(false), _disablePreTransform(false), _disableAnimation(false), + _disableAnimationCleaning(false), _enableAABBonBone(false), _triStripCacheSize(16), _triStripMinSize(2), diff --git a/src/osgPlugins/gles/PrimitiveIndexors b/src/osgPlugins/gles/PrimitiveIndexors index 7e83e6d6b..5791b0e02 100644 --- a/src/osgPlugins/gles/PrimitiveIndexors +++ b/src/osgPlugins/gles/PrimitiveIndexors @@ -1,3 +1,5 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */ + #ifndef PRIMITIVE_OPERATORS_H #define PRIMITIVE_OPERATORS_H diff --git a/src/osgPlugins/gles/RigAnimationVisitor b/src/osgPlugins/gles/RigAnimationVisitor index f069f5b43..3d1e1feb5 100644 --- a/src/osgPlugins/gles/RigAnimationVisitor +++ b/src/osgPlugins/gles/RigAnimationVisitor @@ -1,4 +1,4 @@ -/* -*-c++-*- OpenSceneGraph - Copyright (C) Cedric Pinson +/* -*-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 diff --git a/src/osgPlugins/gles/RigAttributesVisitor b/src/osgPlugins/gles/RigAttributesVisitor index 6674fb9d1..13cd47fe6 100644 --- a/src/osgPlugins/gles/RigAttributesVisitor +++ b/src/osgPlugins/gles/RigAttributesVisitor @@ -1,3 +1,5 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */ + #ifndef RIG_ATTRIBUTES_VISITOR #define RIG_ATTRIBUTES_VISITOR @@ -31,7 +33,7 @@ public: } } - void process(osg::Geometry& geometry) { + void process(osg::Geometry& /*geometry*/) { return; } diff --git a/src/osgPlugins/gles/SmoothNormalVisitor b/src/osgPlugins/gles/SmoothNormalVisitor index 2f72275a4..62ba9ae75 100644 --- a/src/osgPlugins/gles/SmoothNormalVisitor +++ b/src/osgPlugins/gles/SmoothNormalVisitor @@ -1,3 +1,5 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */ + #include #include #include @@ -197,7 +199,16 @@ protected: bool flipped = false; osg::Vec3Array* normals = dynamic_cast(_geometry.getNormalArray()); - for(unsigned int index = 0 ; index < _geometry.getVertexArray()->getNumElements() ; ++ index) { + osg::Vec3Array* positions = dynamic_cast(_geometry.getVertexArray()); + + if(!positions || !normals || normals->getNumElements() != positions->getNumElements()) { + OSG_WARN << std::endl + << "Warning: [smoothVertexNormals] [[normals]] Geometry '" << _geometry.getName() + << "' has invalid positions/normals"; + return; + } + + for(unsigned int index = 0 ; index < positions->getNumElements() ; ++ index) { std::vector oneRing = _graph->vertexOneRing(_graph->unify(index), _creaseAngle); osg::Vec3f smoothedNormal(0.f, 0.f, 0.f); diff --git a/src/osgPlugins/gles/StatLogger b/src/osgPlugins/gles/StatLogger index 047483157..a69f8006d 100644 --- a/src/osgPlugins/gles/StatLogger +++ b/src/osgPlugins/gles/StatLogger @@ -1,3 +1,5 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */ + #ifndef STAT_LOGGER #define STAT_LOGGER diff --git a/src/osgPlugins/gles/SubGeometry b/src/osgPlugins/gles/SubGeometry index b9c81a7f7..41b1d0129 100644 --- a/src/osgPlugins/gles/SubGeometry +++ b/src/osgPlugins/gles/SubGeometry @@ -1,3 +1,5 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */ + #ifndef SUB_GEOMETRY #define SUB_GEOMETRY @@ -49,11 +51,14 @@ public: if(const osgAnimation::MorphGeometry* morphSource = dynamic_cast(&source)) { osgAnimation::MorphGeometry* morph = dynamic_cast(_geometry.get()); const osgAnimation::MorphGeometry::MorphTargetList& morphTargetList = morphSource->getMorphTargetList(); - for(osgAnimation::MorphGeometry::MorphTargetList::const_iterator targetSource = morphTargetList.begin() ; - targetSource != morphTargetList.end() ; ++ targetSource) { - osg::Geometry* target = new osg::Geometry; - addSourceBuffers(target, *targetSource->getGeometry()); - morph->addMorphTarget(target, targetSource->getWeight()); + + osgAnimation::MorphGeometry::MorphTargetList::const_iterator targetSource; + for(targetSource = morphTargetList.begin() ; targetSource != morphTargetList.end() ; ++ targetSource) { + if(targetSource->getGeometry()) { + osg::Geometry* target = new osg::Geometry; + addSourceBuffers(target, *targetSource->getGeometry()); + morph->addMorphTarget(target, targetSource->getWeight()); + } } } diff --git a/src/osgPlugins/gles/TriangleMeshGraph b/src/osgPlugins/gles/TriangleMeshGraph index 052bce56c..1c48e3832 100644 --- a/src/osgPlugins/gles/TriangleMeshGraph +++ b/src/osgPlugins/gles/TriangleMeshGraph @@ -1,3 +1,5 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */ + #ifndef MESH_GRAPH #define MESH_GRAPH @@ -171,10 +173,12 @@ public: _positions(dynamic_cast(geometry.getVertexArray())), _comparePosition(comparePosition) { - unsigned int nbVertex = _positions->getNumElements(); - _unique.resize(nbVertex, std::numeric_limits::max()); - _vertexTriangles.resize(nbVertex, IndexVector()); - build(); + if(_positions) { + unsigned int nbVertex = _positions->getNumElements(); + _unique.resize(nbVertex, std::numeric_limits::max()); + _vertexTriangles.resize(nbVertex, IndexVector()); + build(); + } } VertexIterator begin() const { diff --git a/src/osgPlugins/gles/glesUtil b/src/osgPlugins/gles/glesUtil index 1e3b0b388..f9db652bd 100644 --- a/src/osgPlugins/gles/glesUtil +++ b/src/osgPlugins/gles/glesUtil @@ -1,3 +1,5 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */ + #ifndef GLES_UTIL #define GLES_UTIL From 67b17fa8018f58c169d465c0a9781c1c180c046b Mon Sep 17 00:00:00 2001 From: Marc Helbling Date: Tue, 5 Jul 2016 16:37:12 +0200 Subject: [PATCH 2/3] Updates osgjs plugin for animation serialization --- src/osgPlugins/osgjs/Adaptor | 117 +++++++ src/osgPlugins/osgjs/Animation | 26 +- src/osgPlugins/osgjs/Animation.cpp | 286 +++++++++++++---- src/osgPlugins/osgjs/CMakeLists.txt | 4 +- src/osgPlugins/osgjs/CompactBufferVisitor | 24 +- src/osgPlugins/osgjs/JSON_Objects | 148 ++++----- src/osgPlugins/osgjs/JSON_Objects.cpp | 109 ++----- src/osgPlugins/osgjs/ReaderWriterJSON.cpp | 11 +- src/osgPlugins/osgjs/WriteVisitor | 369 ++++++++++++++++++---- src/osgPlugins/osgjs/WriteVisitor.cpp | 368 +++++++++++++++------ src/osgPlugins/osgjs/json_stream | 177 +---------- src/osgPlugins/osgjs/utf8_string | 187 +++++++++++ 12 files changed, 1264 insertions(+), 562 deletions(-) create mode 100644 src/osgPlugins/osgjs/Adaptor create mode 100644 src/osgPlugins/osgjs/utf8_string diff --git a/src/osgPlugins/osgjs/Adaptor b/src/osgPlugins/osgjs/Adaptor new file mode 100644 index 000000000..1837175b9 --- /dev/null +++ b/src/osgPlugins/osgjs/Adaptor @@ -0,0 +1,117 @@ +/* -*-c++-*- + * Copyright (C) 2010 Cedric Pinson + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library 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. See the + * OpenSceneGraph Public License for more details. + * + * Authors: + * Cedric Pinson + */ + +#include + + +struct DrawArrayLenghtAdaptor +{ + unsigned int _normalArraySize; + const Vec3* _normalArrayPtr; + + unsigned int _colorArraySize; + const Vec4* _colorArrayPtr; + + std::vector > _uvs; + + virtual void setNormalArray(unsigned int count,const Vec3* vertices) { + _normalArraySize = count; + _normalArrayPtr = vertices; + } + + virtual void setNormalArray(unsigned int count,const Vec4* colors) { + _colorArraySize = count; + _colorArrayPtr = colors; + } + + virtual void setTexCoordArray(int unit, unsigned int count,const Vec2* uvs) { + if (_uvs.size() <= unit) + _uvs.resize(unit+1); + _uvs[i].first = count; + _uvs[i].second = uvs; + } +}; + + +struct AdaptDraw : public osg::TriangleFunctor +{ + + virtual void drawArrays(GLenum mode,GLint first,GLsizei count) + { + if (_vertexArrayPtr==0 || count==0) return; + + switch(mode) + { + case(GL_TRIANGLES): + { + unsigned int last = first+count; + for(unsigned int current = first; currentoperator()(current, current+1, current+2,_treatVertexDataAsTemporary); + + } + break; + } + case(GL_TRIANGLE_STRIP): + { + unsigned int current = first; + for(GLsizei i=2;ioperator()(current, current+2, current+1,_treatVertexDataAsTemporary); + else this->operator()(current, current+1, current+2,_treatVertexDataAsTemporary); + } + break; + } + case(GL_QUADS): + { + unsigned int current = first; + for(GLsizei i=3;ioperator()(current, current+1, current+2,_treatVertexDataAsTemporary); + this->operator()(current, current+2, current+3,_treatVertexDataAsTemporary); + } + break; + } + case(GL_QUAD_STRIP): + { + unsigned int current = first; + for(GLsizei i=3;ioperator()(current, current+1, current+2,_treatVertexDataAsTemporary); + this->operator()(current+1, current+3, current+2,_treatVertexDataAsTemporary); + } + break; + } + case(GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN + case(GL_TRIANGLE_FAN): + { + unsigned int current = first + 1; + for(GLsizei i=2;ioperator()(first),current, current+1,_treatVertexDataAsTemporary); + } + break; + } + case(GL_POINTS): + case(GL_LINES): + case(GL_LINE_STRIP): + case(GL_LINE_LOOP): + default: + // can't be converted into to triangles. + break; + } + } +}; diff --git a/src/osgPlugins/osgjs/Animation b/src/osgPlugins/osgjs/Animation index 43bfedcb5..92a1e2891 100644 --- a/src/osgPlugins/osgjs/Animation +++ b/src/osgPlugins/osgjs/Animation @@ -6,7 +6,29 @@ #include #include -JSONObject* createJSONAnimation(osgAnimation::Animation* anim); -JSONObject* createJSONUpdateMatrixTransform(osgAnimation::UpdateMatrixTransform& acb); +struct WriteVisitor; + +JSONObject* createJSONAnimation(osgAnimation::Animation* anim, WriteVisitor* writer); +JSONObject* createJSONUpdateMatrixTransform(osgAnimation::UpdateMatrixTransform& acb, WriteVisitor* writer); + + +// Remaps: [(u0, v0,..., w0), (u1, v1, ... w1), ..., (un, vn, ..., wn)] +// into: [(u0, u1, ...), ..., (v0, v1, ...), ..., (w0, w1, ...), ...] +template +Out* pack(const In* array) { + unsigned int inSize = array->getNumElements(); + unsigned int inDim = In::ElementDataType::num_components; + unsigned int outDim = Out::ElementDataType::num_components; + + Out* interleaved = new Out(static_cast(.5 + (inSize * inDim) * 1. / outDim)); + + for(unsigned int i = 0 ; i < inSize ; ++ i) { + for(unsigned int j = 0 ; j < inDim ; ++ j) { + unsigned int index = j * inSize + i; + (*interleaved)[index / outDim][index % outDim] = (*array)[i][j]; + } + } + return interleaved; +} #endif diff --git a/src/osgPlugins/osgjs/Animation.cpp b/src/osgPlugins/osgjs/Animation.cpp index f6e50a570..c9bd1382f 100644 --- a/src/osgPlugins/osgjs/Animation.cpp +++ b/src/osgPlugins/osgjs/Animation.cpp @@ -1,66 +1,109 @@ -/* -*-c++-*- +/* -*-c++-*- * Copyright (C) 2011 Cedric Pinson */ #include #include +#include #include #include #include #include #include +#include +#include +#include #include "JSON_Objects" +#include "WriteVisitor" -static bool addJSONChannelVec3(osgAnimation::Vec3LinearChannel* channel, JSONObject& anim) -{ + +template +struct osg_array +{ typedef osg::Array array_type; }; + +#define ADD_ARRAY_TYPE(T, A)\ +template<> \ +struct osg_array \ +{ typedef A array_type; } + +ADD_ARRAY_TYPE(osg::Vec3f, osg::Vec3Array); +ADD_ARRAY_TYPE(osg::Quat, osg::QuatArray); +ADD_ARRAY_TYPE(osg::Vec3i, osg::Vec3iArray); +ADD_ARRAY_TYPE(osg::Vec4i, osg::Vec4iArray); +ADD_ARRAY_TYPE(osg::Vec3ui, osg::Vec3uiArray); +ADD_ARRAY_TYPE(osg::Vec3us, osg::Vec3usArray); +ADD_ARRAY_TYPE(float, osg::FloatArray); +ADD_ARRAY_TYPE(double, osg::FloatArray); +ADD_ARRAY_TYPE(int, osg::IntArray); +ADD_ARRAY_TYPE(unsigned int, osg::UIntArray); +ADD_ARRAY_TYPE(unsigned short, osg::UShortArray); + + +template +bool addJSONChannel(const std::string& channelType, T* channel, bool packByCoords, JSONObject& anim, WriteVisitor* writer, osg::Object* parent) { if (channel && channel->getSampler()) { osg::ref_ptr json = new JSONObject; + std::string jsonType = channelType + (packByCoords ? "Packed" : ""); + + translateObject(json.get(), channel); + json->getMaps()["Name"] = new JSONValue(channel->getName()); json->getMaps()["TargetName"] = new JSONValue(channel->getTargetName()); - osgAnimation::Vec3KeyframeContainer* keys = channel->getSamplerTyped()->getKeyframeContainerTyped(); - JSONKeyframes* jsonKeys = new JSONKeyframes(); - //if (!keys->getName().empty()) { - // jsonKeys->getMaps()["Name"] = new JSONValue(keys->getName()); - //} + + typename T::KeyframeContainerType* keys = channel->getSamplerTyped()->getKeyframeContainerTyped(); + typedef typename T::UsingType KeyframeType; + typedef typename osg_array::array_type KeyframeArray; + + osg::ref_ptr jsKeys = new JSONObject; + osg::ref_ptr timesArray = new osg::FloatArray; + osg::ref_ptr valuesArray = new KeyframeArray; for (unsigned int i = 0; i < keys->size(); i++) { - JSONVec4Array* kf = new JSONVec4Array(osg::Vec4((*keys)[i].getTime(), - (*keys)[i].getValue()[0], - (*keys)[i].getValue()[1], - (*keys)[i].getValue()[2])); - jsonKeys->getArray().push_back(kf); + timesArray->push_back((*keys)[i].getTime()); + valuesArray->push_back((*keys)[i].getValue()); } - json->getMaps()["KeyFrames"] = jsonKeys; - + + jsKeys->getMaps()["Time"] = writer->createJSONBufferArray(timesArray.get(), parent); + + osg::ref_ptr values; + if(packByCoords) { // data channel packing + values = pack(valuesArray.get()); + } + else { + values = valuesArray; + } + + jsKeys->getMaps()["Key"] = writer->createJSONBufferArray(values.get(), parent); + json->getMaps()["KeyFrames"] = jsKeys; + osg::ref_ptr jsonChannel = new JSONObject(); - jsonChannel->getMaps()["osgAnimation.Vec3LerpChannel"] = json; + jsonChannel->getMaps()[jsonType] = json; anim.getMaps()["Channels"]->asArray()->getArray().push_back(jsonChannel); return true; } return false; } - - -static bool addJSONChannelFloat(osgAnimation::FloatLinearChannel* channel, JSONObject& anim) +static bool addJSONChannelFloat(osgAnimation::FloatLinearChannel* channel, JSONObject& anim, WriteVisitor* writer, osg::Object* parent=0) { if (channel->getSampler()) { osg::ref_ptr json = new JSONObject; json->getMaps()["Name"] = new JSONValue(channel->getName()); json->getMaps()["TargetName"] = new JSONValue(channel->getTargetName()); osgAnimation::FloatKeyframeContainer* keys = channel->getSamplerTyped()->getKeyframeContainerTyped(); - JSONKeyframes* jsonKeys = new JSONKeyframes(); - //if (!keys->getName().empty()) { - // jsonKeys->getMaps()["Name"] = new JSONValue(keys->getName()); - //} + osg::ref_ptr jsKeys = new JSONObject; + osg::ref_ptr timesArray = new osg::FloatArray; + osg::ref_ptr keysArray = new osg::FloatArray; for (unsigned int i = 0; i < keys->size(); i++) { - JSONVec2Array* kf = new JSONVec2Array(osg::Vec2((*keys)[i].getTime(), - (*keys)[i].getValue())); - jsonKeys->getArray().push_back(kf); + timesArray->push_back((*keys)[i].getTime()); + keysArray->push_back((*keys)[i].getValue()); } - json->getMaps()["KeyFrames"] = jsonKeys; - + + jsKeys->getMaps()["Time"] = writer->createJSONBufferArray(timesArray.get(), parent); + jsKeys->getMaps()["Key"] = writer->createJSONBufferArray(keysArray.get(), parent); + json->getMaps()["KeyFrames"] = jsKeys; + osg::ref_ptr jsonChannel = new JSONObject(); jsonChannel->getMaps()["osgAnimation.FloatLerpChannel"] = json; anim.getMaps()["Channels"]->asArray()->getArray().push_back(jsonChannel); @@ -69,48 +112,130 @@ static bool addJSONChannelFloat(osgAnimation::FloatLinearChannel* channel, JSONO return false; } - -static bool addJSONChannelQuaternion(osgAnimation::QuatSphericalLinearChannel* channel, JSONObject& anim) +static bool addJSONChannelFloatCubicBezier(osgAnimation::FloatCubicBezierChannel* channel, JSONObject& anim, WriteVisitor* writer, osg::Object* parent=0) { - if (channel->getSampler()) { + if(channel->getSampler()) { osg::ref_ptr json = new JSONObject; json->getMaps()["Name"] = new JSONValue(channel->getName()); json->getMaps()["TargetName"] = new JSONValue(channel->getTargetName()); - osgAnimation::QuatKeyframeContainer* keys = channel->getSamplerTyped()->getKeyframeContainerTyped(); - JSONKeyframes* jsonKeys = new JSONKeyframes(); + + osgAnimation::FloatCubicBezierKeyframeContainer * keys = channel->getSamplerTyped()->getKeyframeContainerTyped(); + osg::ref_ptr timeArray = new osg::FloatArray, + positionArray = new osg::FloatArray, + controlPointInArray = new osg::FloatArray, + controlPointOutArray = new osg::FloatArray; for (unsigned int i = 0; i < keys->size(); i++) { - JSONVec5Array* kf = new JSONVec5Array(Vec5((*keys)[i].getTime(), - (*keys)[i].getValue()[0], - (*keys)[i].getValue()[1], - (*keys)[i].getValue()[2], - (*keys)[i].getValue()[3])); - jsonKeys->getArray().push_back(kf); + timeArray->push_back((*keys)[i].getTime()); + positionArray->push_back((*keys)[i].getValue().getPosition()); + controlPointInArray->push_back((*keys)[i].getValue().getControlPointIn()); + controlPointOutArray->push_back((*keys)[i].getValue().getControlPointOut()); } - json->getMaps()["KeyFrames"] = jsonKeys; - + osg::ref_ptr jsKeys = new JSONObject; + + jsKeys->getMaps()["ControlPointOut"] = writer->createJSONBufferArray(controlPointOutArray.get(), parent); + + jsKeys->getMaps()["ControlPointIn"] = writer->createJSONBufferArray(controlPointInArray.get(), parent); + + jsKeys->getMaps()["Position"] = writer->createJSONBufferArray(positionArray.get(), parent); + + jsKeys->getMaps()["Time"] = writer->createJSONBufferArray(timeArray.get(), parent); + + json->getMaps()["KeyFrames"] = jsKeys; + osg::ref_ptr jsonChannel = new JSONObject(); - jsonChannel->getMaps()["osgAnimation.QuatSlerpChannel"] = json; + jsonChannel->getMaps()["osgAnimation.FloatCubicBezierChannel"] = json; anim.getMaps()["Channels"]->asArray()->getArray().push_back(jsonChannel); return true; } return false; } -static void addJSONChannel(osgAnimation::Channel* channel, JSONObject& anim) +static bool addJSONChannelVec3CubicBezier(osgAnimation::Vec3CubicBezierChannel* channel, JSONObject& anim, WriteVisitor* writer, osg::Object* parent=0) +{ + if(channel->getSampler()) { + osg::ref_ptr json = new JSONObject; + json->getMaps()["Name"] = new JSONValue(channel->getName()); + json->getMaps()["TargetName"] = new JSONValue(channel->getTargetName()); + + osgAnimation::Vec3CubicBezierKeyframeContainer * keys = channel->getSamplerTyped()->getKeyframeContainerTyped(); + osg::ref_ptr timeArray = new osg::FloatArray, + positionArrayX = new osg::FloatArray, + positionArrayY = new osg::FloatArray, + positionArrayZ = new osg::FloatArray, + + controlPointInArrayX = new osg::FloatArray, + controlPointInArrayY = new osg::FloatArray, + controlPointInArrayZ = new osg::FloatArray, + + controlPointOutArrayX = new osg::FloatArray, + controlPointOutArrayY = new osg::FloatArray, + controlPointOutArrayZ = new osg::FloatArray; + + for (unsigned int i = 0; i < keys->size(); i++) { + timeArray->push_back((*keys)[i].getTime()); + + positionArrayX->push_back((*keys)[i].getValue().getPosition().x()); + positionArrayY->push_back((*keys)[i].getValue().getPosition().y()); + positionArrayZ->push_back((*keys)[i].getValue().getPosition().z()); + + controlPointInArrayX->push_back((*keys)[i].getValue().getControlPointIn().x()); + controlPointInArrayY->push_back((*keys)[i].getValue().getControlPointIn().y()); + controlPointInArrayZ->push_back((*keys)[i].getValue().getControlPointIn().z()); + + controlPointOutArrayX->push_back((*keys)[i].getValue().getControlPointOut().x()); + controlPointOutArrayY->push_back((*keys)[i].getValue().getControlPointOut().y()); + controlPointOutArrayZ->push_back((*keys)[i].getValue().getControlPointOut().z()); + } + osg::ref_ptr jsKeys = new JSONObject; + + osg::ref_ptr jsControlPointOutArray = new JSONArray; + jsControlPointOutArray->asArray()->getArray().push_back(writer->createJSONBufferArray(controlPointOutArrayX.get(), parent)); + jsControlPointOutArray->asArray()->getArray().push_back(writer->createJSONBufferArray(controlPointOutArrayY.get(), parent)); + jsControlPointOutArray->asArray()->getArray().push_back(writer->createJSONBufferArray(controlPointOutArrayZ.get(), parent)); + jsKeys->getMaps()["ControlPointOut"] = jsControlPointOutArray; + + osg::ref_ptr jsControlPointInArray = new JSONArray; + jsControlPointInArray->asArray()->getArray().push_back(writer->createJSONBufferArray(controlPointInArrayX.get(), parent)); + jsControlPointInArray->asArray()->getArray().push_back(writer->createJSONBufferArray(controlPointInArrayY.get(), parent)); + jsControlPointInArray->asArray()->getArray().push_back(writer->createJSONBufferArray(controlPointInArrayZ.get(), parent)); + jsKeys->getMaps()["ControlPointIn"] = jsControlPointInArray; + + osg::ref_ptr jsPositionVertexArray = new JSONArray; + jsPositionVertexArray->asArray()->getArray().push_back(writer->createJSONBufferArray(positionArrayX.get(), parent)); + jsPositionVertexArray->asArray()->getArray().push_back(writer->createJSONBufferArray(positionArrayY.get(), parent)); + jsPositionVertexArray->asArray()->getArray().push_back(writer->createJSONBufferArray(positionArrayZ.get(), parent)); + jsKeys->getMaps()["Position"] = jsPositionVertexArray; + + jsKeys->getMaps()["Time"] = writer->createJSONBufferArray(timeArray.get(), parent); + + json->getMaps()["KeyFrames"] = jsKeys; + + osg::ref_ptr jsonChannel = new JSONObject(); + jsonChannel->getMaps()["osgAnimation.Vec3CubicBezierChannel"] = json; + anim.getMaps()["Channels"]->asArray()->getArray().push_back(jsonChannel); + return true; + } + return false; +} + + + + +static void addJSONChannel(osgAnimation::Channel* channel, JSONObject& anim, WriteVisitor* writer, osg::Object* parent=0) { { - osgAnimation::Vec3LinearChannel* c = dynamic_cast(channel); + osgAnimation::FloatLinearChannel* c = dynamic_cast(channel); if (c) { - if (addJSONChannelVec3(c, anim)) + if (addJSONChannelFloat(c, anim, writer, parent)) return; } } { - osgAnimation::FloatLinearChannel* c = dynamic_cast(channel); + osgAnimation::Vec3LinearChannel* c = dynamic_cast(channel); if (c) { - if (addJSONChannelFloat(c, anim)) + if (addJSONChannel("osgAnimation.Vec3LerpChannel", c, false, anim, writer, parent)) return; } } @@ -118,33 +243,47 @@ static void addJSONChannel(osgAnimation::Channel* channel, JSONObject& anim) { osgAnimation::QuatSphericalLinearChannel* c = dynamic_cast(channel); if (c) { - if (addJSONChannelQuaternion(c, anim)) + if (addJSONChannel("osgAnimation.QuatSlerpChannel", c, false, anim, writer, parent)) + return; + } + } + + { + osgAnimation::FloatCubicBezierChannel* c = dynamic_cast(channel); + if (c) { + if (addJSONChannelFloatCubicBezier(c, anim, writer, parent)) + return; + } + } + + { + osgAnimation::Vec3CubicBezierChannel *c = dynamic_cast(channel); + if (c) { + if (addJSONChannelVec3CubicBezier(c, anim, writer, parent)) return; } } - } -JSONObject* createJSONAnimation(osgAnimation::Animation* anim) +JSONObject* createJSONAnimation(osgAnimation::Animation* anim, WriteVisitor* writer) { osg::ref_ptr json = new JSONObject; + json->addUniqueID(); json->getMaps()["Channels"] = new JSONArray(); json->getMaps()["Name"] = new JSONValue(anim->getName()); for (unsigned int i = 0; i < anim->getChannels().size(); i++) { - addJSONChannel(anim->getChannels()[i].get(), *json); + addJSONChannel(anim->getChannels()[i].get(), *json, writer, anim); } return json.release(); } - - -JSONObject* createJSONUpdateMatrixTransform(osgAnimation::UpdateMatrixTransform& acb) +JSONObject* createJSONUpdateMatrixTransform(osgAnimation::UpdateMatrixTransform& acb, WriteVisitor* writer) { - std::string name = acb.getName(); osg::ref_ptr json = new JSONObject; + json->addUniqueID(); json->getMaps()["Name"] = new JSONValue(acb.getName()); - + osg::ref_ptr jsonStackedArray = new JSONArray(); json->getMaps()["StackedTransforms"] = jsonStackedArray; @@ -194,8 +333,41 @@ JSONObject* createJSONUpdateMatrixTransform(osgAnimation::UpdateMatrixTransform& continue; } } + + + { + osgAnimation::StackedMatrixElement * element = dynamic_cast(st[i].get()); + if (element) { + osg::ref_ptr jsonElement = new JSONObject; + jsonElement->getMaps()["Name"] = new JSONValue(element->getName()); + jsonElement->getMaps()["Matrix"] = new JSONMatrix(element->getMatrix()); + + osg::ref_ptr jsonElementObject = new JSONObject; + jsonElementObject->getMaps()["osgAnimation.StackedMatrix"] = jsonElement; + jsonStackedArray->getArray().push_back(jsonElementObject); + continue; + } + } + + { + osgAnimation::StackedScaleElement * element = dynamic_cast(st[i].get()); + if (element) { + osg::ref_ptr jsonElement = new JSONObject; + jsonElement->getMaps()["Name"] = new JSONValue(element->getName()); + jsonElement->getMaps()["Scale"] = new JSONVec3Array(element->getScale()); + + osg::ref_ptr jsonElementObject = new JSONObject; + jsonElementObject->getMaps()["osgAnimation.StackedScale"] = jsonElement; + jsonStackedArray->getArray().push_back(jsonElementObject); + continue; + } + } } - if (jsonStackedArray->getArray().empty()) { + + // In the case of a Bone, we serialize the UpdateBone element even if there are no stackedTransforms. The reason is + // that for now, we use UpdateBone to compute the transforms from bone's parents, and for a bone without UpdateBone we + // get a bad transform and the related geometries are messed up + if (jsonStackedArray->getArray().empty() && !dynamic_cast(&acb)) { return 0; } diff --git a/src/osgPlugins/osgjs/CMakeLists.txt b/src/osgPlugins/osgjs/CMakeLists.txt index 13486695f..615ed46bf 100644 --- a/src/osgPlugins/osgjs/CMakeLists.txt +++ b/src/osgPlugins/osgjs/CMakeLists.txt @@ -6,15 +6,17 @@ SET(TARGET_SRC WriteVisitor.cpp) SET(TARGET_H - Adaptator + Adaptor Animation Base64 CompactBufferVisitor JSON_Objects json_stream + utf8_string WriteVisitor ) + #### end var setup ### SET(TARGET_ADDED_LIBRARIES osgAnimation diff --git a/src/osgPlugins/osgjs/CompactBufferVisitor b/src/osgPlugins/osgjs/CompactBufferVisitor index 74145053b..f4ad92d90 100644 --- a/src/osgPlugins/osgjs/CompactBufferVisitor +++ b/src/osgPlugins/osgjs/CompactBufferVisitor @@ -22,6 +22,8 @@ #include #include +#include + #include @@ -31,23 +33,17 @@ class CompactBufferVisitor : public osg::NodeVisitor { osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} - void apply(osg::Geode& geode){ - for (unsigned int i = 0; i < geode.getNumDrawables(); i++) { - apply(*geode.getDrawable(i)); - } - } - - void apply(osg::Drawable& drawable){ - osg::Geometry* geometry = drawable.asGeometry(); - if (!geometry || isProcessed(geometry)) { - return; - } - apply(*geometry); - } - void apply(osg::Geometry& geometry) { + if(isProcessed(&geometry)) + return; + compactPrimitiveSets(geometry); setProcessed(&geometry); + + osgAnimation::RigGeometry *rig = dynamic_cast(&geometry); + if(rig && rig->getSourceGeometry()) { + apply(*rig->getSourceGeometry()); + } } diff --git a/src/osgPlugins/osgjs/JSON_Objects b/src/osgPlugins/osgjs/JSON_Objects index b75f8a640..66cd8d5cc 100644 --- a/src/osgPlugins/osgjs/JSON_Objects +++ b/src/osgPlugins/osgjs/JSON_Objects @@ -21,21 +21,6 @@ class WriteVisitor; -struct Vec5 -{ - float _v[5]; - Vec5() {} - Vec5(float a0, float a1, float a2, float a3, float a4) { - _v[0] = a0; - _v[1] = a1; - _v[2] = a2; - _v[3] = a3; - _v[4] = a4; - }; - inline float& operator [] (int i) { return _v[i]; } - inline float operator [] (int i) const { return _v[i]; } -}; - struct JSONObjectBase : public osg::Referenced { static int level; @@ -50,8 +35,23 @@ struct JSONObject : public JSONObjectBase { typedef std::map > JSONMap; typedef std::vector OrderList; + + static unsigned int uniqueID; + std::string _bufferName; JSONMap _maps; + + JSONObject() {} + JSONObject(const unsigned int id, const std::string& bufferName = ""); + + void addUniqueID(); + unsigned int getUniqueID() const; + JSONObject* getShadowObject() { return new JSONObject(getUniqueID(), _bufferName); } + + virtual void setBufferName(const std::string& name) { _bufferName = name; } + std::string getBufferName() { return _bufferName; } + JSONMap& getMaps() { return _maps; } + void writeOrder(json_stream& str, const OrderList& order, WriteVisitor& visitor); virtual void write(json_stream& str, WriteVisitor& visitor); void addChild(const std::string& type, JSONObject* child); @@ -60,18 +60,6 @@ struct JSONObject : public JSONObjectBase return dynamic_cast * > ( this); } - JSONObject(const unsigned int id, const std::string& bufferName = ""); - JSONObject(); - void addUniqueID(); - unsigned int getUniqueID() const { return _uniqueID; } - JSONObject* getShadowObject() { return new JSONObject(_uniqueID, _bufferName); } - - unsigned int _uniqueID; - static unsigned int uniqueID; - - std::string _bufferName; - virtual void setBufferName(const std::string& name) { _bufferName = name; } - std::string getBufferName() { return _bufferName; } bool isVarintableIntegerBuffer(osg::Array const*) const; void encodeArrayAsVarintBuffer(osg::Array const*, std::vector&) const; template @@ -88,15 +76,16 @@ struct JSONObject : public JSONObjectBase JSONObject* createLight(osg::Light* light); -struct JSONNode : public JSONObject +struct JSONObjectWithUniqueID : public JSONObject { - void write(json_stream& str, WriteVisitor& visitor); + JSONObjectWithUniqueID() + { addUniqueID(); } }; -typedef JSONObject JSONStateSet; -typedef JSONObject JSONMaterial; -typedef JSONObject JSONLight; - +typedef JSONObjectWithUniqueID JSONNode; +typedef JSONObjectWithUniqueID JSONStateSet; +typedef JSONObjectWithUniqueID JSONMaterial; +typedef JSONObjectWithUniqueID JSONLight; struct JSONArray : public JSONObject { @@ -108,11 +97,6 @@ struct JSONArray : public JSONObject JSONArray* asArray() { return this; } }; -struct JSONKeyframes : public JSONArray -{ - virtual void write(json_stream& str, WriteVisitor& visitor); -}; - struct JSONVec3Array : public JSONArray { @@ -126,11 +110,6 @@ struct JSONVec4Array : public JSONVec3Array JSONVec4Array(const osg::Vec4&); }; -struct JSONVec5Array : public JSONVec3Array -{ - JSONVec5Array(const Vec5&); -}; - struct JSONVec2Array : public JSONVec3Array { JSONVec2Array(const osg::Vec2&); @@ -140,30 +119,20 @@ template struct JSONValue : public JSONObject { T _value; + JSONValue(const T& v) { _value = v; } + T& getValue() { return _value; } + T getValue() const { return _value; } + virtual void write(json_stream& str, WriteVisitor& /*visitor*/) { str << _value ; } }; -template <> -struct JSONValue : public JSONObject -{ - double _value; - JSONValue(const double& v) { - _value = v; - } - void write(json_stream& str, WriteVisitor& /*visitor*/) { - if (osg::isNaN(_value)) { - _value = 0.0; - } - str << _value; - } -}; template <> struct JSONValue : public JSONObject @@ -171,35 +140,30 @@ struct JSONValue : public JSONObject std::string _value; JSONValue(const std::string& v) { - _value = jsonEscape(v); + _value = escape(v); } void write(json_stream& str, WriteVisitor& /*visitor*/) { str << '"' << _value << '"'; } - protected: - std::string jsonEscape(const std::string& input) { - std::string value = input; - replace(value, std::string("\\"), std::string("\\\\")); - replace(value, std::string("\""), std::string("\\\"")); - replace(value, std::string("\b"), std::string("\\b")); - replace(value, std::string("\f"), std::string("\\f")); - replace(value, std::string("\n"), std::string("\\n")); - replace(value, std::string("\r"), std::string("\\r")); - replace(value, std::string("\t"), std::string("\\t")); - return value; - } +protected: + std::string escape(const std::string& input) { + std::string value = input; + replace(value, std::string("\\"), std::string("\\\\")); + replace(value, std::string("\""), std::string("\\\"")); + return value; + } - void replace(std::string& str, const std::string& from, const std::string& to) { - if(from.empty()) - return; - size_t start_pos = 0; - while((start_pos = str.find(from, start_pos)) != std::string::npos) { - str.replace(start_pos, from.length(), to); - start_pos += to.length(); - } + void replace(std::string& str, const std::string& from, const std::string& to) { + if(from.empty()) + return; + size_t start_pos = 0; + while((start_pos = str.find(from, start_pos)) != std::string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); } + } }; @@ -273,9 +237,8 @@ struct JSONVertexArray : public JSONArray } }; -struct JSONBufferArray : public JSONObject +struct JSONBufferArray : public JSONObjectWithUniqueID { - JSONBufferArray() {} JSONBufferArray(const osg::Array* array) { JSONVertexArray* b = new JSONVertexArray(array); @@ -293,14 +256,29 @@ struct JSONBufferArray : public JSONObject JSONObject* getDrawMode(GLenum mode); -struct JSONDrawArray : public JSONObject +struct JSONDrawArray : public JSONObjectWithUniqueID { - JSONDrawArray(osg::DrawArrays& array); + JSONDrawArray(osg::DrawArrays& array) + { + getMaps()["First"] = new JSONValue(array.getFirst()); + getMaps()["Count"] = new JSONValue(array.getCount()); + getMaps()["Mode"] = getDrawMode(array.getMode()); + } }; -struct JSONDrawArrayLengths : public JSONObject +struct JSONDrawArrayLengths : public JSONObjectWithUniqueID { - JSONDrawArrayLengths(osg::DrawArrayLengths& array); + JSONDrawArrayLengths(osg::DrawArrayLengths& array) + { + getMaps()["First"] = new JSONValue(array.getFirst()); + getMaps()["Mode"] = getDrawMode(array.getMode()); + + JSONArray* jsonArray = new JSONArray; + for (unsigned int i = 0; i < array.size(); i++) { + jsonArray->getArray().push_back(new JSONValue(array[i])); + } + getMaps()["ArrayLengths"] = jsonArray; + } void setBufferName(const std::string& bufferName) { JSONObject::setBufferName(bufferName); @@ -323,7 +301,7 @@ ADD_INDEX_BUFFER(osg::DrawElementsUByte, osg::UByteArray); template -struct JSONDrawElements : public JSONObject +struct JSONDrawElements : public JSONObjectWithUniqueID { JSONDrawElements(T& array) { typedef typename BufferArray::type array_type; diff --git a/src/osgPlugins/osgjs/JSON_Objects.cpp b/src/osgPlugins/osgjs/JSON_Objects.cpp index f71641f2f..2fe381438 100644 --- a/src/osgPlugins/osgjs/JSON_Objects.cpp +++ b/src/osgPlugins/osgjs/JSON_Objects.cpp @@ -19,6 +19,7 @@ int JSONObjectBase::level = 0; unsigned int JSONObject::uniqueID = 0; + std::string JSONObjectBase::indent() { std::string str; @@ -41,34 +42,27 @@ void JSONMatrix::write(json_stream& str, WriteVisitor& visitor) } -void JSONNode::write(json_stream& str, WriteVisitor& visitor) -{ - std::vector order; - order.push_back("UniqueID"); - order.push_back("Name"); - order.push_back("TargetName"); - order.push_back("Matrix"); - order.push_back("UpdateCallbacks"); - order.push_back("StateSet"); - writeOrder(str, order, visitor); -} - JSONObject::JSONObject(const unsigned int id, const std::string& bufferName) { - _uniqueID = id; _bufferName = bufferName; _maps["UniqueID"] = new JSONValue(id); } -JSONObject::JSONObject() -{ - _uniqueID = 0xffffffff; -} - void JSONObject::addUniqueID() { - _uniqueID = JSONObject::uniqueID++; - _maps["UniqueID"] = new JSONValue(_uniqueID); + if(_maps.find("UniqueID") == _maps.end()) { + _maps["UniqueID"] = new JSONValue(JSONObject::uniqueID ++); + } +} + +unsigned int JSONObject::getUniqueID() const +{ + JSONMap::const_iterator iterator = _maps.find("UniqueID"); + if(iterator == _maps.end()) { + return 0xffffffff; + } + const JSONValue* uid = dynamic_cast*>(iterator->second.get()); + return uid->getValue(); } void JSONObject::addChild(const std::string& type, JSONObject* child) @@ -267,16 +261,15 @@ static void writeEntry(json_stream& str, const std::string& key, JSONObject::JSO if (key.empty()) return; - if ( map.find(key) != map.end() && - map[ key ].valid() ) { + JSONObject::JSONMap::iterator keyValue = map.find(key); + if ( keyValue != map.end() && keyValue->second.valid() ) { str << JSONObjectBase::indent() << '"' << key << '"' << ": "; - map[ key ]->write(str, visitor); - map.erase(key); + keyValue->second->write(str, visitor); + map.erase(keyValue); if (!map.empty()) { - str << ", "; - str << "\n"; + str << ",\n"; } } } @@ -359,7 +352,7 @@ void JSONVertexArray::write(json_stream& str, WriteVisitor& visitor) if (visitor._mergeAllBinaryFiles) url << bufferName; else - url << basename << "_" << _uniqueID << ".bin"; + url << basename << "_" << getUniqueID() << ".bin"; } std::string type; @@ -367,6 +360,20 @@ void JSONVertexArray::write(json_stream& str, WriteVisitor& visitor) osg::ref_ptr array = _arrayData; switch (array->getType()) { + case osg::Array::QuatArrayType: + { + osg::ref_ptr converted = new osg::Vec4Array; + converted->reserve(array->getNumElements()); + const osg::QuatArray* a = dynamic_cast(array.get()); + for (unsigned int i = 0; i < array->getNumElements(); ++i) { + converted->push_back(osg::Vec4(static_cast((*a)[i][0]), + static_cast((*a)[i][1]), + static_cast((*a)[i][2]), + static_cast((*a)[i][3]))); + } + array = converted; + type = "Float32Array"; + } case osg::Array::FloatArrayType: case osg::Array::Vec2ArrayType: case osg::Array::Vec3ArrayType: @@ -456,6 +463,7 @@ void JSONVertexArray::write(json_stream& str, WriteVisitor& visitor) case osg::Array::Vec2dArrayType: case osg::Array::Vec3dArrayType: case osg::Array::Vec4dArrayType: + case osg::Array::QuatArrayType: { const double* a = static_cast(array->getDataPointer()); unsigned int size = array->getNumElements() * array->getDataSize(); @@ -583,13 +591,6 @@ JSONVec4Array::JSONVec4Array(const osg::Vec4& v) : JSONVec3Array() } } -JSONVec5Array::JSONVec5Array(const Vec5& v) : JSONVec3Array() -{ - for (int i = 0; i < 5; ++i) { - _array.push_back(new JSONValue(v[i])); - } -} - JSONVec2Array::JSONVec2Array(const osg::Vec2& v) : JSONVec3Array() { for (int i = 0; i < 2; ++i) { @@ -619,26 +620,6 @@ void JSONVec3Array::write(json_stream& str,WriteVisitor& visitor) str << "]"; } -void JSONKeyframes::write(json_stream& str,WriteVisitor& visitor) -{ - JSONObjectBase::level++; - str << "[" << std::endl << JSONObjectBase::indent(); - for (unsigned int i = 0; i < _array.size(); i++) { - if (_array[i].valid()) { - _array[i]->write(str, visitor); - } else { - str << "undefined"; - } - if (i != _array.size() -1) { - str << ","; - str << "\n" << JSONObjectBase::indent(); - } - } - str << " ]"; - JSONObjectBase::level--; -} - - void JSONArray::write(json_stream& str,WriteVisitor& visitor) { str << "[ "; @@ -697,23 +678,3 @@ JSONObject* getDrawMode(GLenum mode) } return result; } - -JSONDrawArray::JSONDrawArray(osg::DrawArrays& array) -{ - getMaps()["First"] = new JSONValue(array.getFirst()); - getMaps()["Count"] = new JSONValue(array.getCount()); - getMaps()["Mode"] = getDrawMode(array.getMode()); -} - - -JSONDrawArrayLengths::JSONDrawArrayLengths(osg::DrawArrayLengths& array) -{ - getMaps()["First"] = new JSONValue(array.getFirst()); - getMaps()["Mode"] = getDrawMode(array.getMode()); - - JSONArray* jsonArray = new JSONArray; - for (unsigned int i = 0; i < array.size(); i++) { - jsonArray->getArray().push_back(new JSONValue(array[i])); - } - getMaps()["ArrayLengths"] = jsonArray; -} diff --git a/src/osgPlugins/osgjs/ReaderWriterJSON.cpp b/src/osgPlugins/osgjs/ReaderWriterJSON.cpp index 21960cf8c..cdf929d34 100644 --- a/src/osgPlugins/osgjs/ReaderWriterJSON.cpp +++ b/src/osgPlugins/osgjs/ReaderWriterJSON.cpp @@ -48,7 +48,7 @@ public: bool varint; bool strictJson; std::vector useSpecificBuffer; - + std::string baseLodURL; OptionsStruct() { resizeTextureUpToPowerOf2 = 0; useExternalBinaryArray = false; @@ -69,7 +69,7 @@ public: supportsOption("mergeAllBinaryFiles","merge all binary files into one to avoid multi request on a server"); supportsOption("inlineImages","insert base64 encoded images instead of referring to them"); supportsOption("varint","Use varint encoding to serialize integer buffers"); - supportsOption("useSpecificBuffer=uservalue1,uservalue2","uses specific buffers for unshared buffers attached to geometries having a specified user value"); + supportsOption("useSpecificBuffer=userkey1[=uservalue1][:buffername1],userkey2[=uservalue2][:buffername2]","uses specific buffers for unshared buffers attached to geometries having a specified user key/value. Buffer name *may* be specificed after ':' and will be set to uservalue by default. If no value is set then only the existence of a uservalue with key string is performed."); supportsOption("disableCompactBuffer","keep source types and do not try to optimize buffers size"); supportsOption("disableStrictJson","do not clean string (to utf8) or floating point (should be finite) values"); } @@ -85,6 +85,7 @@ public: std::string ext = osgDB::getFileExtension(fileName); if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; + OptionsStruct _options = parseOptions(options); json_stream fout(fileName, _options.strictJson); @@ -127,6 +128,7 @@ public: writer.inlineImages(options.inlineImages); writer.setMaxTextureDimension(options.resizeTextureUpToPowerOf2); writer.setVarint(options.varint); + writer.setBaseLodURL(options.baseLodURL); for(std::vector::const_iterator specificBuffer = options.useSpecificBuffer.begin() ; specificBuffer != options.useSpecificBuffer.end() ; ++ specificBuffer) { writer.addSpecificBuffer(*specificBuffer); @@ -214,6 +216,11 @@ public: localOptions.useSpecificBuffer.push_back(post_equals.substr(start_pos, post_equals.length() - start_pos)); } + + } + if (!options->getPluginStringData( std::string ("baseLodURL" )).empty()) + { + localOptions.baseLodURL = options->getPluginStringData( std::string ("baseLodURL" )); } } return localOptions; diff --git a/src/osgPlugins/osgjs/WriteVisitor b/src/osgPlugins/osgjs/WriteVisitor index c1e885e49..c2e64d247 100644 --- a/src/osgPlugins/osgjs/WriteVisitor +++ b/src/osgPlugins/osgjs/WriteVisitor @@ -14,25 +14,37 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include +#include +#include +#include +#include + +#include +# #include #include #include #include #include +#include +#include #include "JSON_Objects" #include "Animation" #include "json_stream" -#define WRITER_VERSION 7 +#define WRITER_VERSION 9 osg::Array* getTangentSpaceArray(osg::Geometry& geometry); @@ -46,18 +58,20 @@ class WriteVisitor : public osg::NodeVisitor { public: typedef std::vector > StateSetStack; + typedef std::pair KeyValue; std::map, osg::ref_ptr > _maps; std::vector > _parents; osg::ref_ptr _root; StateSetStack _stateset; std::string _baseName; + std::string _baseLodURL; bool _useExternalBinaryArray; bool _mergeAllBinaryFiles; bool _inlineImages; - bool _varint; int _maxTextureDimension; - std::vector _specificBuffers; + bool _varint; + std::map _specificBuffers; std::map _buffers; std::ofstream& getBufferFile(const std::string& name) { @@ -67,13 +81,14 @@ public: return *_buffers[name]; } - WriteVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) { - _mergeAllBinaryFiles = false; - _useExternalBinaryArray = false; - _inlineImages = false; - _maxTextureDimension = 0; - _varint = false; - } + WriteVisitor() : + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), + _useExternalBinaryArray(false), + _mergeAllBinaryFiles(false), + _inlineImages(false), + _maxTextureDimension(0), + _varint(false) + {} ~WriteVisitor() { for(std::map::iterator buffer = _buffers.begin() ; @@ -82,12 +97,20 @@ public: } } - std::string getBinaryFilename(const std::string& buffer = "") { - std::string suffix; - if(!buffer.empty()) { - suffix = "_" + buffer; + std::string getBinaryFilename(KeyValue flag=KeyValue()) const { + std::string suffix, + prefix(_baseName); + std::map::const_iterator it_buffer = _specificBuffers.find(flag); + if(it_buffer != _specificBuffers.end()) { + if(osgDB::isAbsolutePath(it_buffer->second)) { + // if output is explicit, do not change it + return it_buffer->second; + } + else { + suffix = "_" + it_buffer->second; + } } - return std::string(_baseName) + suffix + ".bin"; + return prefix + suffix + ".bin"; } void closeBuffers() { @@ -97,9 +120,9 @@ public: } } - unsigned int getBuffersSize() { + unsigned int getBuffersSize() const { unsigned int size = 0; - for(std::map::iterator buffer = _buffers.begin() ; + for(std::map::const_iterator buffer = _buffers.begin() ; buffer != _buffers.end() ; ++ buffer) { size += buffer->second->tellp(); } @@ -130,12 +153,19 @@ public: throw "Error occur"; } - void setBufferName(JSONObject *json, osg::Geometry* geometry) { + void setBufferName(JSONObject *json, osg::Object* parent=0, osg::Object* object=0) const { if(!_mergeAllBinaryFiles || _specificBuffers.empty()) return; - std::string bufferName = getBufferName(geometry); + + // try to fetch buffer name for object + std::string bufferName = getBufferName(object); std::string defaultBufferName = getBinaryFilename(); std::string jsonBufferName = json->getBufferName(); + + if(bufferName == defaultBufferName) { + // in case none is set, fallback to parent buffer name + bufferName = getBufferName(parent); + } // if the buffer is shared we will always favor dumping it in the default // buffer and otherwise we keep the first buffer name set. if(!jsonBufferName.empty()) { @@ -148,39 +178,89 @@ public: } } - std::string getBufferName(osg::Geometry* geometry) { - std::string name(""); - bool isSpecific = false; - for(std::vector::iterator it_flag = _specificBuffers.begin() ; - it_flag != _specificBuffers.end() ; ++ it_flag) { - if(geometry->getUserValue(*it_flag, isSpecific) && isSpecific) { - name = *it_flag; - break; + std::string getBufferName(osg::Object* object) const { + KeyValue flag; + if(object && object->getUserDataContainer() && object->getUserDataContainer()->getNumUserObjects()) { + for(std::map::const_iterator it_flag = _specificBuffers.begin() ; it_flag != _specificBuffers.end() ; ++ it_flag) { + std::string key = it_flag->first.first, + value = it_flag->first.second; + + // only looking for existence of user value + if(value.empty()) { + if(object->getUserDataContainer()->getUserObject(key)) { + flag = it_flag->first; + break; + } + } + else { + std::set uservalues; + + bool boolValue; + int numberValue; + unsigned int uNumberValue; + std::string stringValue; + + if(object->getUserValue(key, boolValue)) { + std::ostringstream oss; + if(boolValue) { + uservalues.insert("1"); + uservalues.insert("true"); + } + else { + uservalues.insert("0"); + uservalues.insert("false"); + } + } + + if(object->getUserValue(key, numberValue)) { + std::ostringstream oss; + oss << numberValue; + uservalues.insert(oss.str()); + } + + if(object->getUserValue(key, uNumberValue)) { + std::ostringstream oss; + oss << uNumberValue; + uservalues.insert(oss.str()); + } + + if(object->getUserValue(key, stringValue)) { + uservalues.insert(stringValue); + } + + if(uservalues.find(value) != uservalues.end()) { + flag = it_flag->first; + break; + } + } } } - return getBinaryFilename(name); + return getBinaryFilename(flag); } JSONObject* createJSONPagedLOD(osg::PagedLOD* plod); JSONObject* createJSONStateSet(osg::StateSet* ss); JSONObject* createJSONTexture(osg::Texture* sa); + JSONObject* createJSONText(osgText::Text* text); JSONObject* createJSONMaterial(osg::Material* sa); JSONObject* createJSONLight(osg::Light* sa); JSONObject* createJSONCullFace(osg::CullFace* sa); JSONObject* createJSONBlendColor(osg::BlendColor* sa); JSONObject* createJSONBlendFunc(osg::BlendFunc* sa); - JSONObject* createJSONBufferArray(osg::Array* array, osg::Geometry* geom = 0); - JSONObject* createJSONDrawElements(osg::DrawArrays* drawArray, osg::Geometry* geom = 0); + JSONObject* createJSONBufferArray(osg::Array* array, osg::Object* parent = 0); + JSONObject* createJSONDrawElements(osg::DrawArrays* drawArray, osg::Object* parent = 0); - JSONObject* createJSONDrawElementsUInt(osg::DrawElementsUInt* de, osg::Geometry* geom = 0); - JSONObject* createJSONDrawElementsUShort(osg::DrawElementsUShort* de, osg::Geometry* geom = 0); - JSONObject* createJSONDrawElementsUByte(osg::DrawElementsUByte* de, osg::Geometry* geom = 0); + JSONObject* createJSONDrawElementsUInt(osg::DrawElementsUInt* de, osg::Object* parent = 0); + JSONObject* createJSONDrawElementsUShort(osg::DrawElementsUShort* de, osg::Object* parent = 0); + JSONObject* createJSONDrawElementsUByte(osg::DrawElementsUByte* de, osg::Object* parent = 0); - JSONObject* createJSONDrawArray(osg::DrawArrays* drawArray, osg::Geometry* geom = 0); - JSONObject* createJSONDrawArrayLengths(osg::DrawArrayLengths* drawArray, osg::Geometry* geom = 0); + JSONObject* createJSONDrawArray(osg::DrawArrays* drawArray, osg::Object* parent = 0); + JSONObject* createJSONDrawArrayLengths(osg::DrawArrayLengths* drawArray, osg::Object* parent = 0); - JSONObject* createJSONGeometry(osg::Geometry* geom); + JSONObject* createJSONGeometry(osg::Geometry* geometry, osg::Object* parent=0); + JSONObject* createJSONRigGeometry(osgAnimation::RigGeometry* rigGeometry); + JSONObject* createJSONMorphGeometry(osgAnimation::MorphGeometry* morphGeom, osg::Object* parent=0); JSONObject* getParent() { if (_parents.empty()) { @@ -214,39 +294,69 @@ public: osg::ref_ptr updateCallbacks = new JSONArray; osg::ref_ptr nc = node.getUpdateCallback(); while (nc) { - osgAnimation::BasicAnimationManager* am = dynamic_cast(nc.get()); - if (am) { + if(osgAnimation::BasicAnimationManager* am = dynamic_cast(nc.get())) { osg::ref_ptr array = new JSONArray; osg::ref_ptr bam = new JSONObject; + translateObject(bam.get(), am); bam->getMaps()["Animations"] = array; - osg::ref_ptr nodeCallbackObject = new JSONObject; nodeCallbackObject->getMaps()["osgAnimation.BasicAnimationManager"] = bam; updateCallbacks->getArray().push_back(nodeCallbackObject); for ( unsigned int i = 0; i < am->getAnimationList().size(); i++) { - osg::ref_ptr jsonAnim = createJSONAnimation(am->getAnimationList()[i].get()); + osgAnimation::Animation* animation = am->getAnimationList()[i].get(); + osg::ref_ptr jsonAnim = createJSONAnimation(animation, this); if (jsonAnim) { + translateObject(jsonAnim.get(), animation); osg::ref_ptr obj = new JSONObject; obj->getMaps()["osgAnimation.Animation"] = jsonAnim; array->getArray().push_back(obj); - //std::stringstream ss; - //jsonAnim->write(ss); - //std::cout << ss.str() << std::endl; } } - } else { - osgAnimation::UpdateMatrixTransform* updateMT = dynamic_cast(nc.get()); - if (updateMT) { - osg::ref_ptr jsonCallback = createJSONUpdateMatrixTransform(*updateMT); - if (jsonCallback.valid()) { - osg::ref_ptr jsonObject = new JSONObject; - jsonObject->getMaps()["osgAnimation.UpdateMatrixTransform"] = jsonCallback; - updateCallbacks->getArray().push_back(jsonObject); - } + } + else if(osgAnimation::UpdateBone* upBone = dynamic_cast(nc.get())) { + osg::ref_ptr jsonCallback = createJSONUpdateMatrixTransform(*upBone, this); + if (jsonCallback.valid()) { + osg::ref_ptr jsonObject = new JSONObject; + jsonObject->getMaps()["osgAnimation.UpdateBone"] = jsonCallback; + updateCallbacks->getArray().push_back(jsonObject); } } + else if(osgAnimation::UpdateMatrixTransform* updateMT = dynamic_cast(nc.get())) { + osg::ref_ptr jsonCallback = createJSONUpdateMatrixTransform(*updateMT, this); + if (jsonCallback.valid()) { + osg::ref_ptr jsonObject = new JSONObject; + jsonObject->getMaps()["osgAnimation.UpdateMatrixTransform"] = jsonCallback; + updateCallbacks->getArray().push_back(jsonObject); + } + } + else if(dynamic_cast(nc.get())) { + osg::ref_ptr json = new JSONNode; + osg::ref_ptr jsonObject = new JSONObject; + _maps[&node] = json; + jsonObject->getMaps()["osgAnimation.UpdateSkeleton"] = json; + updateCallbacks->getArray().push_back(jsonObject); + } + else if(osgAnimation::UpdateMorph* updateMorph = dynamic_cast(nc.get())) { + osg::ref_ptr json = new JSONNode; + osg::ref_ptr jsonObject = new JSONObject; + osg::ref_ptr jsonTargetName = new JSONObject; + json->getMaps()["Name"] = new JSONValue(updateMorph->getName()); + + unsigned int numTarget = updateMorph->getNumTarget(); + for(unsigned int i = 0; i < numTarget; ++i) { + std::ostringstream oss; + oss << i; + jsonTargetName->getMaps()[ oss.str() ] = new JSONValue(updateMorph->getTargetName(i)); + } + json->getMaps()["TargetMap"] = jsonTargetName; + json->getMaps()["TargetMap"] = jsonTargetName; + + _maps[&node] = json; + jsonObject->getMaps()["osgAnimation.UpdateMorph"] = json; + updateCallbacks->getArray().push_back(jsonObject); + } nc = nc->getNestedCallback(); } @@ -255,13 +365,28 @@ public: } } - void apply(osg::Drawable& drw) { - osg::Geometry* geom = dynamic_cast(&drw); - if (geom) { - JSONObject* json = createJSONGeometry(geom); + void apply(osg::Drawable& drawable) { + if(osgAnimation::RigGeometry * rigGeometry = dynamic_cast(&drawable)) { + JSONObject* json = createJSONRigGeometry(rigGeometry); + translateObject(json, rigGeometry); + JSONObject* parent = getParent(); + parent->addChild("osgAnimation.RigGeometry", json); + } + else if(osgAnimation::MorphGeometry * morphGeometry = dynamic_cast(&drawable)) { + JSONObject* json = createJSONMorphGeometry(morphGeometry); + JSONObject* parent = getParent(); + parent->addChild("osgAnimation.MorphGeometry", json); + } + else if(osg::Geometry* geometry = dynamic_cast(&drawable)) { + JSONObject* json = createJSONGeometry(geometry); JSONObject* parent = getParent(); parent->addChild("osg.Geometry", json); } + else if(osgText::Text* text = dynamic_cast(&drawable)) { + JSONObject* json = createJSONText(text); + JSONObject* parent = getParent(); + parent->addChild("osgText.Text", json); + } } void apply(osg::Geode& node) { @@ -273,7 +398,6 @@ public: } osg::ref_ptr json = new JSONNode; - json->addUniqueID(); _maps[&node] = json; applyCallback(node, json.get()); @@ -298,7 +422,6 @@ public: } osg::ref_ptr json = new JSONNode; - json->addUniqueID(); _maps[&node] = json; parent->addChild("osg.Node", json.get()); @@ -346,7 +469,6 @@ public: } osg::ref_ptr json = new JSONNode; - json->addUniqueID(); _maps[&node] = json; applyCallback(node, json.get()); @@ -375,7 +497,6 @@ public: } osg::ref_ptr json = new JSONNode; - json->addUniqueID(); _maps[&node] = json; applyCallback(node, json.get()); @@ -390,15 +511,54 @@ public: _parents.pop_back(); } + void applyCommonMatrixTransform(const char * jsClassName, osg::ref_ptr &json, osg::MatrixTransform &node, JSONObject* parent) { + json->addUniqueID(); + _maps[&node] = json; + + applyCallback(node, json.get()); + createJSONStateSet(node, json.get()); + + parent->addChild(jsClassName, json.get()); + + initJsonObjectFromNode(node, *json); + json->getMaps()["Matrix"] = new JSONMatrix(node.getMatrix()); + } + + void apply(osgText::Text& node) { + JSONObject* parent = getParent(); + if (_maps.find(&node) != _maps.end()) { + parent->addChild("osgText.Text", _maps[&node]->getShadowObject()); + return; + } + + osg::ref_ptr json = createJSONText(&node); + json->addUniqueID(); + _maps[&node] = json.get(); + parent->addChild("osgText.Text", json.get()); + applyCallback(node, json.get()); + createJSONStateSet(node, json.get()); + initJsonObjectFromNode(node, *json); + _parents.push_back(json); + traverse(node); + _parents.pop_back(); + } + void apply(osg::MatrixTransform& node) { + if (dynamic_cast(&node)) { + apply(static_cast(node)); + return; + } + if (dynamic_cast(&node)) { + apply(static_cast(node)); + return; + } + JSONObject* parent = getParent(); if (_maps.find(&node) != _maps.end()) { parent->addChild("osg.MatrixTransform", _maps[&node]->getShadowObject()); return; } - osg::ref_ptr json = new JSONNode; - json->addUniqueID(); _maps[&node] = json; applyCallback(node, json.get()); @@ -408,6 +568,58 @@ public: initJsonObjectFromNode(node, *json); json->getMaps()["Matrix"] = new JSONMatrix(node.getMatrix()); + + _parents.push_back(json); + traverse(node); + _parents.pop_back(); + + } + + void apply(osgAnimation::Skeleton& node) { + JSONObject* parent = getParent(); + if (_maps.find(&node) != _maps.end()) { + parent->addChild("osgAnimation.Skeleton", _maps[&node]->getShadowObject()); + return; + } + osg::ref_ptr json = new JSONNode; + applyCommonMatrixTransform("osgAnimation.Skeleton", json, node, parent); + _parents.push_back(json); + traverse(node); + _parents.pop_back(); + } + + void apply(osgAnimation::Bone &node) { + JSONObject* parent = getParent(); + if (_maps.find(&node) != _maps.end()) { + parent->addChild("osgAnimation.Bone", _maps[&node]->getShadowObject()); + return; + } + + osg::ref_ptr json = new JSONNode; + + osg::Vec3 min(0,0,0), max(0,0,0); + JSONObject *bboxData = new JSONObject; + bool hasBoundindBox = ( node.getUserValue("AABBonBone_min", min) && node.getUserValue("AABBonBone_max", max) ); + + if (hasBoundindBox) { + unsigned int idxmin = node.getUserDataContainer()->getUserObjectIndex("AABBonBone_min"); + node.getUserDataContainer()->removeUserObject(idxmin); + unsigned int idxmax = node.getUserDataContainer()->getUserObjectIndex("AABBonBone_max"); + node.getUserDataContainer()->removeUserObject(idxmax); + + if(node.getUserDataContainer() && node.getUserDataContainer()->getNumUserObjects() == 0) + node.setUserDataContainer(NULL); + + bboxData->getMaps()["min"] = new JSONVec3Array(min); + bboxData->getMaps()["max"] = new JSONVec3Array(max); + + json->getMaps()["BoundingBox"] = bboxData; + } + + json->getMaps()["InvBindMatrixInSkeletonSpace"] = new JSONMatrix(node.getInvBindMatrixInSkeletonSpace()); + + applyCommonMatrixTransform("osgAnimation.Bone", json, node, parent); + _parents.push_back(json); traverse(node); _parents.pop_back(); @@ -422,7 +634,6 @@ public: } osg::ref_ptr json = new JSONNode; - json->addUniqueID(); _maps[&node] = json; applyCallback(node, json.get()); @@ -445,7 +656,37 @@ public: void inlineImages(bool use) { _inlineImages = use; } void setVarint(bool use) { _varint = use; } void setMaxTextureDimension(int use) { _maxTextureDimension = use; } - void addSpecificBuffer(const std::string& bufferFlag) { _specificBuffers.push_back(bufferFlag); } + void addSpecificBuffer(const std::string& bufferFlag) { + if(bufferFlag.empty()) { + return; + } + + std::string key, value, buffer; + size_t equal = bufferFlag.find("="), + colon = bufferFlag.find(":"); + + key = bufferFlag.substr(0, std::min(equal, colon)); + if(equal != std::string::npos) { + if(colon == std::string::npos) { + value = bufferFlag.substr(equal + 1, std::string::npos); + } + else { + value = bufferFlag.substr(equal + 1, colon - equal - 1); + } + } + + if(colon != std::string::npos) { + buffer = bufferFlag.substr(colon + 1, std::string::npos); + } + else { + buffer = key; + } + + // buffer name should be lowercase + std::transform(buffer.begin(), buffer.end(), buffer.begin(), ::tolower); + _specificBuffers[KeyValue(key, value)] = buffer; + } + void setBaseLodURL(const std::string& baseLodURL) { _baseLodURL = baseLodURL; } }; #endif diff --git a/src/osgPlugins/osgjs/WriteVisitor.cpp b/src/osgPlugins/osgjs/WriteVisitor.cpp index 13916efa1..570afb979 100644 --- a/src/osgPlugins/osgjs/WriteVisitor.cpp +++ b/src/osgPlugins/osgjs/WriteVisitor.cpp @@ -10,10 +10,14 @@ #include #include #include + #include -#include "Base64" +#include +#include + +#include "Base64" osg::Array* getTangentSpaceArray(osg::Geometry& geometry) { @@ -27,6 +31,51 @@ osg::Array* getTangentSpaceArray(osg::Geometry& geometry) { return 0; } + +osg::Array* getAnimationBonesArray(osgAnimation::RigGeometry& rigGeometry) { + for(unsigned int i = 0 ; i < rigGeometry.getNumVertexAttribArrays() ; ++ i) { + osg::Array* attribute = rigGeometry.getVertexAttribArray(i); + bool isBones = false; + if(attribute && attribute->getUserValue("bones", isBones) && isBones) { + return attribute; + } + } + return 0; +} + + +osg::Array* getAnimationWeightsArray(osgAnimation::RigGeometry& rigGeometry) { + for(unsigned int i = 0 ; i < rigGeometry.getNumVertexAttribArrays() ; ++ i) { + osg::Array* attribute = rigGeometry.getVertexAttribArray(i); + bool isWeights = false; + if(attribute && attribute->getUserValue("weights", isWeights) && isWeights) { + return attribute; + } + } + return 0; +} + + +osg::ref_ptr buildRigBoneMap(osgAnimation::RigGeometry& rigGeometry) { + osg::Array* bones = getAnimationBonesArray(rigGeometry); + osg::ref_ptr boneMap = new JSONObject; + + unsigned int paletteIndex = 0; + while(true) { + std::ostringstream oss; + oss << "animationBone_" << paletteIndex; + std::string boneName, palette = oss.str(); + if(!bones->getUserValue(palette, boneName)) { + break; + } + boneMap->getMaps()[boneName] = new JSONValue(paletteIndex); + ++ paletteIndex; + } + + return boneMap; +} + + void translateObject(JSONObject* json, osg::Object* osg) { if (!osg->getName().empty()) { @@ -150,6 +199,7 @@ static JSONValue* getBlendFuncMode(GLenum mode) { default: return new JSONValue("ONE"); } + return new JSONValue("ONE"); } static JSONValue* getJSONFilterMode(osg::Texture::FilterMode mode) @@ -194,6 +244,44 @@ static JSONValue* getJSONWrapMode(osg::Texture::WrapMode mode) return 0; } +static JSONValue* getJSONAlignmentType(osgText::Text::AlignmentType type) +{ + switch(type) { + case osgText::Text::LEFT_TOP: + return new JSONValue("LEFT_TOP"); + case osgText::Text::LEFT_CENTER: + return new JSONValue("LEFT_CENTER"); + case osgText::Text::LEFT_BOTTOM: + return new JSONValue("LEFT_BOTTOM"); + case osgText::Text::CENTER_TOP: + return new JSONValue("CENTER_TOP"); + case osgText::Text::CENTER_CENTER: + return new JSONValue("CENTER_CENTER"); + case osgText::Text::CENTER_BOTTOM: + return new JSONValue("CENTER_BOTTOM"); + case osgText::Text::RIGHT_TOP: + return new JSONValue("RIGHT_TOP"); + case osgText::Text::RIGHT_CENTER: + return new JSONValue("RIGHT_CENTER"); + case osgText::Text::RIGHT_BOTTOM: + return new JSONValue("RIGHT_BOTTOM"); + case osgText::Text::LEFT_BASE_LINE: + return new JSONValue("LEFT_BASE_LINE"); + case osgText::Text::CENTER_BASE_LINE: + return new JSONValue("CENTER_BASE_LINE"); + case osgText::Text::RIGHT_BASE_LINE: + return new JSONValue("RIGHT_BASE_LINE"); + case osgText::Text::LEFT_BOTTOM_BASE_LINE: + return new JSONValue("LEFT_BOTTOM_BASE_LINE"); + case osgText::Text::CENTER_BOTTOM_BASE_LINE: + return new JSONValue("CENTER_BOTTOM_BASE_LINE"); + case osgText::Text::RIGHT_BOTTOM_BASE_LINE: + return new JSONValue("RIGHT_BOTTOM_BASE_LINE"); + default: + return 0; + } + return 0; +} JSONObject* createImage(osg::Image* image, bool inlineImages, int maxTextureDimension, const std::string &baseName) { @@ -224,7 +312,8 @@ JSONObject* createImage(osg::Image* image, bool inlineImages, int maxTextureDime } else { // no image file so use this inline name image and create a file std::stringstream ss; - ss << osgDB::getFilePath(baseName) << osgDB::getNativePathSeparator(); + if ( !osgDB::getFilePath(baseName).empty()) + ss << osgDB::getFilePath(baseName) << osgDB::getNativePathSeparator(); ss << (int64_t)image << ".inline_conv_generated.png"; // write the pointer location std::string filename = ss.str(); if (osgDB::writeImageFile(*image, filename)) { @@ -235,9 +324,18 @@ JSONObject* createImage(osg::Image* image, bool inlineImages, int maxTextureDime if (!image->getFileName().empty()) { // means that everything went ok if (inlineImages) { - std::ifstream in(osgDB::findDataFile(image->getFileName()).c_str()); - if (in.is_open()) + std::ifstream in(osgDB::findDataFile(image->getFileName()).c_str(), std::ifstream::in | std::ifstream::binary); + if (in.is_open() && in.good()) { + // read file first to iterate + in.seekg(0, std::ifstream::end); + const std::ifstream::pos_type size = in.tellg(); + in.seekg(0, std::ifstream::beg); + std::vector rawData; + rawData.resize(size); + in.read(reinterpret_cast(rawData.data()),size); + in.seekg(std::ios_base::beg); + std::stringstream out; out << "data:image/" << osgDB::getLowerCaseFileExtension(image->getFileName()) << ";base64,"; base64::encode(std::istreambuf_iterator(in), @@ -255,64 +353,60 @@ JSONObject* createImage(osg::Image* image, bool inlineImages, int maxTextureDime } -JSONObject* WriteVisitor::createJSONBufferArray(osg::Array* array, osg::Geometry* geom) +JSONObject* WriteVisitor::createJSONBufferArray(osg::Array* array, osg::Object* parent) { if (_maps.find(array) != _maps.end()) return _maps[array]->getShadowObject(); osg::ref_ptr json = new JSONBufferArray(array); - json->addUniqueID(); _maps[array] = json; - if(geom && _mergeAllBinaryFiles) { - setBufferName(json.get(), geom); + if(_mergeAllBinaryFiles) { + setBufferName(json.get(), parent, array); } return json.get(); } -JSONObject* WriteVisitor::createJSONDrawElementsUInt(osg::DrawElementsUInt* de, osg::Geometry* geom) +JSONObject* WriteVisitor::createJSONDrawElementsUInt(osg::DrawElementsUInt* de, osg::Object* parent) { if (_maps.find(de) != _maps.end()) return _maps[de]->getShadowObject(); JSONDrawElements* json = new JSONDrawElements(*de); - json->addUniqueID(); _maps[de] = json; - if(geom && _mergeAllBinaryFiles) { - setBufferName(json, geom); + if(_mergeAllBinaryFiles) { + setBufferName(json, parent, de); } return json; } -JSONObject* WriteVisitor::createJSONDrawElementsUShort(osg::DrawElementsUShort* de, osg::Geometry* geom) +JSONObject* WriteVisitor::createJSONDrawElementsUShort(osg::DrawElementsUShort* de, osg::Object* parent) { if (_maps.find(de) != _maps.end()) return _maps[de]->getShadowObject(); JSONDrawElements* json = new JSONDrawElements(*de); - json->addUniqueID(); _maps[de] = json; - if(geom && _mergeAllBinaryFiles) { - setBufferName(json, geom); + if(_mergeAllBinaryFiles) { + setBufferName(json, parent, de); } return json; } -JSONObject* WriteVisitor::createJSONDrawElementsUByte(osg::DrawElementsUByte* de, osg::Geometry* geom) +JSONObject* WriteVisitor::createJSONDrawElementsUByte(osg::DrawElementsUByte* de, osg::Object* parent) { if (_maps.find(de) != _maps.end()) return _maps[de]->getShadowObject(); JSONDrawElements* json = new JSONDrawElements(*de); - json->addUniqueID(); _maps[de] = json; - if(geom && _mergeAllBinaryFiles) { - setBufferName(json, geom); + if(_mergeAllBinaryFiles) { + setBufferName(json, parent, de); } return json; } // use to convert draw array quads to draw elements triangles -JSONObject* WriteVisitor::createJSONDrawElements(osg::DrawArrays* drawArray, osg::Geometry* geom) +JSONObject* WriteVisitor::createJSONDrawElements(osg::DrawArrays* drawArray, osg::Object* parent) { if (_maps.find(drawArray) != _maps.end()) return _maps[drawArray]->getShadowObject(); @@ -335,79 +429,77 @@ JSONObject* WriteVisitor::createJSONDrawElements(osg::DrawArrays* drawArray, osg de->push_back(base + 3); } JSONDrawElements* json = new JSONDrawElements(*de); - json->addUniqueID(); _maps[drawArray] = json; - if(geom && _mergeAllBinaryFiles) { - setBufferName(json, geom); + if(_mergeAllBinaryFiles) { + setBufferName(json, parent, drawArray); } return json; } -JSONObject* WriteVisitor::createJSONDrawArray(osg::DrawArrays* da, osg::Geometry* geom) +JSONObject* WriteVisitor::createJSONDrawArray(osg::DrawArrays* da, osg::Object* parent) { if (_maps.find(da) != _maps.end()) return _maps[da]->getShadowObject(); osg::ref_ptr json = new JSONDrawArray(*da); - json->addUniqueID(); _maps[da] = json; - if(geom && _mergeAllBinaryFiles) { - setBufferName(json.get(), geom); + if(_mergeAllBinaryFiles) { + setBufferName(json.get(), parent, da); } return json.get(); } -JSONObject* WriteVisitor::createJSONDrawArrayLengths(osg::DrawArrayLengths* da, osg::Geometry* geom) +JSONObject* WriteVisitor::createJSONDrawArrayLengths(osg::DrawArrayLengths* da, osg::Object* parent) { if (_maps.find(da) != _maps.end()) return _maps[da]->getShadowObject(); osg::ref_ptr json = new JSONDrawArrayLengths(*da); - json->addUniqueID(); _maps[da] = json; - if(geom && _mergeAllBinaryFiles) { - setBufferName(json.get(), geom); + if(_mergeAllBinaryFiles) { + setBufferName(json.get(), parent, da); } return json.get(); } -JSONObject* WriteVisitor::createJSONGeometry(osg::Geometry* geom) +JSONObject* WriteVisitor::createJSONGeometry(osg::Geometry* geometry, osg::Object* parent) { - if (_maps.find(geom) != _maps.end()) - return _maps[geom]->getShadowObject(); + if(!parent) { + parent = geometry; + } - //if (needToSplit(*geom)) - // error(); + if (_maps.find(geometry) != _maps.end()) + return _maps[geometry]->getShadowObject(); - osg::ref_ptr json = new JSONNode; + osg::ref_ptr json = new JSONObject; json->addUniqueID(); - _maps[geom] = json; + _maps[geometry] = json; - if (geom->getStateSet()) - createJSONStateSet(json.get(), geom->getStateSet()); + if (geometry->getStateSet()) + createJSONStateSet(json.get(), geometry->getStateSet()); - translateObject(json.get(), geom); + translateObject(json.get(), geometry); osg::ref_ptr attributes = new JSONObject; int nbVertexes = 0; - if (geom->getVertexArray()) { - nbVertexes = geom->getVertexArray()->getNumElements(); - attributes->getMaps()["Vertex"] = createJSONBufferArray(geom->getVertexArray(), geom); + if (geometry->getVertexArray()) { + nbVertexes = geometry->getVertexArray()->getNumElements(); + attributes->getMaps()["Vertex"] = createJSONBufferArray(geometry->getVertexArray(), parent); } - if (geom->getNormalArray()) { - attributes->getMaps()["Normal"] = createJSONBufferArray(geom->getNormalArray(), geom); - int nb = geom->getNormalArray()->getNumElements(); + if (geometry->getNormalArray()) { + attributes->getMaps()["Normal"] = createJSONBufferArray(geometry->getNormalArray(), parent); + int nb = geometry->getNormalArray()->getNumElements(); if (nbVertexes != nb) { osg::notify(osg::FATAL) << "Fatal nb normals " << nb << " != " << nbVertexes << std::endl; error(); } } - if (geom->getColorArray()) { - attributes->getMaps()["Color"] = createJSONBufferArray(geom->getColorArray(), geom); - int nb = geom->getColorArray()->getNumElements(); + if (geometry->getColorArray()) { + attributes->getMaps()["Color"] = createJSONBufferArray(geometry->getColorArray(), parent); + int nb = geometry->getColorArray()->getNumElements(); if (nbVertexes != nb) { osg::notify(osg::FATAL) << "Fatal nb colors " << nb << " != " << nbVertexes << std::endl; error(); @@ -419,9 +511,9 @@ JSONObject* WriteVisitor::createJSONGeometry(osg::Geometry* geom) ss.str(""); ss << "TexCoord" << i; //osg::notify(osg::NOTICE) << ss.str() << std::endl; - if (geom->getTexCoordArray(i)) { - attributes->getMaps()[ss.str()] = createJSONBufferArray(geom->getTexCoordArray(i), geom); - int nb = geom->getTexCoordArray(i)->getNumElements(); + if (geometry->getTexCoordArray(i)) { + attributes->getMaps()[ss.str()] = createJSONBufferArray(geometry->getTexCoordArray(i), parent); + int nb = geometry->getTexCoordArray(i)->getNumElements(); if (nbVertexes != nb) { osg::notify(osg::FATAL) << "Fatal nb tex coord " << i << " " << nb << " != " << nbVertexes << std::endl; error(); @@ -429,9 +521,9 @@ JSONObject* WriteVisitor::createJSONGeometry(osg::Geometry* geom) } } - osg::Array* tangents = getTangentSpaceArray(*geom); + osg::Array* tangents = getTangentSpaceArray(*geometry); if (tangents) { - attributes->getMaps()["Tangent"] = createJSONBufferArray(tangents, geom); + attributes->getMaps()["Tangent"] = createJSONBufferArray(tangents, parent); int nb = tangents->getNumElements(); if (nbVertexes != nb) { osg::notify(osg::FATAL) << "Fatal nb tangent " << nb << " != " << nbVertexes << std::endl; @@ -441,11 +533,11 @@ JSONObject* WriteVisitor::createJSONGeometry(osg::Geometry* geom) json->getMaps()["VertexAttributeList"] = attributes; - if (!geom->getPrimitiveSetList().empty()) { + if (!geometry->getPrimitiveSetList().empty()) { osg::ref_ptr primitives = new JSONArray(); - for (unsigned int i = 0; i < geom->getNumPrimitiveSets(); ++i) { + for (unsigned int i = 0; i < geometry->getNumPrimitiveSets(); ++i) { osg::ref_ptr obj = new JSONObject; - osg::PrimitiveSet* primitive = geom->getPrimitiveSet(i); + osg::PrimitiveSet* primitive = geometry->getPrimitiveSet(i); if(!primitive) continue; if (primitive->getType() == osg::PrimitiveSet::DrawArraysPrimitiveType) { @@ -454,9 +546,9 @@ JSONObject* WriteVisitor::createJSONGeometry(osg::Geometry* geom) { primitives->getArray().push_back(obj); if (da->getMode() == GL_QUADS) { - obj->getMaps()["DrawElementsUShort"] = createJSONDrawElements(da, geom); + obj->getMaps()["DrawElementsUShort"] = createJSONDrawElements(da, parent); } else { - obj->getMaps()["DrawArrays"] = createJSONDrawArray(da, geom); + obj->getMaps()["DrawArrays"] = createJSONDrawArray(da, parent); } } } else if (primitive->getType() == osg::PrimitiveSet::DrawElementsUIntPrimitiveType) { @@ -464,40 +556,114 @@ JSONObject* WriteVisitor::createJSONGeometry(osg::Geometry* geom) if (da) { primitives->getArray().push_back(obj); - obj->getMaps()["DrawElementsUInt"] = createJSONDrawElementsUInt(da, geom); + obj->getMaps()["DrawElementsUInt"] = createJSONDrawElementsUInt(da, parent); } - } else if (primitive->getType() == osg::PrimitiveSet::DrawElementsUShortPrimitiveType) { osg::DrawElementsUShort* da = dynamic_cast((primitive)); if (da) { primitives->getArray().push_back(obj); - obj->getMaps()["DrawElementsUShort"] = createJSONDrawElementsUShort(da, geom); + obj->getMaps()["DrawElementsUShort"] = createJSONDrawElementsUShort(da, parent); } } else if (primitive->getType() == osg::PrimitiveSet::DrawElementsUBytePrimitiveType) { osg::DrawElementsUByte* da = dynamic_cast((primitive)); if (da) { primitives->getArray().push_back(obj); - obj->getMaps()["DrawElementsUByte"] = createJSONDrawElementsUByte(da, geom); + obj->getMaps()["DrawElementsUByte"] = createJSONDrawElementsUByte(da, parent); } - } else if (primitive->getType() == osg::PrimitiveSet::DrawArrayLengthsPrimitiveType) { osg::DrawArrayLengths* dal = dynamic_cast((primitive)); if (dal) { primitives->getArray().push_back(obj); - obj->getMaps()["DrawArrayLengths"] = createJSONDrawArrayLengths(dal, geom); + obj->getMaps()["DrawArrayLengths"] = createJSONDrawArrayLengths(dal, parent); } } else { - osg::notify(osg::WARN) << "Primitive Type " << geom->getPrimitiveSetList()[i]->getType() << " not supported, skipping" << std::endl; + osg::notify(osg::WARN) << "Primitive Type " << geometry->getPrimitiveSetList()[i]->getType() << " not supported, skipping" << std::endl; } } json->getMaps()["PrimitiveSetList"] = primitives; } + if (geometry->getComputeBoundingBoxCallback()) { + osg::ref_ptr jsonObj = new JSONObject; + jsonObj->addUniqueID(); + json->getMaps()["osg.ComputeBoundingBoxCallback"] = jsonObj; + } return json.get(); } +JSONObject* WriteVisitor::createJSONRigGeometry(osgAnimation::RigGeometry* rigGeometry) +{ + //TODO : Convert data to JSONVertexArray "Float32Array" + osg::ref_ptr json = new JSONObject; + json->addUniqueID(); + osg::ref_ptr sourceGeometry = new JSONObject; + + if(osgAnimation::MorphGeometry *morphGeometry = dynamic_cast(rigGeometry->getSourceGeometry())) { + sourceGeometry->getMaps()["osgAnimation.MorphGeometry"] = createJSONMorphGeometry(morphGeometry, rigGeometry); + } + else { + osg::Geometry *geometry = dynamic_cast(rigGeometry->getSourceGeometry()); + if(geometry) { + sourceGeometry->getMaps()["osg.Geometry"] = createJSONGeometry(geometry, rigGeometry); + } + } + + json->getMaps()["SourceGeometry"] = sourceGeometry.get(); + + osg::Array* bones = getAnimationBonesArray(*rigGeometry); + osg::Array* weights = getAnimationWeightsArray(*rigGeometry); + if (bones && weights) { + json->getMaps()["BoneMap"] = buildRigBoneMap(*rigGeometry); + + json->getMaps()["VertexAttributeList"] = new JSONObject; + osg::ref_ptr attributes = json->getMaps()["VertexAttributeList"]; + int nbVertexes = rigGeometry->getSourceGeometry()->getVertexArray()->getNumElements(); + + attributes->getMaps()["Bones"] = createJSONBufferArray(bones, rigGeometry); + attributes->getMaps()["Weights"] = createJSONBufferArray(weights, rigGeometry); + int nb = bones->getNumElements(); + if (nbVertexes != nb) { + osg::notify(osg::FATAL) << "Fatal nb bones " << nb << " != " << nbVertexes << std::endl; + error(); + } + nb = weights->getNumElements(); + if (nbVertexes != nb) { + osg::notify(osg::FATAL) << "Fatal nb weights " << nb << " != " << nbVertexes << std::endl; + error(); + } + } + + return json.release(); +} + +JSONObject* WriteVisitor::createJSONMorphGeometry(osgAnimation::MorphGeometry* morphGeometry, osg::Object* parent) +{ + if(!parent) { + parent = morphGeometry; + } + + JSONObject* jsonGeometry = createJSONGeometry(morphGeometry, parent); + JSONArray* targetList = new JSONArray; + + osgAnimation::MorphGeometry::MorphTargetList mTargetList = morphGeometry->getMorphTargetList(); + typedef osgAnimation::MorphGeometry::MorphTargetList::iterator TargetIterator; + + for(TargetIterator ti = mTargetList.begin(); ti != mTargetList.end(); ti++) { + osgAnimation::MorphGeometry::MorphTarget *morphTarget = &(*ti); + JSONObject *jsonGeometryObject = new JSONObject; + if(osg::Geometry* geometry = dynamic_cast(morphTarget->getGeometry())) { + geometry->setPrimitiveSetList(osg::Geometry::PrimitiveSetList()); //delete unused drawArray + jsonGeometryObject->getMaps()["osg.Geometry"] = createJSONGeometry(geometry); + targetList->asArray()->getArray().push_back(jsonGeometryObject); + } + } + jsonGeometry->getMaps()["MorphTargets"] = targetList; + + return jsonGeometry; +} + JSONObject* WriteVisitor::createJSONBlendFunc(osg::BlendFunc* sa) { if (_maps.find(sa) != _maps.end()) @@ -544,7 +710,7 @@ JSONObject* WriteVisitor::createJSONCullFace(osg::CullFace* sa) osg::ref_ptr > mode = new JSONValue("BACK"); if (sa->getMode() == osg::CullFace::FRONT) { - mode = new JSONValue("BACK"); + mode = new JSONValue("FRONT"); } if (sa->getMode() == osg::CullFace::FRONT_AND_BACK) { mode = new JSONValue("FRONT_AND_BACK"); @@ -555,14 +721,12 @@ JSONObject* WriteVisitor::createJSONCullFace(osg::CullFace* sa) - JSONObject* WriteVisitor::createJSONMaterial(osg::Material* material) { if (_maps.find(material) != _maps.end()) return _maps[material]->getShadowObject(); osg::ref_ptr jsonMaterial = new JSONMaterial; - jsonMaterial->addUniqueID(); _maps[material] = jsonMaterial; translateObject(jsonMaterial.get(), material); @@ -583,7 +747,6 @@ JSONObject* WriteVisitor::createJSONLight(osg::Light* light) return _maps[light]->getShadowObject(); osg::ref_ptr jsonLight = new JSONLight; - jsonLight->addUniqueID(); _maps[light] = jsonLight; translateObject(jsonLight.get(), light); @@ -617,6 +780,33 @@ template JSONObject* createImageFromTexture(osg::Texture* texture, JSO return 0; } +JSONObject* WriteVisitor::createJSONText(osgText::Text* text) +{ + if (_maps.find(text) != _maps.end()) + return _maps[text]->getShadowObject(); + + osg::ref_ptr jsonText = new JSONObject; + jsonText->addUniqueID(); + _maps[text] = jsonText; + jsonText->getMaps()["Text"] = new JSONValue( text->getText().createUTF8EncodedString() ); + jsonText->getMaps()["Position"] = new JSONVec3Array(text->getPosition()); + jsonText->getMaps()["Color"] = new JSONVec4Array(osg::Vec4(text->getColor().x(),text->getColor().y(),text->getColor().z(), text->getColor().w() )); + jsonText->getMaps()["CharacterSize"] = new JSONValue(text->getCharacterHeight() ); + jsonText->getMaps()["AutoRotateToScreen"] = new JSONValue(text->getAutoRotateToScreen() ); + jsonText->getMaps()["Alignment"] = getJSONAlignmentType(text->getAlignment()); + + osg::ref_ptr > layout = new JSONValue("LEFT_TO_RIGHT"); + if (text->getLayout() == osgText::Text::RIGHT_TO_LEFT) { + layout = new JSONValue("RIGHT_TO_LEFT"); + } + if (text->getLayout() == osgText::Text::VERTICAL) { + layout = new JSONValue("VERTICAL"); + } + jsonText->getMaps()["Layout"] = layout; + return jsonText.release(); +} + + JSONObject* WriteVisitor::createJSONPagedLOD(osg::PagedLOD *plod) { if (!plod) { return 0; } @@ -626,10 +816,8 @@ JSONObject* WriteVisitor::createJSONPagedLOD(osg::PagedLOD *plod) } osg::ref_ptr jsonPlod = new JSONNode; - jsonPlod->addUniqueID(); _maps[plod] = jsonPlod; - // Center Mode osg::ref_ptr > centerMode = new JSONValue("USE_BOUNDING_SPHERE_CENTER"); if (plod->getCenterMode() == osg::LOD::USER_DEFINED_CENTER) { @@ -649,8 +837,7 @@ JSONObject* WriteVisitor::createJSONPagedLOD(osg::PagedLOD *plod) } jsonPlod->getMaps()["RangeMode"] = rangeMode; // Range List - //osg::ref_ptr rangeList = new JSONArray; - JSONObject* rangeObject = new JSONObject; + osg::ref_ptr rangeObject = new JSONObject; for (unsigned int i =0; i< plod->getRangeList().size(); i++) { std::stringstream ss; @@ -662,7 +849,7 @@ JSONObject* WriteVisitor::createJSONPagedLOD(osg::PagedLOD *plod) jsonPlod->getMaps()["RangeList"] = rangeObject; // File List - JSONObject* fileObject = new JSONObject; + osg::ref_ptr fileObject = new JSONObject; for (unsigned int i =0; i< plod->getNumFileNames(); i++) { std::stringstream ss; @@ -670,19 +857,28 @@ JSONObject* WriteVisitor::createJSONPagedLOD(osg::PagedLOD *plod) ss << i; std::string str = ss.str(); // We need to convert first from osg format to osgjs format. - osg::ref_ptr n = osgDB::readRefNodeFile(plod->getFileName(i)+".gles"); + osg::ref_ptr n = osgDB::readRefNodeFile(plod->getDatabasePath() + plod->getFileName(i)+".gles"); if (n) { - std::string filename(osgDB::getStrippedName(plod->getFileName(i))+".osgjs"); - osgDB::writeNodeFile(*n,filename); - fileObject->getMaps()[str] = new JSONValue(filename); + std::string filename(osgDB::getNameLessExtension(plod->getFileName(i))+".osgjs"); + + std::string fullFilePath(osgDB::getFilePath(_baseName) + osgDB::getNativePathSeparator() + filename); + fileObject->getMaps()[str] = new JSONValue(_baseLodURL + filename); + osgDB::makeDirectoryForFile(fullFilePath); + if (_baseLodURL.empty()) + _baseLodURL = osgDB::getFilePath(filename) + osgDB::getNativePathSeparator() ; + osg::ref_ptr options = osgDB::Registry::instance()->getOptions()->cloneOptions(); + options->setPluginStringData(std::string("baseLodURL"), _baseLodURL); + + osgDB::writeNodeFile(*n, fullFilePath, options.get()); + } else fileObject->getMaps()[str] = new JSONValue(""); } jsonPlod->getMaps()["RangeDataList"] = fileObject; - return jsonPlod.get(); + return jsonPlod.release(); } JSONObject* WriteVisitor::createJSONTexture(osg::Texture* texture) @@ -742,7 +938,6 @@ JSONObject* WriteVisitor::createJSONStateSet(osg::StateSet* stateset) osg::ref_ptr jsonStateSet = new JSONStateSet; _maps[stateset] = jsonStateSet; - jsonStateSet->addUniqueID(); translateObject(jsonStateSet.get(), stateset); @@ -826,17 +1021,10 @@ JSONObject* WriteVisitor::createJSONStateSet(osg::StateSet* stateset) attributeList->getArray().push_back(obj); } - if (!attributeList->getArray().empty()) { jsonStateSet->getMaps()["AttributeList"] = attributeList; } - - osg::StateSet::ModeList modeList = stateset->getModeList(); - for (unsigned int i = 0; i < modeList.size(); ++i) { - // add modes - } - if (jsonStateSet->getMaps().empty()) return 0; return jsonStateSet.release(); diff --git a/src/osgPlugins/osgjs/json_stream b/src/osgPlugins/osgjs/json_stream index 750fed322..611a9b088 100644 --- a/src/osgPlugins/osgjs/json_stream +++ b/src/osgPlugins/osgjs/json_stream @@ -19,15 +19,15 @@ #define JSON_STREAM #include -#include -#include // control characters -#include #include #include #include #include +#include "utf8_string" + + using namespace std; // A simple class wrapping ofstream calls to enable generic cleaning of json data. @@ -117,182 +117,13 @@ class json_stream : public osgDB::ofstream { std::string to_json_utf8(const std::string& s) { // TODO: try to decode latin1 if string is not valid utf8 // before actually fixing bad 'chars' - return clean_invalid_utf8(s); + return utf8_string::sanitize(s); } protected: std::ofstream _stream; bool _strict; - - std::string json_encode_control_char(int ctrl) { - // see http://json.org - std::ostringstream oss; - - if(ctrl == 8 || // \b - ctrl == 9 || // \t - ctrl == 10 || // \n - ctrl == 12 || // \f - ctrl == 13 || // \r - ctrl == 27 || // - ctrl == 34 || // \" - ctrl == 47 // \/ - ) { - oss << static_cast(ctrl); - } - else { - oss.fill('0'); - oss << "\\u" << std::setw(4) << std::hex << ctrl; - } - - return oss.str(); - } - - - inline bool is_valid_continuation_byte(unsigned int byte) { - return ((byte & 0xC0) == 0x80); - } - - inline int get_next_byte(std::string::const_iterator& iterator, std::string::const_iterator end_iterator) { - if(iterator != end_iterator) { - return *(++ iterator); - } - else { - return 0; // invalid continuation byte - } - } - - // from http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences - std::string utf8_encode_codepoint(unsigned code_point) - { - std::string output; - - if(code_point > 0x590 && code_point < 0x5F4) { - return output; - } - - // out of range - if(code_point > 1114112) { - return utf8_encode_codepoint(0xfffd); - } - - if (code_point < 0x80) { - output.push_back(code_point); - } - else if (code_point <= 0x7FF) { - output.push_back((code_point >> 6) + 0xC0); - output.push_back((code_point & 0x3F) + 0x80); - } - else if (code_point <= 0xFFFF) { - output.push_back((code_point >> 12) + 0xE0); - output.push_back(((code_point >> 6) & 0x3F) + 0x80); - output.push_back((code_point & 0x3F) + 0x80); - } - else if (code_point <= 0x10FFFF) { - output.push_back((code_point >> 18) + 0xF0); - output.push_back(((code_point >> 12) & 0x3F) + 0x80); - output.push_back(((code_point >> 6) & 0x3F) + 0x80); - output.push_back((code_point & 0x3F) + 0x80); - } - return output; - } - - // from http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences - std::string clean_invalid_utf8(const std::string& input, - const int replacement_codepoint=0xfffd) { - int code_unit1, code_unit2, code_unit3, code_unit4; - std::string output, replacement = utf8_encode_codepoint(replacement_codepoint); - - for(std::string::const_iterator iterator = input.begin() ; iterator != input.end() ; ++ iterator) { - code_unit1 = *iterator; - if (code_unit1 < 0x80) { - if(std::iscntrl(code_unit1)) { - output += json_encode_control_char(code_unit1); - } - else { - output.push_back(code_unit1); - } - } - else if (code_unit1 < 0xC2) { - // continuation or overlong 2-byte sequence - output += replacement; - } - else if (code_unit1 < 0xE0) { - // 2-byte sequence - code_unit2 = get_next_byte(iterator, input.end()); - - if (!is_valid_continuation_byte(code_unit2)) { - output += replacement; - output += replacement; - } - else { - output += utf8_encode_codepoint((code_unit1 << 6) + code_unit2 - 0x3080); - } - } - else if (code_unit1 < 0xF0) { - // 3-byte sequence - code_unit2 = get_next_byte(iterator, input.end()); - - if (!is_valid_continuation_byte(code_unit2) || - (code_unit1 == 0xE0 && code_unit2 < 0xA0)) /* overlong */ { - output += replacement; - output += replacement; - } - else { - code_unit3 = get_next_byte(iterator, input.end()); - - if (!is_valid_continuation_byte(code_unit3)) { - output += replacement; - output += replacement; - output += replacement; - } - else { - output += utf8_encode_codepoint((code_unit1 << 12) + - (code_unit2 << 6) + - code_unit3 - 0xE2080); - } - } - } - else if (code_unit1 < 0xF5) { - // 4-byte sequence - code_unit2 = get_next_byte(iterator, input.end()); - if(!is_valid_continuation_byte(code_unit2) || - (code_unit1 == 0xF0 && code_unit2 < 0x90) || /* overlong */ - (code_unit1 == 0xF4 && code_unit2 >= 0x90)) { /* > U+10FFFF */ - output += replacement; - output += replacement; - } - else { - code_unit3 = get_next_byte(iterator, input.end()); - if(!is_valid_continuation_byte(code_unit3)) { - output += replacement; - output += replacement; - output += replacement; - } - else { - code_unit4 = get_next_byte(iterator, input.end()); - if(!is_valid_continuation_byte(code_unit4)) { - output += replacement; - output += replacement; - output += replacement; - output += replacement; - } - else { - output += utf8_encode_codepoint((code_unit1 << 18) + - (code_unit2 << 12) + - (code_unit3 << 6) + - code_unit4 - 0x3C82080); - } - } - } - } - else { - /* > U+10FFFF */ - output += replacement; - } - } - return output; - } }; diff --git a/src/osgPlugins/osgjs/utf8_string b/src/osgPlugins/osgjs/utf8_string new file mode 100644 index 000000000..5fc8f2df6 --- /dev/null +++ b/src/osgPlugins/osgjs/utf8_string @@ -0,0 +1,187 @@ +#ifndef UTF8_STRING +#define UTF8_STRING + +#include +#include +#include +#include +#include // control characters + + +namespace utf8_string { + inline std::string encode_control_char(unsigned int ctrl) { + // see http://json.org + std::ostringstream oss; + + if(ctrl == 8 || // \b + ctrl == 9 || // \t + ctrl == 10 || // \n + ctrl == 12 || // \f + ctrl == 13 || // \r + ctrl == 27 || // + ctrl == 34 || // \" + ctrl == 47 // \/ + ) { + oss << static_cast(ctrl); + } + else { + oss.fill('0'); + oss << "\\u" << std::setw(4) << std::hex << ctrl; + } + + return oss.str(); + } + + + inline bool is_valid_continuation_byte(unsigned int byte) { + return ((byte & 0xC0) == 0x80); + } + + + inline int get_next_byte(std::string::const_iterator& iterator, std::string::const_iterator end_iterator) { + if(iterator != end_iterator) { + return *(++ iterator); + } + else { + return 0; // invalid continuation byte + } + } + + + // from http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences + inline std::string encode_codepoint(unsigned code_point) + { + std::string output; + + if(code_point > 0x590 && code_point < 0x5F4) { + return output; + } + + // out of range + if(code_point > 1114112) { + return encode_codepoint(0xfffd); + } + + if (code_point < 0x80) { + output.push_back(code_point); + } + else if (code_point <= 0x7FF) { + output.push_back((code_point >> 6) + 0xC0); + output.push_back((code_point & 0x3F) + 0x80); + } + else if (code_point <= 0xFFFF) { + output.push_back((code_point >> 12) + 0xE0); + output.push_back(((code_point >> 6) & 0x3F) + 0x80); + output.push_back((code_point & 0x3F) + 0x80); + } + else if (code_point <= 0x10FFFF) { + output.push_back((code_point >> 18) + 0xF0); + output.push_back(((code_point >> 12) & 0x3F) + 0x80); + output.push_back(((code_point >> 6) & 0x3F) + 0x80); + output.push_back((code_point & 0x3F) + 0x80); + } + return output; + } + + // from http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences + inline std::string clean_invalid(const std::string& input, const int replacement_codepoint=0xfffd) { + unsigned int code_unit1, code_unit2, code_unit3, code_unit4; + std::string output, replacement = encode_codepoint(replacement_codepoint); + + for(std::string::const_iterator iterator = input.begin() ; iterator != input.end() ; ++ iterator) { + code_unit1 = *iterator; + if (code_unit1 < 0x80) { + if(std::iscntrl(code_unit1)) { + output += encode_control_char(code_unit1); + } + else { + output.push_back(code_unit1); + } + } + else if (code_unit1 < 0xC2) { + // continuation or overlong 2-byte sequence + output += replacement; + } + else if (code_unit1 < 0xE0) { + // 2-byte sequence + code_unit2 = get_next_byte(iterator, input.end()); + + if (!is_valid_continuation_byte(code_unit2)) { + output += replacement; + output += replacement; + } + else { + output += encode_codepoint((code_unit1 << 6) + code_unit2 - 0x3080); + } + } + else if (code_unit1 < 0xF0) { + // 3-byte sequence + code_unit2 = get_next_byte(iterator, input.end()); + + if (!is_valid_continuation_byte(code_unit2) || + (code_unit1 == 0xE0 && code_unit2 < 0xA0)) /* overlong */ { + output += replacement; + output += replacement; + } + else { + code_unit3 = get_next_byte(iterator, input.end()); + + if (!is_valid_continuation_byte(code_unit3)) { + output += replacement; + output += replacement; + output += replacement; + } + else { + output += encode_codepoint((code_unit1 << 12) + + (code_unit2 << 6) + + code_unit3 - 0xE2080); + } + } + } + else if (code_unit1 < 0xF5) { + // 4-byte sequence + code_unit2 = get_next_byte(iterator, input.end()); + if(!is_valid_continuation_byte(code_unit2) || + (code_unit1 == 0xF0 && code_unit2 < 0x90) || /* overlong */ + (code_unit1 == 0xF4 && code_unit2 >= 0x90)) { /* > U+10FFFF */ + output += replacement; + output += replacement; + } + else { + code_unit3 = get_next_byte(iterator, input.end()); + if(!is_valid_continuation_byte(code_unit3)) { + output += replacement; + output += replacement; + output += replacement; + } + else { + code_unit4 = get_next_byte(iterator, input.end()); + if(!is_valid_continuation_byte(code_unit4)) { + output += replacement; + output += replacement; + output += replacement; + output += replacement; + } + else { + output += encode_codepoint((code_unit1 << 18) + + (code_unit2 << 12) + + (code_unit3 << 6) + + code_unit4 - 0x3C82080); + } + } + } + } + else { + /* > U+10FFFF */ + output += replacement; + } + } + return output; + } + + + inline std::string sanitize(const std::string& input) { + return clean_invalid(input); + } +} +#endif From 67c301c23672c9dad43f7100f6406e80b85c8fa8 Mon Sep 17 00:00:00 2001 From: Marc Helbling Date: Tue, 5 Jul 2016 16:37:46 +0200 Subject: [PATCH 3/3] Adds specific flag for compressed animation buffers --- src/osgPlugins/osgjs/Animation.cpp | 20 ++++++++++++++++++++ src/osgPlugins/osgjs/CMakeLists.txt | 3 +++ 2 files changed, 23 insertions(+) diff --git a/src/osgPlugins/osgjs/Animation.cpp b/src/osgPlugins/osgjs/Animation.cpp index c9bd1382f..37fe74e48 100644 --- a/src/osgPlugins/osgjs/Animation.cpp +++ b/src/osgPlugins/osgjs/Animation.cpp @@ -240,6 +240,16 @@ static void addJSONChannel(osgAnimation::Channel* channel, JSONObject& anim, Wri } } +#ifdef USE_COMPRESSED_CHANNELS + { + osgAnimation::Vec3usLinearChannel* c = dynamic_cast(channel); + if (c) { + if (addJSONChannel("osgAnimation.Vec3LerpChannelCompressed", c, true, anim, writer, parent)) + return; + } + } +#endif + { osgAnimation::QuatSphericalLinearChannel* c = dynamic_cast(channel); if (c) { @@ -248,6 +258,16 @@ static void addJSONChannel(osgAnimation::Channel* channel, JSONObject& anim, Wri } } +#ifdef USE_COMPRESSED_CHANNELS + { + osgAnimation::Vec3usSphericalLinearChannel* c = dynamic_cast(channel); + if (c) { + if (addJSONChannel("osgAnimation.QuatSlerpChannelCompressed", c, true, anim, writer, parent)) + return; + } + } +#endif + { osgAnimation::FloatCubicBezierChannel* c = dynamic_cast(channel); if (c) { diff --git a/src/osgPlugins/osgjs/CMakeLists.txt b/src/osgPlugins/osgjs/CMakeLists.txt index 615ed46bf..980f644b9 100644 --- a/src/osgPlugins/osgjs/CMakeLists.txt +++ b/src/osgPlugins/osgjs/CMakeLists.txt @@ -16,6 +16,9 @@ SET(TARGET_H WriteVisitor ) +IF($ENV{SKETCHFAB_BUILD}) + ADD_DEFINITIONS(-DUSE_COMPRESSED_CHANNELS) +ENDIF() #### end var setup ### SET(TARGET_ADDED_LIBRARIES