Merge pull request #102 from marchelbling/update_gles+osgjs

Update gles+osgjs.



This PR

    cleans some gles coverity defects (remaining should only be false positive that need to be sorted out cleanly)
    updates osgjs plugin to support serialization; the history of changes is squashed; details can still be found on cedricpinson fork if needed

As compressed animation channels are no longer part of the main repo, I added a compilation flag for the osgjs plugin. The commit is isolated and the flag is not activated by default.
I am yet to find a better solution to make this plugin entirely free from our specific code.

Note: this PR will not change the gles compilation issues. We only compile on OSX/ubuntu and did not encounter any issue with the plugin.
This commit is contained in:
OpenSceneGraph git repository 2016-07-05 17:49:03 +01:00 committed by GitHub
commit 9cd52fc54e
28 changed files with 1506 additions and 740 deletions

View File

@ -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<osgAnimation::RigGeometry*> 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<osg::Drawable::UpdateCallback*>(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<osg::Vec3Array*>((*rigGeometry)->getVertexArray());
osg::Vec3Array *vertices = dynamic_cast<osg::Vec3Array*>(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<osgAnimation::Bone*> _bones;
std::vector<osgAnimation::RigGeometry*> _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<osg::Drawable::UpdateCallback*>(rig->getUpdateCallback());
if(callback) {
callback->update(0, rig);
}
}
}
BoneList _bones;
RigGeometryList _rigGeometries;
osgAnimation::Skeleton *_root;
bool _createGeometry;
};

View File

@ -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<osgAnimation::RigGeometry> 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;
}
}

View File

