diff --git a/simgear/scene/model/ModelRegistry.cxx b/simgear/scene/model/ModelRegistry.cxx index d65efbb0..58c5bc37 100644 --- a/simgear/scene/model/ModelRegistry.cxx +++ b/simgear/scene/model/ModelRegistry.cxx @@ -314,7 +314,9 @@ OptimizeModelPolicy::OptimizeModelPolicy(const string& extension) : _osgOptions(Optimizer::SHARE_DUPLICATE_STATE | Optimizer::MERGE_GEOMETRY | Optimizer::FLATTEN_STATIC_TRANSFORMS - | Optimizer::TRISTRIP_GEOMETRY) + | Optimizer::INDEX_MESH + | Optimizer::VERTEX_POSTTRANSFORM + | Optimizer::VERTEX_PRETRANSFORM) { } diff --git a/simgear/scene/model/animation.cxx b/simgear/scene/model/animation.cxx index f8bfbcbd..78b0d414 100644 --- a/simgear/scene/model/animation.cxx +++ b/simgear/scene/model/animation.cxx @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -655,7 +657,9 @@ public: SGExpressiond const* animationValue) : _condition(condition), _animationValue(animationValue) - { } + { + setName("SGTranslateAnimation::UpdateCallback"); + } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { if (!_condition || _condition->test()) { @@ -722,60 +726,129 @@ SGTranslateAnimation::createAnimationGroup(osg::Group& parent) // Implementation of rotate/spin animation //////////////////////////////////////////////////////////////////////// -class SGRotateAnimation::UpdateCallback : public osg::NodeCallback { +//Cull callback +class RotAnimCallback : public osg::NodeCallback +{ public: - UpdateCallback(SGCondition const* condition, - SGExpressiond const* animationValue) : - _condition(condition), - _animationValue(animationValue) - { } - virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - if (!_condition || _condition->test()) { - SGRotateTransform* transform; - transform = static_cast(node); - transform->setAngleDeg(_animationValue->getValue()); - } - traverse(node, nv); - } + RotAnimCallback(SGCondition const* condition, + SGExpressiond const* animationValue, + double initialValue = 0.0) : + _condition(condition), + _animationValue(animationValue), + _initialValue(initialValue), + _lastValue(0.0) + { } + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); public: - SGSharedPtr _condition; - SGSharedPtr _animationValue; + SGSharedPtr _condition; + SGSharedPtr _animationValue; + double _initialValue; + double _lastValue; }; -class SGRotateAnimation::SpinUpdateCallback : public osg::NodeCallback { +void RotAnimCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) +{ + using namespace osg; + SGRotateTransform* transform = static_cast(node); + EffectCullVisitor* cv = dynamic_cast(nv); + + if (!cv) + return; + double angle = 0.0; + if (!_condition || _condition->test()) { + angle = _animationValue->getValue() - _initialValue; + _lastValue = angle; + } else { + angle = _lastValue; + } + const SGVec3d& sgcenter = transform->getCenter(); + const SGVec3d& sgaxis = transform->getAxis(); + Matrixd mat = Matrixd::translate(-sgcenter[0], -sgcenter[1], -sgcenter[2]) + * Matrixd::rotate(SGMiscd::deg2rad(angle), sgaxis[0], sgaxis[1], sgaxis[2]) + * Matrixd::translate(sgcenter[0], sgcenter[1], sgcenter[2]) + * *cv->getModelViewMatrix(); + ref_ptr refmat = new RefMatrix(mat); + cv->pushModelViewMatrix(refmat.get(), transform->getReferenceFrame()); + traverse(transform, nv); + cv->popModelViewMatrix(); +} + +// Cull callback +class SpinAnimCallback : public osg::NodeCallback { public: - SpinUpdateCallback(SGCondition const* condition, - SGExpressiond const* animationValue) : + SpinAnimCallback(SGCondition const* condition, + SGExpressiond const* animationValue, + double initialValue = 0.0) : _condition(condition), _animationValue(animationValue), - _lastTime(-1) - { } - virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - if (!_condition || _condition->test()) { - SGRotateTransform* transform; - transform = static_cast(node); - - double t = nv->getFrameStamp()->getReferenceTime(); - double dt = 0; - if (0 <= _lastTime) - dt = t - _lastTime; - _lastTime = t; - double velocity_rpms = _animationValue->getValue()/60; - double angle = transform->getAngleDeg(); - angle += dt*velocity_rpms*360; - angle -= 360*floor(angle/360); - transform->setAngleDeg(angle); - } - traverse(node, nv); - } + _initialValue(initialValue) + {} + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); public: - SGSharedPtr _condition; - SGSharedPtr _animationValue; - double _lastTime; + SGSharedPtr _condition; + SGSharedPtr _animationValue; + double _initialValue; +protected: + // This cull callback can run in different threads if there is + // more than one camera. It is probably safe to overwrite the + // reference values in multiple threads, but we'll provide a + // threadsafe way to manage those values just to be safe. + struct ReferenceValues { + ReferenceValues(double t, double rot, double vel) + : _time(t), _rotation(rot), _rotVelocity(vel) + { + } + double _time; + double _rotation; + double _rotVelocity; + }; + OpenThreads::AtomicPtr _referenceValues; }; +void SpinAnimCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) +{ + using namespace osg; + SGRotateTransform* transform = static_cast(node); + EffectCullVisitor* cv = dynamic_cast(nv); + if (!cv) + return; + if (!_condition || _condition->test()) { + double t = nv->getFrameStamp()->getReferenceTime(); + double rps = _animationValue->getValue() / 60.0; + ReferenceValues* refval = static_cast(_referenceValues.get()); + if (!refval || refval->_rotVelocity != rps) { + ReferenceValues* newref = 0; + if (!refval) { + // initialization + newref = new ReferenceValues(t, 0.0, rps); + } else { + double newRot = refval->_rotation + (t - refval->_time) * refval->_rotVelocity; + newref = new ReferenceValues(t, newRot, rps); + } + if (_referenceValues.assign(newref, refval)) { + delete refval; + } + refval = newref; + } + double rotation = refval->_rotation + (t - refval->_time) * rps; + double intPart; + double rot = modf(rotation, &intPart); + double angle = rot * 2.0 * osg::PI; + const SGVec3d& sgcenter = transform->getCenter(); + const SGVec3d& sgaxis = transform->getAxis(); + Matrixd mat = Matrixd::translate(-sgcenter[0], -sgcenter[1], -sgcenter[2]) + * Matrixd::rotate(angle, sgaxis[0], sgaxis[1], sgaxis[2]) + * Matrixd::translate(sgcenter[0], sgcenter[1], sgcenter[2]) + * *cv->getModelViewMatrix(); + ref_ptr refmat = new RefMatrix(mat); + cv->pushModelViewMatrix(refmat.get(), transform->getReferenceFrame()); + traverse(transform, nv); + cv->popModelViewMatrix(); + } else { + traverse(transform, nv); + } +} + SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode, SGPropertyNode* modelRoot) : SGAnimation(configNode, modelRoot) @@ -792,7 +865,6 @@ SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode, _initialValue = _animationValue->getValue(); else _initialValue = 0; - _center = SGVec3d::zeros(); if (configNode->hasValue("axis/x1-m")) { SGVec3d v1, v2; @@ -823,12 +895,12 @@ SGRotateAnimation::createAnimationGroup(osg::Group& parent) SGRotateTransform* transform = new SGRotateTransform; transform->setName("rotate animation"); if (_isSpin) { - SpinUpdateCallback* uc; - uc = new SpinUpdateCallback(_condition, _animationValue); - transform->setUpdateCallback(uc); + SpinAnimCallback* cc; + cc = new SpinAnimCallback(_condition, _animationValue, _initialValue); + transform->setCullCallback(cc); } else if (_animationValue || !_animationValue->isConst()) { - UpdateCallback* uc = new UpdateCallback(_condition, _animationValue); - transform->setUpdateCallback(uc); + RotAnimCallback* cc = new RotAnimCallback(_condition, _animationValue, _initialValue); + transform->setCullCallback(cc); } transform->setCenter(_center); transform->setAxis(_axis); @@ -851,6 +923,7 @@ public: _animationValue[0] = animationValue[0]; _animationValue[1] = animationValue[1]; _animationValue[2] = animationValue[2]; + setName("SGScaleAnimation::UpdateCallback"); } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { @@ -1373,7 +1446,9 @@ public: _maxAnimationValue(maxAnimationValue), _minStaticValue(minValue), _maxStaticValue(maxValue) - {} + { + setName("SGRangeAnimation::UpdateCallback"); + } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { osg::LOD* lod = static_cast(node); @@ -1629,7 +1704,9 @@ public: UpdateCallback(const SGPropertyNode* configNode, const SGExpressiond* v) : _prev_value(-1), _animationValue(v) - { } + { + setName("SGBlendAnimation::UpdateCallback"); + } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { double blend = _animationValue->getValue(); @@ -1708,6 +1785,7 @@ public: rNode->getDoubleValue( "max", 1)); } } + setName("SGTimedAnimation::UpdateCallback"); } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { @@ -1796,7 +1874,9 @@ class SGShadowAnimation::UpdateCallback : public osg::NodeCallback { public: UpdateCallback(const SGCondition* condition) : _condition(condition) - {} + { + setName("SGShadowAnimation::UpdateCallback"); + } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { if (_condition->test()) @@ -1889,7 +1969,9 @@ class SGTexTransformAnimation::UpdateCallback : public: UpdateCallback(const SGCondition* condition) : _condition(condition) - { } + { + setName("SGTexTransformAnimation::UpdateCallback"); + } virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor*) { if (!_condition || _condition->test()) { diff --git a/simgear/scene/model/animation.hxx b/simgear/scene/model/animation.hxx index fade108c..197ddd53 100644 --- a/simgear/scene/model/animation.hxx +++ b/simgear/scene/model/animation.hxx @@ -136,8 +136,6 @@ public: SGPropertyNode* modelRoot); virtual osg::Group* createAnimationGroup(osg::Group& parent); private: - class UpdateCallback; - class SpinUpdateCallback; SGSharedPtr _condition; SGSharedPtr _animationValue; SGVec3d _axis; diff --git a/simgear/scene/tgdb/TreeBin.cxx b/simgear/scene/tgdb/TreeBin.cxx index 15085d6d..f8e31e6f 100644 --- a/simgear/scene/tgdb/TreeBin.cxx +++ b/simgear/scene/tgdb/TreeBin.cxx @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -281,6 +282,42 @@ struct TreeTransformer Matrix mat; }; +// We may end up with a quadtree with many empty leaves. One might say +// that we should avoid constructing the leaves in the first place, +// but this node visitor tries to clean up after the fact. + +struct QuadTreeCleaner : public osg::NodeVisitor +{ + QuadTreeCleaner() : NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN) + { + } + void apply(LOD& lod) + { + for (int i = lod.getNumChildren() - 1; i >= 0; --i) { + EffectGeode* geode = dynamic_cast(lod.getChild(i)); + if (!geode) + continue; + bool geodeEmpty = true; + for (unsigned j = 0; j < geode->getNumDrawables(); ++j) { + const Geometry* geom = dynamic_cast(geode->getDrawable(j)); + if (!geom) { + geodeEmpty = false; + break; + } + for (unsigned k = 0; k < geom->getNumPrimitiveSets(); k++) { + const PrimitiveSet* ps = geom->getPrimitiveSet(k); + if (ps->getNumIndices() > 0) { + geodeEmpty = false; + break; + } + } + } + if (geodeEmpty) + lod.removeChildren(i, 1); + } + } +}; + // This actually returns a MatrixTransform node. If we rotate the whole // forest into the local Z-up coordinate system we can reuse the // primitive tree geometry for all the forests of the same type. @@ -342,8 +379,10 @@ osg::Group* createForest(SGTreeBinList& forestList, const osg::Matrix& transform } forestList.clear(); - + QuadTreeCleaner cleaner; + mt->accept(cleaner); return mt; } + }