@ -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 <class T> bool arrayAppendElement(osg::Array* src, unsigned int index, osg::Array* dst)
{
T* array = dynamic_cast<T*>(src);
if (array) {
if (array && dst) {
T* arrayDst = dynamic_cast<T*>(dst);
arrayDst->push_back((*array)[index]);
return true;
@ -140,15 +141,6 @@ struct GeometryArrayList {
if (arrayAppendElement<osg::Vec4Array>(src, index, dst))
return;
if (arrayAppendElement<osg::Vec2Array>(src, index, dst))
return;
if (arrayAppendElement<osg::Vec3Array>(src, index, dst))
return;
if (arrayAppendElement<osg::Vec4Array>(src, index, dst))
return;
if (arrayAppendElement<osg::Vec2bArray>(src, index, dst))
return;
@ -266,15 +258,6 @@ struct GeometryArrayList {
if (arraySetNumElements<osg::Vec4Array>(array, numElements))
return;
if (arraySetNumElements<osg::Vec2Array>(array, numElements))
return;
if (arraySetNumElements<osg::Vec3Array>(array, numElements))
return;
if (arraySetNumElements<osg::Vec4Array>(array, numElements))
return;
if (arraySetNumElements<osg::Vec2bArray>(array, numElements))
return;

View File

@ -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<osgAnimation::MorphGeometry*>(rigGeometry.getSourceGeometry());
if(morph) {

View File

@ -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<unsigned int>::max();
for(IndexCache::const_reverse_iterator cached = cache.rbegin() ; cached != cache.rend() ; ++ cached) {
candidate = findCandidate(graph.triangleNeighbors(*cached), clusters);
if(candidate != std::numeric_limits<unsigned int>::max()) break;

View File

@ -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"

View File

@ -1,3 +1,5 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */
#ifndef GLES_LINE
#define GLES_LINE

View File

@ -49,6 +49,7 @@ public:
_disableMergeTriStrip(false),
_disablePreTransform(false),
_disableAnimation(false),
_disableAnimationCleaning(false),
_enableAABBonBone(false),
_triStripCacheSize(16),
_triStripMinSize(2),

View File

@ -1,3 +1,5 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */
#ifndef PRIMITIVE_OPERATORS_H
#define PRIMITIVE_OPERATORS_H

View File

@ -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

View File

@ -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;
}

View File

@ -1,3 +1,5 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */
#include <vector>
#include <list>
#include <set>
@ -197,7 +199,16 @@ protected:
bool flipped = false;
osg::Vec3Array* normals = dynamic_cast<osg::Vec3Array*>(_geometry.getNormalArray());
for(unsigned int index = 0 ; index < _geometry.getVertexArray()->getNumElements() ; ++ index) {
osg::Vec3Array* positions = dynamic_cast<osg::Vec3Array*>(_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<IndexVector> oneRing = _graph->vertexOneRing(_graph->unify(index), _creaseAngle);
osg::Vec3f smoothedNormal(0.f, 0.f, 0.f);

View File

@ -1,3 +1,5 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */
#ifndef STAT_LOGGER
#define STAT_LOGGER

View File

@ -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<const osgAnimation::MorphGeometry*>(&source)) {
osgAnimation::MorphGeometry* morph = dynamic_cast<osgAnimation::MorphGeometry*>(_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());
}
}
}

View File

@ -1,3 +1,5 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */
#ifndef MESH_GRAPH
#define MESH_GRAPH
@ -171,10 +173,12 @@ public:
_positions(dynamic_cast<const osg::Vec3Array*>(geometry.getVertexArray())),
_comparePosition(comparePosition)
{
unsigned int nbVertex = _positions->getNumElements();
_unique.resize(nbVertex, std::numeric_limits<unsigned int>::max());
_vertexTriangles.resize(nbVertex, IndexVector());
build();
if(_positions) {
unsigned int nbVertex = _positions->getNumElements();
_unique.resize(nbVertex, std::numeric_limits<unsigned int>::max());
_vertexTriangles.resize(nbVertex, IndexVector());
build();
}
}
VertexIterator begin() const {

View File

@ -1,3 +1,5 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */
#ifndef GLES_UTIL
#define GLES_UTIL

View File

@ -0,0 +1,117 @@
/* -*-c++-*-
* Copyright (C) 2010 Cedric Pinson <cedric.pinson@plopbyte.net>
*
* 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 <cedric.pinson@plopbyte.net>
*/
#include <osg/TriangleFunctor>
struct DrawArrayLenghtAdaptor
{
unsigned int _normalArraySize;
const Vec3* _normalArrayPtr;
unsigned int _colorArraySize;
const Vec4* _colorArrayPtr;
std::vector<std::pair<unsigned int, const osg::Vec2*> > _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<DrawArrayLenghtAdaptor>
{
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; current<last ; current+=3) {
this->operator()(current, current+1, current+2,_treatVertexDataAsTemporary);
}
break;
}
case(GL_TRIANGLE_STRIP):
{
unsigned int current = first;
for(GLsizei i=2;i<count;++i, current+=1)
{
if ((i%2)) this->operator()(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;i<count;i+=4,current+=4)
{
this->operator()(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;i<count;i+=2,current+=2)
{
this->operator()(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;i<count;++i,++current)
{
this->operator()(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;
}
}
};

View File

@ -6,7 +6,29 @@
#include <osgAnimation/Animation>
#include <osgAnimation/UpdateMatrixTransform>
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<typename In, typename Out>
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<unsigned int>(.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

View File

@ -1,66 +1,109 @@
/* -*-c++-*-
/* -*-c++-*-
* Copyright (C) 2011 Cedric Pinson <cedric.pinson@plopbyte.com>
*/
#include <osgAnimation/Animation>
#include <osgAnimation/Channel>
#include <osgAnimation/CubicBezier>
#include <osgAnimation/Sampler>
#include <osgAnimation/UpdateMatrixTransform>
#include <osgAnimation/StackedTranslateElement>
#include <osgAnimation/StackedQuaternionElement>
#include <osgAnimation/StackedRotateAxisElement>
#include <osgAnimation/StackedMatrixElement>
#include <osgAnimation/StackedScaleElement>
#include <osg/Array>
#include "JSON_Objects"
#include "WriteVisitor"
static bool addJSONChannelVec3(osgAnimation::Vec3LinearChannel* channel, JSONObject& anim)
{
template<typename T>
struct osg_array
{ typedef osg::Array array_type; };
#define ADD_ARRAY_TYPE(T, A)\
template<> \
struct osg_array<T> \
{ 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<typename T>
bool addJSONChannel(const std::string& channelType, T* channel, bool packByCoords, JSONObject& anim, WriteVisitor* writer, osg::Object* parent) {
if (channel && channel->getSampler()) {
osg::ref_ptr<JSONObject> json = new JSONObject;
std::string jsonType = channelType + (packByCoords ? "Packed" : "");
translateObject(json.get(), channel);
json->getMaps()["Name"] = new JSONValue<std::string>(channel->getName());
json->getMaps()["TargetName"] = new JSONValue<std::string>(channel->getTargetName());
osgAnimation::Vec3KeyframeContainer* keys = channel->getSamplerTyped()->getKeyframeContainerTyped();
JSONKeyframes* jsonKeys = new JSONKeyframes();
//if (!keys->getName().empty()) {
// jsonKeys->getMaps()["Name"] = new JSONValue<std::string>(keys->getName());
//}
typename T::KeyframeContainerType* keys = channel->getSamplerTyped()->getKeyframeContainerTyped();
typedef typename T::UsingType KeyframeType;
typedef typename osg_array<KeyframeType>::array_type KeyframeArray;
osg::ref_ptr<JSONObject> jsKeys = new JSONObject;
osg::ref_ptr<osg::FloatArray> timesArray = new osg::FloatArray;
osg::ref_ptr<KeyframeArray> 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<KeyframeArray> values;
if(packByCoords) { // data channel packing
values = pack<KeyframeArray, KeyframeArray>(valuesArray.get());
}
else {
values = valuesArray;
}
jsKeys->getMaps()["Key"] = writer->createJSONBufferArray(values.get(), parent);
json->getMaps()["KeyFrames"] = jsKeys;
osg::ref_ptr<JSONObject> 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<JSONObject> json = new JSONObject;
json->getMaps()["Name"] = new JSONValue<std::string>(channel->getName());
json->getMaps()["TargetName"] = new JSONValue<std::string>(channel->getTargetName());
osgAnimation::FloatKeyframeContainer* keys = channel->getSamplerTyped()->getKeyframeContainerTyped();
JSONKeyframes* jsonKeys = new JSONKeyframes();
//if (!keys->getName().empty()) {
// jsonKeys->getMaps()["Name"] = new JSONValue<std::string>(keys->getName());
//}
osg::ref_ptr<JSONObject> jsKeys = new JSONObject;
osg::ref_ptr<osg::FloatArray> timesArray = new osg::FloatArray;
osg::ref_ptr<osg::FloatArray> 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<JSONObject> jsonChannel = new JSONObject();
jsonChannel->getMaps()["osgAnimation.FloatLerpChannel"] = json;
anim.getMaps()["Channels"]->asArray()->getArray().push_back(jsonChannel);
@ -69,82 +112,198 @@ 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<JSONObject> json = new JSONObject;
json->getMaps()["Name"] = new JSONValue<std::string>(channel->getName());
json->getMaps()["TargetName"] = new JSONValue<std::string>(channel->getTargetName());
osgAnimation::QuatKeyframeContainer* keys = channel->getSamplerTyped()->getKeyframeContainerTyped();
JSONKeyframes* jsonKeys = new JSONKeyframes();
osgAnimation::FloatCubicBezierKeyframeContainer * keys = channel->getSamplerTyped()->getKeyframeContainerTyped();
osg::ref_ptr<osg::FloatArray> 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<JSONObject> 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<JSONObject> 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<JSONObject> json = new JSONObject;
json->getMaps()["Name"] = new JSONValue<std::string>(channel->getName());
json->getMaps()["TargetName"] = new JSONValue<std::string>(channel->getTargetName());
osgAnimation::Vec3CubicBezierKeyframeContainer * keys = channel->getSamplerTyped()->getKeyframeContainerTyped();
osg::ref_ptr<osg::FloatArray> 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<JSONObject> jsKeys = new JSONObject;
osg::ref_ptr<JSONArray> 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<JSONArray> 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<JSONArray> 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<JSONObject> 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<osgAnimation::Vec3LinearChannel*>(channel);
osgAnimation::FloatLinearChannel* c = dynamic_cast<osgAnimation::FloatLinearChannel*>(channel);
if (c) {
if (addJSONChannelVec3(c, anim))
if (addJSONChannelFloat(c, anim, writer, parent))
return;
}
}
{
osgAnimation::FloatLinearChannel* c = dynamic_cast<osgAnimation::FloatLinearChannel*>(channel);
osgAnimation::Vec3LinearChannel* c = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
if (c) {
if (addJSONChannelFloat(c, anim))
if (addJSONChannel<osgAnimation::Vec3LinearChannel>("osgAnimation.Vec3LerpChannel", c, false, anim, writer, parent))
return;
}
}
#ifdef USE_COMPRESSED_CHANNELS
{
osgAnimation::Vec3usLinearChannel* c = dynamic_cast<osgAnimation::Vec3usLinearChannel*>(channel);
if (c) {
if (addJSONChannel<osgAnimation::Vec3usLinearChannel>("osgAnimation.Vec3LerpChannelCompressed", c, true, anim, writer, parent))
return;
}
}
#endif
{
osgAnimation::QuatSphericalLinearChannel* c = dynamic_cast<osgAnimation::QuatSphericalLinearChannel*>(channel);
if (c) {
if (addJSONChannelQuaternion(c, anim))
if (addJSONChannel<osgAnimation::QuatSphericalLinearChannel>("osgAnimation.QuatSlerpChannel", c, false, anim, writer, parent))
return;
}
}
#ifdef USE_COMPRESSED_CHANNELS
{
osgAnimation::Vec3usSphericalLinearChannel* c = dynamic_cast<osgAnimation::Vec3usSphericalLinearChannel*>(channel);
if (c) {
if (addJSONChannel<osgAnimation::Vec3usSphericalLinearChannel>("osgAnimation.QuatSlerpChannelCompressed", c, true, anim, writer, parent))
return;
}
}
#endif
{
osgAnimation::FloatCubicBezierChannel* c = dynamic_cast<osgAnimation::FloatCubicBezierChannel*>(channel);
if (c) {
if (addJSONChannelFloatCubicBezier(c, anim, writer, parent))
return;
}
}
{
osgAnimation::Vec3CubicBezierChannel *c = dynamic_cast<osgAnimation::Vec3CubicBezierChannel*>(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<JSONObject> json = new JSONObject;
json->addUniqueID();
json->getMaps()["Channels"] = new JSONArray();
json->getMaps()["Name"] = new JSONValue<std::string>(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<JSONObject> json = new JSONObject;
json->addUniqueID();
json->getMaps()["Name"] = new JSONValue<std::string>(acb.getName());
osg::ref_ptr<JSONArray> jsonStackedArray = new JSONArray();
json->getMaps()["StackedTransforms"] = jsonStackedArray;
@ -194,8 +353,41 @@ JSONObject* createJSONUpdateMatrixTransform(osgAnimation::UpdateMatrixTransform&
continue;
}
}
{
osgAnimation::StackedMatrixElement * element = dynamic_cast<osgAnimation::StackedMatrixElement*>(st[i].get());
if (element) {
osg::ref_ptr<JSONObject> jsonElement = new JSONObject;
jsonElement->getMaps()["Name"] = new JSONValue<std::string>(element->getName());
jsonElement->getMaps()["Matrix"] = new JSONMatrix(element->getMatrix());
osg::ref_ptr<JSONObject> jsonElementObject = new JSONObject;
jsonElementObject->getMaps()["osgAnimation.StackedMatrix"] = jsonElement;
jsonStackedArray->getArray().push_back(jsonElementObject);
continue;
}
}
{
osgAnimation::StackedScaleElement * element = dynamic_cast<osgAnimation::StackedScaleElement*>(st[i].get());
if (element) {
osg::ref_ptr<JSONObject> jsonElement = new JSONObject;
jsonElement->getMaps()["Name"] = new JSONValue<std::string>(element->getName());
jsonElement->getMaps()["Scale"] = new JSONVec3Array(element->getScale());
osg::ref_ptr<JSONObject> 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<osgAnimation::UpdateBone*>(&acb)) {
return 0;
}

View File

@ -6,15 +6,20 @@ SET(TARGET_SRC
WriteVisitor.cpp)
SET(TARGET_H
Adaptator
Adaptor
Animation
Base64
CompactBufferVisitor
JSON_Objects
json_stream
utf8_string
WriteVisitor
)
IF($ENV{SKETCHFAB_BUILD})
ADD_DEFINITIONS(-DUSE_COMPRESSED_CHANNELS)
ENDIF()
#### end var setup ###
SET(TARGET_ADDED_LIBRARIES
osgAnimation

View File

@ -22,6 +22,8 @@
#include <osg/Geometry>
#include <osg/Geode>
#include <osgAnimation/RigGeometry>
#include <map>
@ -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<osgAnimation::RigGeometry*>(&geometry);
if(rig && rig->getSourceGeometry()) {
apply(*rig->getSourceGeometry());
}
}

View File

@ -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<std::string, osg::ref_ptr<JSONObject> > JSONMap;
typedef std::vector<std::string> 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<JSONValue<T> * > ( 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<uint8_t>&) const;
template<typename T>
@ -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 <class T>
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<double> : 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<std::string> : public JSONObject
@ -171,35 +140,30 @@ struct JSONValue<std::string> : 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<int>(array.getFirst());
getMaps()["Count"] = new JSONValue<int>(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<int>(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<int>(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 <class T>
struct JSONDrawElements : public JSONObject
struct JSONDrawElements : public JSONObjectWithUniqueID
{
JSONDrawElements(T& array) {
typedef typename BufferArray<T>::type array_type;

View File

@ -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<std::string> 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<unsigned int>(id);
}
JSONObject::JSONObject()
{
_uniqueID = 0xffffffff;
}
void JSONObject::addUniqueID()
{
_uniqueID = JSONObject::uniqueID++;
_maps["UniqueID"] = new JSONValue<unsigned int>(_uniqueID);
if(_maps.find("UniqueID") == _maps.end()) {
_maps["UniqueID"] = new JSONValue<unsigned int>(JSONObject::uniqueID ++);
}
}
unsigned int JSONObject::getUniqueID() const
{
JSONMap::const_iterator iterator = _maps.find("UniqueID");
if(iterator == _maps.end()) {
return 0xffffffff;
}
const JSONValue<unsigned int>* uid = dynamic_cast<JSONValue<unsigned int>*>(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<const osg::Array> array = _arrayData;
switch (array->getType()) {
case osg::Array::QuatArrayType:
{
osg::ref_ptr<osg::Vec4Array> converted = new osg::Vec4Array;
converted->reserve(array->getNumElements());
const osg::QuatArray* a = dynamic_cast<const osg::QuatArray*>(array.get());
for (unsigned int i = 0; i < array->getNumElements(); ++i) {
converted->push_back(osg::Vec4(static_cast<float>((*a)[i][0]),
static_cast<float>((*a)[i][1]),
static_cast<float>((*a)[i][2]),
static_cast<float>((*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<const double*>(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<float>(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<int>(array.getFirst());
getMaps()["Count"] = new JSONValue<int>(array.getCount());
getMaps()["Mode"] = getDrawMode(array.getMode());
}
JSONDrawArrayLengths::JSONDrawArrayLengths(osg::DrawArrayLengths& array)
{
getMaps()["First"] = new JSONValue<int>(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<int>(array[i]));
}
getMaps()["ArrayLengths"] = jsonArray;
}

View File

@ -48,7 +48,7 @@ public:
bool varint;
bool strictJson;
std::vector<std::string> 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<std::string>::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;

View File

@ -14,25 +14,37 @@
#include <osg/PagedLOD>
#include <osg/PositionAttitudeTransform>
#include <osgAnimation/BasicAnimationManager>
#include <osgAnimation/Skeleton>
#include <osg/LightSource>
#include <osg/CullFace>
#include <osg/Material>
#include <osg/BlendColor>
#include <osg/BlendFunc>
#include <osg/ValueObject>
#include <osg/Array>
#include <osgDB/FileNameUtils>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/MorphGeometry>
#include <osgAnimation/Bone>
#include <osgAnimation/UpdateBone>
#include <osgText/Text>
#
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include <sstream>
#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<osg::ref_ptr<osg::StateSet> > StateSetStack;
typedef std::pair<std::string, std::string> KeyValue;
std::map<osg::ref_ptr<osg::Object>, osg::ref_ptr<JSONObject> > _maps;
std::vector<osg::ref_ptr<JSONObject> > _parents;
osg::ref_ptr<JSONObject> _root;
StateSetStack _stateset;
std::string _baseName;
std::string _baseLodURL;
bool _useExternalBinaryArray;
bool _mergeAllBinaryFiles;
bool _inlineImages;
bool _varint;
int _maxTextureDimension;
std::vector<std::string> _specificBuffers;
bool _varint;
std::map<KeyValue, std::string> _specificBuffers;
std::map<std::string, std::ofstream*> _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<std::string, std::ofstream*>::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<KeyValue, std::string>::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<std::string, std::ofstream*>::iterator buffer = _buffers.begin() ;
for(std::map<std::string, std::ofstream*>::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<std::string>::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<KeyValue, std::string>::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<std::string> 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<JSONArray> updateCallbacks = new JSONArray;
osg::ref_ptr<osg::Callback> nc = node.getUpdateCallback();
while (nc) {
osgAnimation::BasicAnimationManager* am = dynamic_cast<osgAnimation::BasicAnimationManager*>(nc.get());
if (am) {
if(osgAnimation::BasicAnimationManager* am = dynamic_cast<osgAnimation::BasicAnimationManager*>(nc.get())) {
osg::ref_ptr<JSONArray> array = new JSONArray;
osg::ref_ptr<JSONObject> bam = new JSONObject;
translateObject(bam.get(), am);
bam->getMaps()["Animations"] = array;
osg::ref_ptr<JSONObject> 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<JSONObject> jsonAnim = createJSONAnimation(am->getAnimationList()[i].get());
osgAnimation::Animation* animation = am->getAnimationList()[i].get();
osg::ref_ptr<JSONObject> jsonAnim = createJSONAnimation(animation, this);
if (jsonAnim) {
translateObject(jsonAnim.get(), animation);
osg::ref_ptr<JSONObject> 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<osgAnimation::UpdateMatrixTransform*>(nc.get());
if (updateMT) {
osg::ref_ptr<JSONObject> jsonCallback = createJSONUpdateMatrixTransform(*updateMT);
if (jsonCallback.valid()) {
osg::ref_ptr<JSONObject> jsonObject = new JSONObject;
jsonObject->getMaps()["osgAnimation.UpdateMatrixTransform"] = jsonCallback;
updateCallbacks->getArray().push_back(jsonObject);
}
}
else if(osgAnimation::UpdateBone* upBone = dynamic_cast<osgAnimation::UpdateBone*>(nc.get())) {
osg::ref_ptr<JSONObject> jsonCallback = createJSONUpdateMatrixTransform(*upBone, this);
if (jsonCallback.valid()) {
osg::ref_ptr<JSONObject> jsonObject = new JSONObject;
jsonObject->getMaps()["osgAnimation.UpdateBone"] = jsonCallback;
updateCallbacks->getArray().push_back(jsonObject);
}
}
else if(osgAnimation::UpdateMatrixTransform* updateMT = dynamic_cast<osgAnimation::UpdateMatrixTransform*>(nc.get())) {
osg::ref_ptr<JSONObject> jsonCallback = createJSONUpdateMatrixTransform(*updateMT, this);
if (jsonCallback.valid()) {
osg::ref_ptr<JSONObject> jsonObject = new JSONObject;
jsonObject->getMaps()["osgAnimation.UpdateMatrixTransform"] = jsonCallback;
updateCallbacks->getArray().push_back(jsonObject);
}
}
else if(dynamic_cast<osgAnimation::Skeleton::UpdateSkeleton*>(nc.get())) {
osg::ref_ptr<JSONObject> json = new JSONNode;
osg::ref_ptr<JSONObject> jsonObject = new JSONObject;
_maps[&node] = json;
jsonObject->getMaps()["osgAnimation.UpdateSkeleton"] = json;
updateCallbacks->getArray().push_back(jsonObject);
}
else if(osgAnimation::UpdateMorph* updateMorph = dynamic_cast<osgAnimation::UpdateMorph*>(nc.get())) {
osg::ref_ptr<JSONObject> json = new JSONNode;
osg::ref_ptr<JSONObject> jsonObject = new JSONObject;
osg::ref_ptr<JSONObject> jsonTargetName = new JSONObject;
json->getMaps()["Name"] = new JSONValue<std::string>(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<std::string>(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<osg::Geometry*>(&drw);
if (geom) {
JSONObject* json = createJSONGeometry(geom);
void apply(osg::Drawable& drawable) {
if(osgAnimation::RigGeometry * rigGeometry = dynamic_cast<osgAnimation::RigGeometry*>(&drawable)) {
JSONObject* json = createJSONRigGeometry(rigGeometry);
translateObject(json, rigGeometry);
JSONObject* parent = getParent();
parent->addChild("osgAnimation.RigGeometry", json);
}
else if(osgAnimation::MorphGeometry * morphGeometry = dynamic_cast<osgAnimation::MorphGeometry*>(&drawable)) {
JSONObject* json = createJSONMorphGeometry(morphGeometry);
JSONObject* parent = getParent();
parent->addChild("osgAnimation.MorphGeometry", json);
}
else if(osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(&drawable)) {
JSONObject* json = createJSONGeometry(geometry);
JSONObject* parent = getParent();
parent->addChild("osg.Geometry", json);
}
else if(osgText::Text* text = dynamic_cast<osgText::Text*>(&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<JSONObject> json = new JSONNode;
json->addUniqueID();
_maps[&node] = json;
applyCallback(node, json.get());
@ -298,7 +422,6 @@ public:
}
osg::ref_ptr<JSONObject> json = new JSONNode;
json->addUniqueID();
_maps[&node] = json;
parent->addChild("osg.Node", json.get());
@ -346,7 +469,6 @@ public:
}
osg::ref_ptr<JSONObject> json = new JSONNode;
json->addUniqueID();
_maps[&node] = json;
applyCallback(node, json.get());
@ -375,7 +497,6 @@ public:
}
osg::ref_ptr<JSONObject> 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<JSONObject> &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<JSONObject> 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<osgAnimation::Skeleton*>(&node)) {
apply(static_cast<osgAnimation::Skeleton&>(node));
return;
}
if (dynamic_cast<osgAnimation::Bone*>(&node)) {
apply(static_cast<osgAnimation::Bone&>(node));
return;
}
JSONObject* parent = getParent();
if (_maps.find(&node) != _maps.end()) {
parent->addChild("osg.MatrixTransform", _maps[&node]->getShadowObject());
return;
}
osg::ref_ptr<JSONObject> 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<JSONObject> 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<JSONObject> 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<JSONObject> 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

View File

@ -10,10 +10,14 @@
#include <osg/Types>
#include <osg/Material>
#include <osg/BlendFunc>
#include <osgSim/ShapeAttribute>
#include "Base64"
#include <osgText/Text>
#include <osgAnimation/MorphGeometry>
#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<JSONObject> buildRigBoneMap(osgAnimation::RigGeometry& rigGeometry) {
osg::Array* bones = getAnimationBonesArray(rigGeometry);
osg::ref_ptr<JSONObject> 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<int>(paletteIndex);
++ paletteIndex;
}
return boneMap;
}
void translateObject(JSONObject* json, osg::Object* osg)
{
if (!osg->getName().empty()) {
@ -150,6 +199,7 @@ static JSONValue<std::string>* getBlendFuncMode(GLenum mode) {
default:
return new JSONValue<std::string>("ONE");
}
return new JSONValue<std::string>("ONE");
}
static JSONValue<std::string>* getJSONFilterMode(osg::Texture::FilterMode mode)
@ -194,6 +244,44 @@ static JSONValue<std::string>* getJSONWrapMode(osg::Texture::WrapMode mode)
return 0;
}
static JSONValue<std::string>* getJSONAlignmentType(osgText::Text::AlignmentType type)
{
switch(type) {
case osgText::Text::LEFT_TOP:
return new JSONValue<std::string>("LEFT_TOP");
case osgText::Text::LEFT_CENTER:
return new JSONValue<std::string>("LEFT_CENTER");
case osgText::Text::LEFT_BOTTOM:
return new JSONValue<std::string>("LEFT_BOTTOM");
case osgText::Text::CENTER_TOP:
return new JSONValue<std::string>("CENTER_TOP");
case osgText::Text::CENTER_CENTER:
return new JSONValue<std::string>("CENTER_CENTER");
case osgText::Text::CENTER_BOTTOM:
return new JSONValue<std::string>("CENTER_BOTTOM");
case osgText::Text::RIGHT_TOP:
return new JSONValue<std::string>("RIGHT_TOP");
case osgText::Text::RIGHT_CENTER:
return new JSONValue<std::string>("RIGHT_CENTER");
case osgText::Text::RIGHT_BOTTOM:
return new JSONValue<std::string>("RIGHT_BOTTOM");
case osgText::Text::LEFT_BASE_LINE:
return new JSONValue<std::string>("LEFT_BASE_LINE");
case osgText::Text::CENTER_BASE_LINE:
return new JSONValue<std::string>("CENTER_BASE_LINE");
case osgText::Text::RIGHT_BASE_LINE:
return new JSONValue<std::string>("RIGHT_BASE_LINE");
case osgText::Text::LEFT_BOTTOM_BASE_LINE:
return new JSONValue<std::string>("LEFT_BOTTOM_BASE_LINE");
case osgText::Text::CENTER_BOTTOM_BASE_LINE:
return new JSONValue<std::string>("CENTER_BOTTOM_BASE_LINE");
case osgText::Text::RIGHT_BOTTOM_BASE_LINE:
return new JSONValue<std::string>("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<unsigned char> rawData;
rawData.resize(size);
in.read(reinterpret_cast<char*>(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<char>(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<JSONBufferArray> 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<osg::DrawElementsUInt>* json = new JSONDrawElements<osg::DrawElementsUInt>(*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<osg::DrawElementsUShort>* json = new JSONDrawElements<osg::DrawElementsUShort>(*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<osg::DrawElementsUByte>* json = new JSONDrawElements<osg::DrawElementsUByte>(*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<osg::DrawElementsUShort>* json = new JSONDrawElements<osg::DrawElementsUShort>(*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<JSONDrawArray> 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<JSONDrawArrayLengths> 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<JSONObject> json = new JSONNode;
osg::ref_ptr<JSONObject> 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<JSONObject> 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<JSONArray> primitives = new JSONArray();
for (unsigned int i = 0; i < geom->getNumPrimitiveSets(); ++i) {
for (unsigned int i = 0; i < geometry->getNumPrimitiveSets(); ++i) {
osg::ref_ptr<JSONObject> 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<osg::DrawElementsUShort*>((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<osg::DrawElementsUByte*>((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<osg::DrawArrayLengths*>((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<JSONObject> 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<JSONObject> json = new JSONObject;
json->addUniqueID();
osg::ref_ptr<JSONObject> sourceGeometry = new JSONObject;
if(osgAnimation::MorphGeometry *morphGeometry = dynamic_cast<osgAnimation::MorphGeometry*>(rigGeometry->getSourceGeometry())) {
sourceGeometry->getMaps()["osgAnimation.MorphGeometry"] = createJSONMorphGeometry(morphGeometry, rigGeometry);
}
else {
osg::Geometry *geometry = dynamic_cast<osg::Geometry*>(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<JSONObject> 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<osg::Geometry*>(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<JSONValue<std::string> > mode = new JSONValue<std::string>("BACK");
if (sa->getMode() == osg::CullFace::FRONT) {
mode = new JSONValue<std::string>("BACK");
mode = new JSONValue<std::string>("FRONT");
}
if (sa->getMode() == osg::CullFace::FRONT_AND_BACK) {
mode = new JSONValue<std::string>("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<JSONObject> 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<JSONObject> jsonLight = new JSONLight;
jsonLight->addUniqueID();
_maps[light] = jsonLight;
translateObject(jsonLight.get(), light);
@ -617,6 +780,33 @@ template <class T> 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<JSONObject> jsonText = new JSONObject;
jsonText->addUniqueID();
_maps[text] = jsonText;
jsonText->getMaps()["Text"] = new JSONValue<std::string>( 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<float>(text->getCharacterHeight() );
jsonText->getMaps()["AutoRotateToScreen"] = new JSONValue<int>(text->getAutoRotateToScreen() );
jsonText->getMaps()["Alignment"] = getJSONAlignmentType(text->getAlignment());
osg::ref_ptr<JSONValue<std::string> > layout = new JSONValue<std::string>("LEFT_TO_RIGHT");
if (text->getLayout() == osgText::Text::RIGHT_TO_LEFT) {
layout = new JSONValue<std::string>("RIGHT_TO_LEFT");
}
if (text->getLayout() == osgText::Text::VERTICAL) {
layout = new JSONValue<std::string>("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<JSONObject> jsonPlod = new JSONNode;
jsonPlod->addUniqueID();
_maps[plod] = jsonPlod;
// Center Mode
osg::ref_ptr<JSONValue<std::string> > centerMode = new JSONValue<std::string>("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<JSONArray> rangeList = new JSONArray;
JSONObject* rangeObject = new JSONObject;
osg::ref_ptr<JSONObject> 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<JSONObject> 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<osg::Node> n = osgDB::readRefNodeFile(plod->getFileName(i)+".gles");
osg::ref_ptr<osg::Node> 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<std::string>(filename);
std::string filename(osgDB::getNameLessExtension(plod->getFileName(i))+".osgjs");
std::string fullFilePath(osgDB::getFilePath(_baseName) + osgDB::getNativePathSeparator() + filename);
fileObject->getMaps()[str] = new JSONValue<std::string>(_baseLodURL + filename);
osgDB::makeDirectoryForFile(fullFilePath);
if (_baseLodURL.empty())
_baseLodURL = osgDB::getFilePath(filename) + osgDB::getNativePathSeparator() ;
osg::ref_ptr<osgDB::Options> options = osgDB::Registry::instance()->getOptions()->cloneOptions();
options->setPluginStringData(std::string("baseLodURL"), _baseLodURL);
osgDB::writeNodeFile(*n, fullFilePath, options.get());
}
else
fileObject->getMaps()[str] = new JSONValue<std::string>("");
}
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<JSONObject> 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();

View File

@ -19,15 +19,15 @@
#define JSON_STREAM
#include <iostream>
#include <iomanip>
#include <cctype> // control characters
#include <sstream>
#include <string>
#include <cmath>
#include <limits>
#include <osgDB/fstream>
#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<char>(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;
}
};

View File

@ -0,0 +1,187 @@
#ifndef UTF8_STRING
#define UTF8_STRING
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <cctype> // 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<unsigned char>(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