diff --git a/simgear/canvas/Canvas.cxx b/simgear/canvas/Canvas.cxx index a94dd679..9b3ae44c 100644 --- a/simgear/canvas/Canvas.cxx +++ b/simgear/canvas/Canvas.cxx @@ -22,8 +22,10 @@ #include "CanvasEventManager.hxx" #include "CanvasEventVisitor.hxx" #include "CanvasPlacement.hxx" + #include #include +#include #include #include @@ -32,9 +34,6 @@ #include #include -#include -#include - namespace simgear { namespace canvas @@ -64,18 +63,9 @@ namespace canvas //---------------------------------------------------------------------------- Canvas::Canvas(SGPropertyNode* node): PropertyBasedElement(node), - _canvas_mgr(0), _event_manager(new EventManager), - _size_x(-1), - _size_y(-1), - _view_width(-1), - _view_height(-1), _status(node, "status"), - _status_msg(node, "status-msg"), - _sampling_dirty(false), - _render_dirty(true), - _visible(true), - _render_always(false) + _status_msg(node, "status-msg") { _status = 0; setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y); @@ -236,6 +226,10 @@ namespace canvas if( _status & STATUS_DIRTY ) { + // Retrieve reference here, to ensure the scene group is not deleted while + // creating the new texture and camera + osg::ref_ptr root_scene_group = _root_group->getSceneGroup(); + _texture.setSize(_size_x, _size_y); if( !_texture.serviceable() ) @@ -261,7 +255,7 @@ namespace canvas parseColor(_node->getStringValue("background"), clear_color); camera->setClearColor(clear_color); - camera->addChild(_root_group->getMatrixTransform()); + camera->addChild(root_scene_group); if( _texture.serviceable() ) { @@ -281,7 +275,7 @@ namespace canvas if( _visible || _render_always ) { - BOOST_FOREACH(CanvasWeakPtr canvas_weak, _child_canvases) + for(auto& canvas_weak: _child_canvases) { // TODO should we check if the image the child canvas is displayed // within is really visible? @@ -293,7 +287,7 @@ namespace canvas if( _render_dirty ) { // Also mark all canvases this canvas is displayed within as dirty - BOOST_FOREACH(CanvasWeakPtr canvas_weak, _parent_canvases) + for(auto& canvas_weak: _parent_canvases) { CanvasPtr canvas = canvas_weak.lock(); if( canvas ) @@ -522,8 +516,8 @@ namespace canvas { const std::string& name = node->getNameString(); - if( boost::starts_with(name, "status") - || boost::starts_with(name, "data-") ) + if( strutils::starts_with(name, "status") + || strutils::starts_with(name, "data-") ) return; _render_dirty = true; @@ -538,7 +532,7 @@ namespace canvas if( !placements.empty() ) { bool placement_dirty = false; - BOOST_FOREACH(PlacementPtr& placement, placements) + for(auto& placement: placements) { // check if change can be directly handled by placement if( placement->getProps() == node->getParent() diff --git a/simgear/canvas/Canvas.hxx b/simgear/canvas/Canvas.hxx index efcb0a47..6e02b247 100644 --- a/simgear/canvas/Canvas.hxx +++ b/simgear/canvas/Canvas.hxx @@ -33,7 +33,7 @@ #include #include -#include +#include #include namespace simgear @@ -211,21 +211,21 @@ namespace canvas protected: - CanvasMgr *_canvas_mgr; + CanvasMgr *_canvas_mgr {nullptr}; - boost::scoped_ptr _event_manager; + std::unique_ptr _event_manager; - int _size_x, - _size_y, - _view_width, - _view_height; + int _size_x {-1}, + _size_y {-1}, + _view_width {-1}, + _view_height {-1}; PropertyObject _status; PropertyObject _status_msg; - bool _sampling_dirty, - _render_dirty, - _visible; + bool _sampling_dirty {false}, + _render_dirty {true}, + _visible {true}; ODGauge _texture; @@ -235,7 +235,9 @@ namespace canvas ElementWeakPtr _focus_element; CullCallbackPtr _cull_callback; - bool _render_always; //!< Used to disable automatic lazy rendering (culling) + + /** Used to disable automatic lazy rendering (culling) */ + bool _render_always {false}; std::vector _dirty_placements; std::vector _placements; diff --git a/simgear/canvas/CanvasWindow.cxx b/simgear/canvas/CanvasWindow.cxx index 46774a6e..0e6b52bd 100644 --- a/simgear/canvas/CanvasWindow.cxx +++ b/simgear/canvas/CanvasWindow.cxx @@ -22,13 +22,11 @@ #include "CanvasWindow.hxx" #include +#include #include #include -#include -#include - namespace simgear { namespace canvas @@ -43,9 +41,6 @@ namespace canvas const Style& parent_style, Element* parent ): Image(canvas, node, parent_style, parent), - _attributes_dirty(0), - _resizable(false), - _capture_events(true), _resize_top(node, "resize-top"), _resize_right(node, "resize-right"), _resize_bottom(node, "resize-bottom"), @@ -92,7 +87,7 @@ namespace canvas _capture_events = node->getBoolValue(); else if( name == "decoration-border" ) parseDecorationBorder(node->getStringValue()); - else if( boost::starts_with(name, "shadow-") + else if( strutils::starts_with(name, "shadow-") || name == "content-size" ) _attributes_dirty |= DECORATION; else @@ -103,16 +98,10 @@ namespace canvas Image::valueChanged(node); } - //---------------------------------------------------------------------------- - osg::Group* Window::getGroup() - { - return getMatrixTransform(); - } - //---------------------------------------------------------------------------- const SGVec2 Window::getPosition() const { - const osg::Matrix& m = getMatrixTransform()->getMatrix(); + auto const& m = getMatrix(); return SGVec2( m(3, 0), m(3, 1) ); } diff --git a/simgear/canvas/CanvasWindow.hxx b/simgear/canvas/CanvasWindow.hxx index 330b6fb8..1605164f 100644 --- a/simgear/canvas/CanvasWindow.hxx +++ b/simgear/canvas/CanvasWindow.hxx @@ -70,7 +70,6 @@ namespace canvas virtual void update(double delta_time_sec); virtual void valueChanged(SGPropertyNode* node); - osg::Group* getGroup(); const SGVec2 getPosition() const; const SGRect getScreenRegion() const; @@ -104,7 +103,7 @@ namespace canvas DECORATION = 1 }; - uint32_t _attributes_dirty; + uint32_t _attributes_dirty {0}; CanvasPtr _canvas_decoration; CanvasWeakPtr _canvas_content; @@ -113,8 +112,8 @@ namespace canvas ImagePtr _image_content, _image_shadow; - bool _resizable, - _capture_events; + bool _resizable {false}, + _capture_events {true}; PropertyObject _resize_top, _resize_right, diff --git a/simgear/canvas/elements/CanvasElement.cxx b/simgear/canvas/elements/CanvasElement.cxx index a8557a06..7efcd6f0 100644 --- a/simgear/canvas/elements/CanvasElement.cxx +++ b/simgear/canvas/elements/CanvasElement.cxx @@ -31,10 +31,6 @@ #include #include -#include -#include -#include - #include #include #include @@ -214,22 +210,22 @@ namespace canvas //---------------------------------------------------------------------------- void Element::onDestroy() { - if( !_transform.valid() ) + if( !_scene_group.valid() ) return; // The transform node keeps a reference on this element, so ensure it is // deleted. - BOOST_FOREACH(osg::Group* parent, _transform->getParents()) + for(osg::Group* parent: _scene_group->getParents()) { - parent->removeChild(_transform.get()); + parent->removeChild(_scene_group.get()); } // Hide in case someone still holds a reference setVisible(false); removeListener(); - _parent = 0; - _transform = 0; + _parent = nullptr; + _scene_group = nullptr; } //---------------------------------------------------------------------------- @@ -247,29 +243,8 @@ namespace canvas //---------------------------------------------------------------------------- void Element::update(double dt) { - if( !isVisible() ) - return; - - // Trigger matrix update - getMatrix(); - - // Update bounding box on manual update (manual updates pass zero dt) - if( dt == 0 && _drawable ) - _drawable->getBound(); - - if( (_attributes_dirty & BLEND_FUNC) && _transform.valid() ) - { - parseBlendFunc( - _transform->getOrCreateStateSet(), - _node->getChild("blend-source"), - _node->getChild("blend-destination"), - _node->getChild("blend-source-rgb"), - _node->getChild("blend-destination-rgb"), - _node->getChild("blend-source-alpha"), - _node->getChild("blend-destination-alpha") - ); - _attributes_dirty &= ~BLEND_FUNC; - } + if( isVisible() ) + updateImpl(dt); } //---------------------------------------------------------------------------- @@ -341,7 +316,8 @@ namespace canvas if( listeners == _listener.end() ) return false; - BOOST_FOREACH(EventListener const& listener, listeners->second) + for(auto const& listener: listeners->second) + { try { listener(event); @@ -354,6 +330,7 @@ namespace canvas "canvas::Element: event handler error: '" << ex.what() << "'" ); } + } return true; } @@ -395,9 +372,9 @@ namespace canvas getBoundingBox() #endif .contains(osg::Vec3f(local_pos, 0)); - else if( _transform.valid() ) + else if( _scene_group.valid() ) // ... for other elements, i.e. groups only a bounding sphere is available - return _transform->getBound().contains(osg::Vec3f(parent_pos, 0)); + return _scene_group->getBound().contains(osg::Vec3f(parent_pos, 0)); else return false; } @@ -406,35 +383,32 @@ namespace canvas //---------------------------------------------------------------------------- void Element::setVisible(bool visible) { - if( _transform.valid() ) + if( _scene_group.valid() ) // TODO check if we need another nodemask - _transform->setNodeMask(visible ? 0xffffffff : 0); + _scene_group->setNodeMask(visible ? 0xffffffff : 0); } //---------------------------------------------------------------------------- bool Element::isVisible() const { - return _transform.valid() && _transform->getNodeMask() != 0; + return _scene_group.valid() && _scene_group->getNodeMask() != 0; } //---------------------------------------------------------------------------- - osg::MatrixTransform* Element::getMatrixTransform() + osg::MatrixTransform* Element::getSceneGroup() const { - return _transform.get(); - } - - //---------------------------------------------------------------------------- - osg::MatrixTransform const* Element::getMatrixTransform() const - { - return _transform.get(); + return _scene_group.get(); } //---------------------------------------------------------------------------- osg::Vec2f Element::posToLocal(const osg::Vec2f& pos) const { - getMatrix(); - if (! _transform) return osg::Vec2f(pos[0], pos[1]); - const osg::Matrix& m = _transform->getInverseMatrix(); + if( !_scene_group ) + // TODO log warning? + return pos; + + updateMatrix(); + const osg::Matrix& m = _scene_group->getInverseMatrix(); return osg::Vec2f ( m(0, 0) * pos[0] + m(1, 0) * pos[1] + m(3, 0), @@ -487,9 +461,6 @@ namespace canvas { if( child->getNameString() == NAME_TRANSFORM ) { - if( !_transform.valid() ) - return; - if( child->getIndex() >= static_cast(_transform_types.size()) ) { SG_LOG @@ -526,7 +497,7 @@ namespace canvas if( parent == _node ) { const std::string& name = child->getNameString(); - if( boost::starts_with(name, "data-") ) + if( strutils::starts_with(name, "data-") ) return; else if( StyleInfo const* style_info = getStyleInfo(name) ) { @@ -541,7 +512,7 @@ namespace canvas } else if( name == "update" ) return update(0); - else if( boost::starts_with(name, "blend-") ) + else if( strutils::starts_with(name, "blend-") ) return (void)(_attributes_dirty |= BLEND_FUNC); } else if( parent @@ -565,6 +536,10 @@ namespace canvas //---------------------------------------------------------------------------- void Element::setClip(const std::string& clip) { + if( !_scene_group ) + // TODO warn? + return; + osg::StateSet* ss = getOrCreateStateSet(); if( !ss ) return; @@ -578,8 +553,8 @@ namespace canvas // TODO generalize CSS property parsing const std::string RECT("rect("); - if( !boost::ends_with(clip, ")") - || !boost::starts_with(clip, RECT) ) + if( !strutils::ends_with(clip, ")") + || !strutils::starts_with(clip, RECT) ) { SG_LOG(SG_GENERAL, SG_WARN, "Canvas: invalid clip: " << clip); return; @@ -619,7 +594,7 @@ namespace canvas } if( !_scissor ) - _scissor = new RelativeScissor(_transform.get()); + _scissor = new RelativeScissor(_scene_group.get()); // , , , _scissor->x() = values[3]; @@ -643,26 +618,26 @@ namespace canvas _scissor->_coord_reference = rf; } - //---------------------------------------------------------------------------- - void Element::setRotation(unsigned int index, double r) - { - _node->getChild(NAME_TRANSFORM, index, true)->setDoubleValue("rot", r); - } + //---------------------------------------------------------------------------- + void Element::setRotation(unsigned int index, double r) + { + _node->getChild(NAME_TRANSFORM, index, true)->setDoubleValue("rot", r); + } - //---------------------------------------------------------------------------- - void Element::setTranslation(unsigned int index, double x, double y) - { - SGPropertyNode* tf = _node->getChild(NAME_TRANSFORM, index, true); - tf->getChild("t", 0, true)->setDoubleValue(x); - tf->getChild("t", 1, true)->setDoubleValue(y); - } + //---------------------------------------------------------------------------- + void Element::setTranslation(unsigned int index, double x, double y) + { + SGPropertyNode* tf = _node->getChild(NAME_TRANSFORM, index, true); + tf->getChild("t", 0, true)->setDoubleValue(x); + tf->getChild("t", 1, true)->setDoubleValue(y); + } - //---------------------------------------------------------------------------- - void Element::setTransformEnabled(unsigned int index, bool enabled) - { - SGPropertyNode* tf = _node->getChild(NAME_TRANSFORM, index, true); - tf->setBoolValue("enabled", enabled); - } + //---------------------------------------------------------------------------- + void Element::setTransformEnabled(unsigned int index, bool enabled) + { + SGPropertyNode* tf = _node->getChild(NAME_TRANSFORM, index, true); + tf->setBoolValue("enabled", enabled); + } //---------------------------------------------------------------------------- osg::BoundingBox Element::getBoundingBox() const @@ -676,8 +651,8 @@ namespace canvas osg::BoundingBox bb; - if( _transform.valid() ) - bb.expandBy(_transform->getBound()); + if( _scene_group.valid() ) + bb.expandBy( _scene_group->getBound() ); return bb; } @@ -711,73 +686,11 @@ namespace canvas //---------------------------------------------------------------------------- osg::Matrix Element::getMatrix() const { - if( !_transform ) + if( !_scene_group ) return osg::Matrix::identity(); - if( !(_attributes_dirty & TRANSFORM) ) - return _transform->getMatrix(); - - osg::Matrix m; - for( size_t i = 0; i < _transform_types.size(); ++i ) - { - // Skip unused indizes... - if( _transform_types[i] == TT_NONE ) - continue; - - SGPropertyNode* tf_node = _node->getChild("tf", i, true); - if (!tf_node->getBoolValue("enabled", true)) { - continue; // skip disabled transforms - } - - // Build up the matrix representation of the current transform node - osg::Matrix tf; - switch( _transform_types[i] ) - { - case TT_MATRIX: - tf = osg::Matrix( tf_node->getDoubleValue("m[0]", 1), - tf_node->getDoubleValue("m[1]", 0), - 0, - tf_node->getDoubleValue("m[6]", 0), - - tf_node->getDoubleValue("m[2]", 0), - tf_node->getDoubleValue("m[3]", 1), - 0, - tf_node->getDoubleValue("m[7]", 0), - - 0, - 0, - 1, - 0, - - tf_node->getDoubleValue("m[4]", 0), - tf_node->getDoubleValue("m[5]", 0), - 0, - tf_node->getDoubleValue("m[8]", 1) ); - break; - case TT_TRANSLATE: - tf.makeTranslate( osg::Vec3f( tf_node->getDoubleValue("t[0]", 0), - tf_node->getDoubleValue("t[1]", 0), - 0 ) ); - break; - case TT_ROTATE: - tf.makeRotate( tf_node->getDoubleValue("rot", 0), 0, 0, 1 ); - break; - case TT_SCALE: - { - float sx = tf_node->getDoubleValue("s[0]", 1); - // sy defaults to sx... - tf.makeScale( sx, tf_node->getDoubleValue("s[1]", sx), 1 ); - break; - } - default: - break; - } - m.postMult( tf ); - } - _transform->setMatrix(m); - _attributes_dirty &= ~TRANSFORM; - - return m; + updateMatrix(); + return _scene_group->getMatrix(); } //---------------------------------------------------------------------------- @@ -791,11 +704,8 @@ namespace canvas PropertyBasedElement(node), _canvas( canvas ), _parent( parent ), - _attributes_dirty( 0 ), - _transform( new osg::MatrixTransform ), - _style( parent_style ), - _scissor( 0 ), - _drawable( 0 ) + _scene_group( new osg::MatrixTransform ), + _style( parent_style ) { staticInit(); @@ -807,15 +717,15 @@ namespace canvas ); // Ensure elements are drawn in order they appear in the element tree - _transform->getOrCreateStateSet() - ->setRenderBinDetails - ( - 0, - "PreOrderBin", - osg::StateSet::OVERRIDE_RENDERBIN_DETAILS - ); + _scene_group + ->getOrCreateStateSet() + ->setRenderBinDetails( + 0, + "PreOrderBin", + osg::StateSet::OVERRIDE_RENDERBIN_DETAILS + ); - _transform->setUserData( new OSGUserData(this) ); + _scene_group->setUserData( new OSGUserData(this) ); } //---------------------------------------------------------------------------- @@ -903,11 +813,21 @@ namespace canvas void Element::setDrawable( osg::Drawable* drawable ) { _drawable = drawable; - assert( _drawable ); - osg::ref_ptr geode = new osg::Geode; + if( !_drawable ) + { + SG_LOG(SG_GL, SG_WARN, "canvas::Element::setDrawable: NULL drawable"); + return; + } + if( !_scene_group ) + { + SG_LOG(SG_GL, SG_WARN, "canvas::Element::setDrawable: NULL scenegroup"); + return; + } + + auto geode = new osg::Geode; geode->addDrawable(_drawable); - _transform->addChild(geode); + _scene_group->addChild(geode); } //---------------------------------------------------------------------------- @@ -915,18 +835,109 @@ namespace canvas { if( _drawable.valid() ) return _drawable->getOrCreateStateSet(); - if( _transform.valid() ) - return _transform->getOrCreateStateSet(); - - return 0; + else if( _scene_group.valid() ) + return _scene_group->getOrCreateStateSet(); + else + return nullptr; } //---------------------------------------------------------------------------- void Element::setupStyle() { - BOOST_FOREACH( Style::value_type style, _style ) + for(auto const& style: _style) setStyle(style.second); } + //---------------------------------------------------------------------------- + void Element::updateMatrix() const + { + if( !(_attributes_dirty & TRANSFORM) || !_scene_group ) + return; + + osg::Matrix m; + for( size_t i = 0; i < _transform_types.size(); ++i ) + { + // Skip unused indizes... + if( _transform_types[i] == TT_NONE ) + continue; + + SGPropertyNode* tf_node = _node->getChild("tf", i, true); + if (!tf_node->getBoolValue("enabled", true)) { + continue; // skip disabled transforms + } + + // Build up the matrix representation of the current transform node + osg::Matrix tf; + switch( _transform_types[i] ) + { + case TT_MATRIX: + tf = osg::Matrix( tf_node->getDoubleValue("m[0]", 1), + tf_node->getDoubleValue("m[1]", 0), + 0, + tf_node->getDoubleValue("m[6]", 0), + + tf_node->getDoubleValue("m[2]", 0), + tf_node->getDoubleValue("m[3]", 1), + 0, + tf_node->getDoubleValue("m[7]", 0), + + 0, + 0, + 1, + 0, + + tf_node->getDoubleValue("m[4]", 0), + tf_node->getDoubleValue("m[5]", 0), + 0, + tf_node->getDoubleValue("m[8]", 1) ); + break; + case TT_TRANSLATE: + tf.makeTranslate( osg::Vec3f( tf_node->getDoubleValue("t[0]", 0), + tf_node->getDoubleValue("t[1]", 0), + 0 ) ); + break; + case TT_ROTATE: + tf.makeRotate( tf_node->getDoubleValue("rot", 0), 0, 0, 1 ); + break; + case TT_SCALE: + { + float sx = tf_node->getDoubleValue("s[0]", 1); + // sy defaults to sx... + tf.makeScale( sx, tf_node->getDoubleValue("s[1]", sx), 1 ); + break; + } + default: + break; + } + m.postMult( tf ); + } + _scene_group->setMatrix(m); + _attributes_dirty &= ~TRANSFORM; + } + + //---------------------------------------------------------------------------- + void Element::updateImpl(double dt) + { + updateMatrix(); + + // Update bounding box on manual update (manual updates pass zero dt) + if( dt == 0 && _drawable ) + _drawable->getBound(); + + if( (_attributes_dirty & BLEND_FUNC) ) + { + parseBlendFunc( + _scene_group->getOrCreateStateSet(), + _node->getChild("blend-source"), + _node->getChild("blend-destination"), + _node->getChild("blend-source-rgb"), + _node->getChild("blend-destination-rgb"), + _node->getChild("blend-source-alpha"), + _node->getChild("blend-destination-alpha") + ); + _attributes_dirty &= ~BLEND_FUNC; + } + } + } // namespace canvas } // namespace simgear diff --git a/simgear/canvas/elements/CanvasElement.hxx b/simgear/canvas/elements/CanvasElement.hxx index 8782362b..fe22aa3c 100644 --- a/simgear/canvas/elements/CanvasElement.hxx +++ b/simgear/canvas/elements/CanvasElement.hxx @@ -24,13 +24,13 @@ #include #include #include // for uint32_t +#include #include #include #include #include -#include namespace osg { @@ -49,6 +49,7 @@ namespace canvas public PropertyBasedElement { public: + using SceneGroupWeakPtr = osg::observer_ptr; /** * Store pointer to window as user data @@ -142,8 +143,11 @@ namespace canvas */ virtual bool isVisible() const; - osg::MatrixTransform* getMatrixTransform(); - osg::MatrixTransform const* getMatrixTransform() const; + /** + * Get the according group in the OSG scene graph + */ + // TODO ref_ptr + osg::MatrixTransform* getSceneGroup() const; /** * Transform position to local coordinages. @@ -217,13 +221,14 @@ namespace canvas */ template static - typename boost::enable_if< - boost::is_base_of, + std::enable_if_t< + std::is_base_of::value, ElementPtr - >::type create( const CanvasWeakPtr& canvas, - const SGPropertyNode_ptr& node, - const Style& style = Style(), - Element* parent = NULL ) + > + create( const CanvasWeakPtr& canvas, + const SGPropertyNode_ptr& node, + const Style& style = Style(), + Element* parent = NULL ) { return ElementPtr( new Derived(canvas, node, style, parent) ); } @@ -251,13 +256,13 @@ namespace canvas CanvasWeakPtr _canvas; ElementWeakPtr _parent; - mutable uint32_t _attributes_dirty; + mutable uint32_t _attributes_dirty = 0; - osg::observer_ptr _transform; - std::vector _transform_types; + SceneGroupWeakPtr _scene_group; + std::vector _transform_types; Style _style; - RelativeScissor *_scissor; + RelativeScissor *_scissor = nullptr; typedef std::vector Listener; typedef std::map ListenerMap; @@ -584,6 +589,10 @@ namespace canvas void setupStyle(); + void updateMatrix() const; + + virtual void updateImpl(double dt); + private: osg::ref_ptr _drawable; diff --git a/simgear/canvas/elements/CanvasGroup.cxx b/simgear/canvas/elements/CanvasGroup.cxx index d398fe2e..02696cde 100644 --- a/simgear/canvas/elements/CanvasGroup.cxx +++ b/simgear/canvas/elements/CanvasGroup.cxx @@ -23,13 +23,10 @@ #include "CanvasMap.hxx" #include "CanvasPath.hxx" #include "CanvasText.hxx" + #include #include -#include -#include -#include - namespace simgear { namespace canvas @@ -48,7 +45,7 @@ namespace canvas ElementFactories Group::_child_factories; const std::string Group::TYPE_NAME = "group"; - void warnTransformExpired(const char* member_name) + void warnSceneGroupExpired(const char* member_name) { SG_LOG( SG_GENERAL, SG_WARN, @@ -135,63 +132,57 @@ namespace canvas //---------------------------------------------------------------------------- ElementPtr Group::getElementById(const std::string& id) { - if( !_transform.valid() ) + if( !_scene_group.valid() ) { - warnTransformExpired("getElementById"); - return ElementPtr(); + warnSceneGroupExpired("getElementById"); + return {}; } - std::vector groups; - for(size_t i = 0; i < _transform->getNumChildren(); ++i) + // TODO check search algorithm. Not completely breadth-first and might be + // possible with using less dynamic memory + std::vector child_groups; + for(size_t i = 0; i < _scene_group->getNumChildren(); ++i) { const ElementPtr& el = getChildByIndex(i); if( el->get("id") == id ) return el; - Group* group = dynamic_cast(el.get()); - if( group ) - groups.push_back(group); + if( Group* child_group = dynamic_cast(el.get()) ) + child_groups.push_back(child_group); } - BOOST_FOREACH( GroupPtr group, groups ) + for(auto group: child_groups) { - ElementPtr el = group->getElementById(id); - if( el ) + if( ElementPtr el = group->getElementById(id) ) return el; } - return ElementPtr(); + return {}; } //---------------------------------------------------------------------------- void Group::clearEventListener() { - if( !_transform.valid() ) - return warnTransformExpired("clearEventListener"); - - for(size_t i = 0; i < _transform->getNumChildren(); ++i) - getChildByIndex(i)->clearEventListener(); - Element::clearEventListener(); - } - //---------------------------------------------------------------------------- - void Group::update(double dt) - { - for(size_t i = 0; i < _transform->getNumChildren(); ++i) - getChildByIndex(i)->update(dt); + if( !_scene_group.valid() ) + return warnSceneGroupExpired("clearEventListener"); - Element::update(dt); + for(size_t i = 0; i < _scene_group->getNumChildren(); ++i) + getChildByIndex(i)->clearEventListener(); } //---------------------------------------------------------------------------- bool Group::traverse(EventVisitor& visitor) { - // Iterate in reverse order as last child is displayed on top - for(size_t i = _transform->getNumChildren(); i --> 0;) + if( _scene_group.valid() ) { - if( getChildByIndex(i)->accept(visitor) ) - return true; + // Iterate in reverse order as last child is displayed on top + for(size_t i = _scene_group->getNumChildren(); i --> 0;) + { + if( getChildByIndex(i)->accept(visitor) ) + return true; + } } return false; } @@ -206,13 +197,13 @@ namespace canvas bool handled = setStyleImpl(style, style_info); if( style_info->inheritable ) { - if( !_transform.valid() ) + if( !_scene_group.valid() ) { - warnTransformExpired("setStyle"); + warnSceneGroupExpired("setStyle"); return false; } - for(size_t i = 0; i < _transform->getNumChildren(); ++i) + for(size_t i = 0; i < _scene_group->getNumChildren(); ++i) handled |= getChildByIndex(i)->setStyle(style, style_info); } @@ -222,26 +213,20 @@ namespace canvas //---------------------------------------------------------------------------- osg::BoundingBox Group::getTransformedBounds(const osg::Matrix& m) const { - osg::BoundingBox bb; - if( !_transform.valid() ) + if( !_scene_group.valid() ) { - warnTransformExpired("getTransformedBounds"); - return bb; + warnSceneGroupExpired("getTransformedBounds"); + return {}; } - for(size_t i = 0; i < _transform->getNumChildren(); ++i) + osg::BoundingBox bb; + for(size_t i = 0; i < _scene_group->getNumChildren(); ++i) { - const ElementPtr& child = getChildByIndex(i); - if( !child->getMatrixTransform()->getNodeMask() ) + auto child = getChildByIndex(i); + if( !child || !child->isVisible() ) continue; - bb.expandBy - ( - child->getTransformedBounds - ( - child->getMatrixTransform()->getMatrix() * m - ) - ); + bb.expandBy( child->getTransformedBounds(child->getMatrix() * m) ); } return bb; @@ -257,6 +242,15 @@ namespace canvas return ElementFactory(); } + //---------------------------------------------------------------------------- + void Group::updateImpl(double dt) + { + Element::updateImpl(dt); + + for(size_t i = 0; i < _scene_group->getNumChildren(); ++i) + getChildByIndex(i)->update(dt); + } + //---------------------------------------------------------------------------- void Group::childAdded(SGPropertyNode* child) { @@ -266,13 +260,13 @@ namespace canvas ElementFactory child_factory = getChildFactory( child->getNameString() ); if( child_factory ) { - if( !_transform.valid() ) - return warnTransformExpired("childAdded"); + if( !_scene_group.valid() ) + return warnSceneGroupExpired("childAdded"); ElementPtr element = child_factory(_canvas, child, _style, this); // Add to osg scene graph... - _transform->addChild( element->getMatrixTransform() ); + _scene_group->addChild(element->getSceneGroup()); // ...and ensure correct ordering handleZIndexChanged(element); @@ -293,7 +287,7 @@ namespace canvas if( getChildFactory(node->getNameString()) ) { - if( !_transform.valid() ) + if( !_scene_group.valid() ) // If transform is destroyed also all children are destroyed, so we can // not do anything here. return; @@ -323,7 +317,7 @@ namespace canvas void Group::childChanged(SGPropertyNode* node) { SGPropertyNode* parent = node->getParent(); - SGPropertyNode* grand_parent = parent ? parent->getParent() : NULL; + SGPropertyNode* grand_parent = parent ? parent->getParent() : nullptr; if( grand_parent == _node && node->getNameString() == "z-index" ) @@ -333,16 +327,18 @@ namespace canvas //---------------------------------------------------------------------------- void Group::handleZIndexChanged(ElementPtr child, int z_index) { - if( !child || !_transform.valid() ) + if( !child || !_scene_group.valid() ) return; - osg::ref_ptr tf = child->getMatrixTransform(); - size_t index = _transform->getChildIndex(tf), + // Keep reference to prevent deleting while removing and re-inserting later + osg::ref_ptr tf = child->getSceneGroup(); + + size_t index = _scene_group->getChildIndex(tf), index_new = index; for(;; ++index_new) { - if( index_new + 1 == _transform->getNumChildren() ) + if( index_new + 1 == _scene_group->getNumChildren() ) break; // Move to end of block with same index (= move upwards until the next @@ -369,8 +365,8 @@ namespace canvas return; } - _transform->removeChild(index); - _transform->insertChild(index_new, tf); + _scene_group->removeChild(index); + _scene_group->insertChild(index_new, tf); SG_LOG ( @@ -383,26 +379,27 @@ namespace canvas //---------------------------------------------------------------------------- ElementPtr Group::getChildByIndex(size_t index) const { - assert(_transform.valid()); - OSGUserData* ud = - static_cast(_transform->getChild(index)->getUserData()); - assert(ud); - if (ud) - return ud->element; - return nullptr; + assert( _scene_group.valid() ); + + auto child = _scene_group->getChild(index); + if( !child ) + return {}; + + auto ud = static_cast(child->getUserData()); + return ud ? ud->element : ElementPtr(); } //---------------------------------------------------------------------------- ElementPtr Group::findChild( const SGPropertyNode* node, const std::string& id ) const { - if( !_transform.valid() ) + if( !_scene_group.valid() ) { - warnTransformExpired("findChild"); - return ElementPtr(); + warnSceneGroupExpired("findChild"); + return {}; } - for(size_t i = 0; i < _transform->getNumChildren(); ++i) + for(size_t i = 0; i < _scene_group->getNumChildren(); ++i) { ElementPtr el = getChildByIndex(i); @@ -418,7 +415,7 @@ namespace canvas } } - return ElementPtr(); + return {}; } } // namespace canvas diff --git a/simgear/canvas/elements/CanvasGroup.hxx b/simgear/canvas/elements/CanvasGroup.hxx index 6a047f0b..2352aab4 100644 --- a/simgear/canvas/elements/CanvasGroup.hxx +++ b/simgear/canvas/elements/CanvasGroup.hxx @@ -88,8 +88,6 @@ namespace canvas virtual void clearEventListener(); - virtual void update(double dt); - virtual bool traverse(EventVisitor& visitor); virtual bool setStyle( const SGPropertyNode* child, @@ -107,6 +105,8 @@ namespace canvas */ virtual ElementFactory getChildFactory(const std::string& type) const; + virtual void updateImpl(double dt); + virtual void childAdded(SGPropertyNode * child); virtual void childRemoved(SGPropertyNode * child); virtual void childChanged(SGPropertyNode * child); diff --git a/simgear/canvas/elements/CanvasImage.cxx b/simgear/canvas/elements/CanvasImage.cxx index 0286a4bc..4c3aaec9 100644 --- a/simgear/canvas/elements/CanvasImage.cxx +++ b/simgear/canvas/elements/CanvasImage.cxx @@ -117,9 +117,7 @@ namespace canvas ElementWeakPtr parent ): Element(canvas, node, parent_style, parent), _texture(new osg::Texture2D), - _node_src_rect( node->getNode("source", 0, true) ), - _src_rect(0,0), - _region(0,0) + _node_src_rect( node->getNode("source", 0, true) ) { staticInit(); @@ -157,22 +155,207 @@ namespace canvas //---------------------------------------------------------------------------- Image::~Image() { - if( _http_request ) { - Canvas::getSystemAdapter()->getHTTPClient()->cancelRequest(_http_request, "image destroyed"); - } + if( _http_request ) + { + Canvas::getSystemAdapter() + ->getHTTPClient() + ->cancelRequest(_http_request, "image destroyed"); + } } //---------------------------------------------------------------------------- - void Image::update(double dt) + void Image::valueChanged(SGPropertyNode* child) { - Element::update(dt); + // If the image is switched from invisible to visible, and it shows a + // canvas, we need to delay showing it by one frame to ensure the canvas is + // updated before the image is displayed. + // + // As canvas::Element handles and filters changes to the "visible" property + // we can not check this in Image::childChanged but instead have to override + // Element::valueChanged. + if( !isVisible() + && child->getParent() == _node + && child->getNameString() == "visible" + && child->getBoolValue() ) + { + CullCallback* cb = +#if OSG_VERSION_LESS_THAN(3,3,2) + static_cast +#else + dynamic_cast +#endif + ( _geom->getCullCallback() ); + + if( cb ) + cb->cullNextFrame(); + } + + Element::valueChanged(child); + } + + //---------------------------------------------------------------------------- + void Image::setSrcCanvas(CanvasPtr canvas) + { + CanvasPtr src_canvas = _src_canvas.lock(), + self_canvas = _canvas.lock(); + + if( src_canvas ) + src_canvas->removeParentCanvas(self_canvas); + if( self_canvas ) + self_canvas->removeChildCanvas(src_canvas); + + _src_canvas = src_canvas = canvas; + _attributes_dirty |= SRC_CANVAS; + _geom->setCullCallback(canvas ? new CullCallback(canvas) : 0); + + if( src_canvas ) + { + setupDefaultDimensions(); + + if( self_canvas ) + { + self_canvas->addChildCanvas(src_canvas); + src_canvas->addParentCanvas(self_canvas); + } + } + } + + //---------------------------------------------------------------------------- + CanvasWeakPtr Image::getSrcCanvas() const + { + return _src_canvas; + } + + //---------------------------------------------------------------------------- + void Image::setImage(osg::ref_ptr img) + { + // remove canvas... + setSrcCanvas( CanvasPtr() ); + + _texture->setResizeNonPowerOfTwoHint(false); + _texture->setImage(img); + _texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + _texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); + _geom->getOrCreateStateSet() + ->setTextureAttributeAndModes(0, _texture); + + if( img ) + setupDefaultDimensions(); + } + + //---------------------------------------------------------------------------- + void Image::setFill(const std::string& fill) + { + osg::Vec4 color(1,1,1,1); + if( !fill.empty() // If no color is given default to white + && !parseColor(fill, color) ) + return; + setFill(color); + } + + //---------------------------------------------------------------------------- + void Image::setFill(const osg::Vec4& color) + { + _colors->front() = color; + _colors->dirty(); + } + + + //---------------------------------------------------------------------------- + void Image::setOutset(const std::string& outset) + { + _outset = CSSBorder::parse(outset); + _attributes_dirty |= DEST_SIZE; + } + + //---------------------------------------------------------------------------- + void Image::setPreserveAspectRatio(const std::string& scale) + { + _preserve_aspect_ratio = SVGpreserveAspectRatio::parse(scale); + _attributes_dirty |= SRC_RECT; + } + + //---------------------------------------------------------------------------- + void Image::setSourceRect(const SGRect& sourceRect) + { + _attributes_dirty |= SRC_RECT; + _src_rect = sourceRect; + } + + //---------------------------------------------------------------------------- + void Image::setSlice(const std::string& slice) + { + _slice = CSSBorder::parse(slice); + _attributes_dirty |= SRC_RECT | DEST_SIZE; + } + + //---------------------------------------------------------------------------- + void Image::setSliceWidth(const std::string& width) + { + _slice_width = CSSBorder::parse(width); + _attributes_dirty |= DEST_SIZE; + } + + //---------------------------------------------------------------------------- + const SGRect& Image::getRegion() const + { + return _region; + } + + //---------------------------------------------------------------------------- + bool Image::handleEvent(const EventPtr& event) + { + bool handled = Element::handleEvent(event); + + CanvasPtr src_canvas = _src_canvas.lock(); + if( !src_canvas ) + return handled; + + if( MouseEventPtr mouse_event = dynamic_cast(event.get()) ) + { + mouse_event.reset( new MouseEvent(*mouse_event) ); + + mouse_event->client_pos = mouse_event->local_pos + - toOsg(_region.getMin()); + + osg::Vec2f size(_region.width(), _region.height()); + if( _outset.isValid() ) + { + CSSBorder::Offsets outset = + _outset.getAbsOffsets(getTextureDimensions()); + + mouse_event->client_pos += osg::Vec2f(outset.l, outset.t); + size.x() += outset.l + outset.r; + size.y() += outset.t + outset.b; + } + + // Scale event pos according to canvas view size vs. displayed/screen size + mouse_event->client_pos.x() *= src_canvas->getViewWidth() / size.x(); + mouse_event->client_pos.y() *= src_canvas->getViewHeight()/ size.y(); + mouse_event->local_pos = mouse_event->client_pos; + + handled |= src_canvas->handleMouseEvent(mouse_event); + } + else if( KeyboardEventPtr keyboard_event = + dynamic_cast(event.get()) ) + { + handled |= src_canvas->handleKeyboardEvent(keyboard_event); + } + + return handled; + } + + //---------------------------------------------------------------------------- + void Image::updateImpl(double dt) + { + Element::updateImpl(dt); osg::Texture2D* texture = dynamic_cast ( _geom->getOrCreateStateSet() ->getTextureAttribute(0, osg::StateAttribute::TEXTURE) ); - simgear::canvas::CanvasPtr canvas = _src_canvas.lock(); + auto canvas = _src_canvas.lock(); if( (_attributes_dirty & SRC_CANVAS) // check if texture has changed (eg. due to resizing) @@ -402,188 +585,6 @@ namespace canvas } } - //---------------------------------------------------------------------------- - void Image::valueChanged(SGPropertyNode* child) - { - // If the image is switched from invisible to visible, and it shows a - // canvas, we need to delay showing it by one frame to ensure the canvas is - // updated before the image is displayed. - // - // As canvas::Element handles and filters changes to the "visible" property - // we can not check this in Image::childChanged but instead have to override - // Element::valueChanged. - if( !isVisible() - && child->getParent() == _node - && child->getNameString() == "visible" - && child->getBoolValue() ) - { - CullCallback* cb = -#if OSG_VERSION_LESS_THAN(3,3,2) - static_cast -#else - dynamic_cast -#endif - ( _geom->getCullCallback() ); - - if( cb ) - cb->cullNextFrame(); - } - - Element::valueChanged(child); - } - - //---------------------------------------------------------------------------- - void Image::setSrcCanvas(CanvasPtr canvas) - { - CanvasPtr src_canvas = _src_canvas.lock(), - self_canvas = _canvas.lock(); - - if( src_canvas ) - src_canvas->removeParentCanvas(self_canvas); - if( self_canvas ) - self_canvas->removeChildCanvas(src_canvas); - - _src_canvas = src_canvas = canvas; - _attributes_dirty |= SRC_CANVAS; - _geom->setCullCallback(canvas ? new CullCallback(canvas) : 0); - - if( src_canvas ) - { - setupDefaultDimensions(); - - if( self_canvas ) - { - self_canvas->addChildCanvas(src_canvas); - src_canvas->addParentCanvas(self_canvas); - } - } - } - - //---------------------------------------------------------------------------- - CanvasWeakPtr Image::getSrcCanvas() const - { - return _src_canvas; - } - - //---------------------------------------------------------------------------- - void Image::setImage(osg::ref_ptr img) - { - // remove canvas... - setSrcCanvas( CanvasPtr() ); - - _texture->setResizeNonPowerOfTwoHint(false); - _texture->setImage(img); - _texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); - _texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); - _geom->getOrCreateStateSet() - ->setTextureAttributeAndModes(0, _texture); - - if( img ) - setupDefaultDimensions(); - } - - //---------------------------------------------------------------------------- - void Image::setFill(const std::string& fill) - { - osg::Vec4 color(1,1,1,1); - if( !fill.empty() // If no color is given default to white - && !parseColor(fill, color) ) - return; - setFill(color); - } - - //---------------------------------------------------------------------------- - void Image::setFill(const osg::Vec4& color) - { - _colors->front() = color; - _colors->dirty(); - } - - - //---------------------------------------------------------------------------- - void Image::setOutset(const std::string& outset) - { - _outset = CSSBorder::parse(outset); - _attributes_dirty |= DEST_SIZE; - } - - //---------------------------------------------------------------------------- - void Image::setPreserveAspectRatio(const std::string& scale) - { - _preserve_aspect_ratio = SVGpreserveAspectRatio::parse(scale); - _attributes_dirty |= SRC_RECT; - } - - //---------------------------------------------------------------------------- - void Image::setSourceRect(const SGRect& sourceRect) - { - _attributes_dirty |= SRC_RECT; - _src_rect = sourceRect; - } - - //---------------------------------------------------------------------------- - void Image::setSlice(const std::string& slice) - { - _slice = CSSBorder::parse(slice); - _attributes_dirty |= SRC_RECT | DEST_SIZE; - } - - //---------------------------------------------------------------------------- - void Image::setSliceWidth(const std::string& width) - { - _slice_width = CSSBorder::parse(width); - _attributes_dirty |= DEST_SIZE; - } - - //---------------------------------------------------------------------------- - const SGRect& Image::getRegion() const - { - return _region; - } - - //---------------------------------------------------------------------------- - bool Image::handleEvent(const EventPtr& event) - { - bool handled = Element::handleEvent(event); - - CanvasPtr src_canvas = _src_canvas.lock(); - if( !src_canvas ) - return handled; - - if( MouseEventPtr mouse_event = dynamic_cast(event.get()) ) - { - mouse_event.reset( new MouseEvent(*mouse_event) ); - - mouse_event->client_pos = mouse_event->local_pos - - toOsg(_region.getMin()); - - osg::Vec2f size(_region.width(), _region.height()); - if( _outset.isValid() ) - { - CSSBorder::Offsets outset = - _outset.getAbsOffsets(getTextureDimensions()); - - mouse_event->client_pos += osg::Vec2f(outset.l, outset.t); - size.x() += outset.l + outset.r; - size.y() += outset.t + outset.b; - } - - // Scale event pos according to canvas view size vs. displayed/screen size - mouse_event->client_pos.x() *= src_canvas->getViewWidth() / size.x(); - mouse_event->client_pos.y() *= src_canvas->getViewHeight()/ size.y(); - mouse_event->local_pos = mouse_event->client_pos; - - handled |= src_canvas->handleMouseEvent(mouse_event); - } - else if( KeyboardEventPtr keyboard_event = - dynamic_cast(event.get()) ) - { - handled |= src_canvas->handleKeyboardEvent(keyboard_event); - } - - return handled; - } - //---------------------------------------------------------------------------- void Image::childChanged(SGPropertyNode* child) { @@ -634,7 +635,9 @@ namespace canvas // Abort pending request if( _http_request ) { - Canvas::getSystemAdapter()->getHTTPClient()->cancelRequest(_http_request, "setting new image"); + Canvas::getSystemAdapter() + ->getHTTPClient() + ->cancelRequest(_http_request, "setting new image"); _http_request.reset(); } diff --git a/simgear/canvas/elements/CanvasImage.hxx b/simgear/canvas/elements/CanvasImage.hxx index b7ddfb8f..162349b1 100644 --- a/simgear/canvas/elements/CanvasImage.hxx +++ b/simgear/canvas/elements/CanvasImage.hxx @@ -53,7 +53,6 @@ namespace canvas ElementWeakPtr parent = 0 ); virtual ~Image(); - virtual void update(double dt); virtual void valueChanged(SGPropertyNode* child); void setSrcCanvas(CanvasPtr canvas); @@ -100,8 +99,8 @@ namespace canvas * */ void setSourceRect(const SGRect& sourceRect); - protected: + protected: enum ImageAttributes { SRC_RECT = LAST_ATTRIBUTE << 1, // Source image rectangle @@ -109,6 +108,8 @@ namespace canvas SRC_CANVAS = DEST_SIZE << 1 }; + virtual void updateImpl(double dt); + virtual void childChanged(SGPropertyNode * child); void setupDefaultDimensions(); @@ -134,9 +135,9 @@ namespace canvas osg::ref_ptr _texCoords; osg::ref_ptr _colors; - SGPropertyNode *_node_src_rect; - SGRect _src_rect, - _region; + SGPropertyNode *_node_src_rect = nullptr; + SGRect _src_rect {0, 0}, + _region {0, 0}; SVGpreserveAspectRatio _preserve_aspect_ratio; diff --git a/simgear/canvas/elements/CanvasMap.cxx b/simgear/canvas/elements/CanvasMap.cxx index e15dc13b..35763198 100644 --- a/simgear/canvas/elements/CanvasMap.cxx +++ b/simgear/canvas/elements/CanvasMap.cxx @@ -18,13 +18,14 @@ // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA #include + #include "CanvasMap.hxx" #include "map/geo_node_pair.hxx" #include "map/projection.hxx" -#include +#include -#include +#include #define LOG_GEO_RET(msg) \ {\ @@ -73,13 +74,8 @@ namespace canvas Group(canvas, node, parent_style, parent) { staticInit(); - if (node->getChild(PROJECTION) && - (node->getChild(PROJECTION)->getStringValue() == WEB_MERCATOR)) { - _projection = (boost::shared_ptr) new WebMercatorProjection(); - } else { - _projection = (boost::shared_ptr) new SansonFlamsteedProjection(); - } - _projection_dirty = true; + + projectionNodeChanged(node->getChild(PROJECTION)); } //---------------------------------------------------------------------------- @@ -89,13 +85,13 @@ namespace canvas } //---------------------------------------------------------------------------- - void Map::update(double dt) + void Map::updateImpl(double dt) { - for( GeoNodes::iterator it = _geo_nodes.begin(); - it != _geo_nodes.end(); - ++it ) + Group::updateImpl(dt); + + for(auto& it: _geo_nodes) { - GeoNodePair* geo_node = it->second.get(); + GeoNodePair* geo_node = it.second.get(); if( !geo_node->isComplete() || (!geo_node->isDirty() && !_projection_dirty) ) continue; @@ -117,14 +113,12 @@ namespace canvas geo_node->setDirty(false); } _projection_dirty = false; - - Group::update(dt); } //---------------------------------------------------------------------------- void Map::childAdded(SGPropertyNode* parent, SGPropertyNode* child) { - if( boost::ends_with(child->getNameString(), GEO) ) + if( strutils::ends_with(child->getNameString(), GEO) ) _geo_nodes[child].reset(new GeoNodePair()); else if( parent != _node && child->getNameString() == HDG ) _hdg_nodes.insert(child); @@ -135,7 +129,7 @@ namespace canvas //---------------------------------------------------------------------------- void Map::childRemoved(SGPropertyNode* parent, SGPropertyNode* child) { - if( boost::ends_with(child->getNameString(), GEO) ) + if( strutils::ends_with(child->getNameString(), GEO) ) // TODO remove from other node _geo_nodes.erase(child); else if( parent != _node && child->getName() == HDG ) @@ -157,7 +151,7 @@ namespace canvas { const std::string& name = child->getNameString(); - if( boost::ends_with(name, GEO) ) + if( strutils::ends_with(name, GEO) ) return geoNodeChanged(child); else if( name == HDG ) return hdgNodeChanged(child); @@ -188,24 +182,31 @@ namespace canvas _projection->setRange(child->getDoubleValue()); else if( child->getNameString() == SCREEN_RANGE ) _projection->setScreenRange(child->getDoubleValue()); - else if( child->getNameString() == PROJECTION ) { - if (child->getStringValue() == WEB_MERCATOR) { - _projection = (boost::shared_ptr) new WebMercatorProjection(); - } else { - _projection = (boost::shared_ptr) new SansonFlamsteedProjection(); - } - _projection->setWorldPosition(_node->getDoubleValue(REF_LAT), - _node->getDoubleValue(REF_LON) ); - _projection->setOrientation(_node->getFloatValue(HDG)); - _projection->setScreenRange(_node->getDoubleValue(SCREEN_RANGE)); - _projection->setRange(_node->getDoubleValue(RANGE)); - _projection_dirty = true; - } else + else if( child->getNameString() == PROJECTION ) + projectionNodeChanged(child); + else return Group::childChanged(child); _projection_dirty = true; } + //---------------------------------------------------------------------------- + void Map::projectionNodeChanged(SGPropertyNode* child) + { + if(child && child->getStringValue() == WEB_MERCATOR) + _projection = std::make_shared(); + else + _projection = std::make_shared(); + + _projection->setWorldPosition(_node->getDoubleValue(REF_LAT), + _node->getDoubleValue(REF_LON) ); + _projection->setOrientation(_node->getFloatValue(HDG)); + _projection->setScreenRange(_node->getDoubleValue(SCREEN_RANGE)); + _projection->setRange(_node->getDoubleValue(RANGE)); + + _projection_dirty = true; + } + //---------------------------------------------------------------------------- void Map::geoNodeChanged(SGPropertyNode* child) { diff --git a/simgear/canvas/elements/CanvasMap.hxx b/simgear/canvas/elements/CanvasMap.hxx index 993d45da..ca0521f0 100644 --- a/simgear/canvas/elements/CanvasMap.hxx +++ b/simgear/canvas/elements/CanvasMap.hxx @@ -22,9 +22,9 @@ #include "CanvasGroup.hxx" -#include -#include -#include +#include +#include +#include namespace simgear { @@ -45,45 +45,41 @@ namespace canvas ElementWeakPtr parent = 0 ); virtual ~Map(); - virtual void update(double dt); - - virtual void childAdded( SGPropertyNode * parent, - SGPropertyNode * child ); - virtual void childRemoved( SGPropertyNode * parent, - SGPropertyNode * child ); - virtual void valueChanged(SGPropertyNode * child); - protected: + virtual void updateImpl(double dt); - virtual void childChanged(SGPropertyNode * child); + void updateProjection(SGPropertyNode* type_node); - typedef boost::unordered_map< SGPropertyNode*, - boost::shared_ptr - > GeoNodes; - typedef boost::unordered_set NodeSet; + virtual void childAdded( SGPropertyNode* parent, + SGPropertyNode* child ); + virtual void childRemoved( SGPropertyNode* parent, + SGPropertyNode* child ); + virtual void valueChanged(SGPropertyNode* child); + virtual void childChanged(SGPropertyNode* child); + + using GeoNodes = + std::unordered_map>; + using NodeSet = std::unordered_set; GeoNodes _geo_nodes; NodeSet _hdg_nodes; - boost::shared_ptr _projection; - bool _projection_dirty; + std::shared_ptr _projection; + bool _projection_dirty = false; struct GeoCoord { - GeoCoord(): - type(INVALID), - value(0) - {} enum { INVALID, LATITUDE, LONGITUDE - } type; - double value; + } type = INVALID; + double value = 0; }; - void geoNodeChanged(SGPropertyNode * child); - void hdgNodeChanged(SGPropertyNode * child); + void projectionNodeChanged(SGPropertyNode* child); + void geoNodeChanged(SGPropertyNode* child); + void hdgNodeChanged(SGPropertyNode* child); GeoCoord parseGeoCoord(const std::string& val) const; }; diff --git a/simgear/canvas/elements/CanvasPath.cxx b/simgear/canvas/elements/CanvasPath.cxx index 188f70d6..7d11a426 100644 --- a/simgear/canvas/elements/CanvasPath.cxx +++ b/simgear/canvas/elements/CanvasPath.cxx @@ -206,23 +206,13 @@ namespace canvas return SGVec2f(-1.0f, -1.0f); } - //---------------------------------------------------------------------------- - + //---------------------------------------------------------------------------- class Path::PathDrawable: public osg::Drawable { public: PathDrawable(Path* path): - _path_element(path), - _path(VG_INVALID_HANDLE), - _paint(VG_INVALID_HANDLE), - _paint_fill(VG_INVALID_HANDLE), - _attributes_dirty(~0), - _mode(0), - _fill_rule(VG_EVEN_ODD), - _stroke_width(1), - _stroke_linecap(VG_CAP_BUTT), - _stroke_linejoin(VG_JOIN_MITER) + _path_element(path) { setSupportsDisplayList(false); setDataVariance(Object::DYNAMIC); @@ -283,6 +273,16 @@ namespace canvas } } + /** + * Set path fill opacity (Only used if fill is not "none") + */ + void setFillOpacity(float opacity) + { + _fill_opacity = + static_cast(SGMiscf::clip(opacity, 0.f, 1.f) * 255); + _attributes_dirty |= FILL_COLOR; + } + /** * Set path fill rule ("pseudo-nonzero" or "evenodd") * @@ -310,7 +310,7 @@ namespace canvas else if( parseColor(stroke, _stroke_color) ) { _mode |= VG_STROKE_PATH; - _attributes_dirty |= STROKE_COLOR; + _attributes_dirty |= STROKE_COLOR; } else { @@ -323,6 +323,16 @@ namespace canvas } } + /** + * Set path stroke opacity (only used if stroke is not "none") + */ + void setStrokeOpacity(float opacity) + { + _stroke_opacity = + static_cast(SGMiscf::clip(opacity, 0.f, 1.f) * 255); + _attributes_dirty |= STROKE_COLOR; + } + /** * Set stroke width */ @@ -390,31 +400,22 @@ namespace canvas osg::StateAttribute const* blend_func = state->getLastAppliedAttribute(osg::StateAttribute::BLENDFUNC); - // Initialize/Update the paint - if( _attributes_dirty & STROKE_COLOR ) - { - if( _paint == VG_INVALID_HANDLE ) - _paint = vgCreatePaint(); - - vgSetParameterfv(_paint, VG_PAINT_COLOR, 4, _stroke_color._v); - - _attributes_dirty &= ~STROKE_COLOR; - } - - // Initialize/update fill paint - if( _attributes_dirty & FILL_COLOR ) - { - if( _paint_fill == VG_INVALID_HANDLE ) - _paint_fill = vgCreatePaint(); - - vgSetParameterfv(_paint_fill, VG_PAINT_COLOR, 4, _fill_color._v); - - _attributes_dirty &= ~FILL_COLOR; - } - // Setup paint if( _mode & VG_STROKE_PATH ) { + // Initialize/Update the paint + if( _attributes_dirty & STROKE_COLOR ) + { + if( _paint == VG_INVALID_HANDLE ) + _paint = vgCreatePaint(); + + auto color = _stroke_color; + color.a() *= _stroke_opacity / 255.f; + vgSetParameterfv(_paint, VG_PAINT_COLOR, 4, color._v); + + _attributes_dirty &= ~STROKE_COLOR; + } + vgSetPaint(_paint, VG_STROKE_PATH); vgSetf(VG_STROKE_LINE_WIDTH, _stroke_width); @@ -426,6 +427,19 @@ namespace canvas } if( _mode & VG_FILL_PATH ) { + // Initialize/update fill paint + if( _attributes_dirty & FILL_COLOR ) + { + if( _paint_fill == VG_INVALID_HANDLE ) + _paint_fill = vgCreatePaint(); + + auto color = _fill_color; + color.a() *= _fill_opacity / 255.f; + vgSetParameterfv(_paint_fill, VG_PAINT_COLOR, 4, color._v); + + _attributes_dirty &= ~FILL_COLOR; + } + vgSetPaint(_paint_fill, VG_FILL_PATH); vgSeti(VG_FILL_RULE, _fill_rule); @@ -579,22 +593,24 @@ namespace canvas Path *_path_element; - mutable VGPath _path; - mutable VGPaint _paint; - mutable VGPaint _paint_fill; - mutable uint32_t _attributes_dirty; + mutable VGPath _path {VG_INVALID_HANDLE}; + mutable VGPaint _paint {VG_INVALID_HANDLE}; + mutable VGPaint _paint_fill {VG_INVALID_HANDLE}; + mutable uint32_t _attributes_dirty {~0u}; CmdList _cmds; CoordList _coords; - VGbitfield _mode; + VGbitfield _mode {0}; osg::Vec4f _fill_color; - VGFillRule _fill_rule; + uint8_t _fill_opacity {255}; + VGFillRule _fill_rule {VG_EVEN_ODD}; osg::Vec4f _stroke_color; - VGfloat _stroke_width; + uint8_t _stroke_opacity {255}; + VGfloat _stroke_width {1}; std::vector _stroke_dash; - VGCapStyle _stroke_linecap; - VGJoinStyle _stroke_linejoin; + VGCapStyle _stroke_linecap {VG_CAP_BUTT}; + VGJoinStyle _stroke_linejoin {VG_JOIN_MITER}; osg::Vec3f transformPoint( const osg::Matrix& m, osg::Vec2f pos ) const @@ -670,8 +686,10 @@ namespace canvas PathDrawableRef Path::*path = &Path::_path; addStyle("fill", "color", &PathDrawable::setFill, path); + addStyle("fill-opacity", "numeric", &PathDrawable::setFillOpacity, path); addStyle("fill-rule", "", &PathDrawable::setFillRule, path); addStyle("stroke", "color", &PathDrawable::setStroke, path); + addStyle("stroke-opacity", "numeric", &PathDrawable::setStrokeOpacity, path); addStyle("stroke-width", "numeric", &PathDrawable::setStrokeWidth, path); addStyle("stroke-dasharray", "", &PathDrawable::setStrokeDashArray, path); addStyle("stroke-linecap", "", &PathDrawable::setStrokeLinecap, path); @@ -700,40 +718,6 @@ namespace canvas } - //---------------------------------------------------------------------------- - void Path::update(double dt) - { - if( _attributes_dirty & (CMDS | COORDS) ) - { - _path->setSegments - ( - _node->getChildValues("cmd"), - _node->getChildValues("coord") - ); - - _attributes_dirty &= ~(CMDS | COORDS); - } - - // SVG path overrides manual cmd/coord specification - if ( _hasSVG && (_attributes_dirty & SVG)) - { - CmdList cmds; - CoordList coords; - parseSVGPathToVGPath(_node->getStringValue("svg"), cmds, coords); - _path->setSegments(cmds, coords); - _attributes_dirty &= ~SVG; - } - - if ( _hasRect &&(_attributes_dirty & RECT)) - { - parseRectToVGPath(); - _attributes_dirty &= ~RECT; - - } - - Element::update(dt); - } - //---------------------------------------------------------------------------- osg::BoundingBox Path::getTransformedBounds(const osg::Matrix& m) const { @@ -839,36 +823,70 @@ namespace canvas _node->getChild("border-radius", 1, true)->setDoubleValue(radiusY); } + //---------------------------------------------------------------------------- + void Path::updateImpl(double dt) + { + Element::updateImpl(dt); + + if( _attributes_dirty & (CMDS | COORDS) ) + { + _path->setSegments + ( + _node->getChildValues("cmd"), + _node->getChildValues("coord") + ); + + _attributes_dirty &= ~(CMDS | COORDS); + } + + // SVG path overrides manual cmd/coord specification + if( _hasSVG && (_attributes_dirty & SVG) ) + { + CmdList cmds; + CoordList coords; + parseSVGPathToVGPath(_node->getStringValue("svg"), cmds, coords); + _path->setSegments(cmds, coords); + _attributes_dirty &= ~SVG; + } + + if( _hasRect &&(_attributes_dirty & RECT) ) + { + parseRectToVGPath(); + _attributes_dirty &= ~RECT; + } + } + //---------------------------------------------------------------------------- void Path::childChanged(SGPropertyNode* child) { - const std::string& name = child->getNameString(); - const std::string &prName = child->getParent()->getNameString(); + const std::string& name = child->getNameString(); + const std::string &prName = child->getParent()->getNameString(); - if (simgear::strutils::starts_with(name, "border-")) - { - _attributes_dirty |= RECT; - return; - } + if( strutils::starts_with(name, "border-") ) + { + _attributes_dirty |= RECT; + return; + } - if (prName == "rect") { - _hasRect = true; - if (name == "left") { - _rect.setLeft(child->getDoubleValue()); - } else if (name == "top") { - _rect.setTop(child->getDoubleValue()); - } else if (name == "right") { - _rect.setRight(child->getDoubleValue()); - } else if (name == "bottom") { - _rect.setBottom(child->getDoubleValue()); - } else if (name == "width") { - _rect.setWidth(child->getDoubleValue()); - } else if (name == "height") { - _rect.setHeight(child->getDoubleValue()); - } - _attributes_dirty |= RECT; - return; + if (prName == "rect") + { + _hasRect = true; + if (name == "left") { + _rect.setLeft(child->getDoubleValue()); + } else if (name == "top") { + _rect.setTop(child->getDoubleValue()); + } else if (name == "right") { + _rect.setRight(child->getDoubleValue()); + } else if (name == "bottom") { + _rect.setBottom(child->getDoubleValue()); + } else if (name == "width") { + _rect.setWidth(child->getDoubleValue()); + } else if (name == "height") { + _rect.setHeight(child->getDoubleValue()); } + _attributes_dirty |= RECT; + return; + } if( child->getParent() != _node ) return; @@ -904,67 +922,68 @@ namespace canvas return values; } - //---------------------------------------------------------------------------- + //---------------------------------------------------------------------------- + void operator+=(CoordList& base, const std::initializer_list& other) + { + base.insert(base.end(), other.begin(), other.end()); + } - void operator+=(CoordList& base, const std::initializer_list& other) - { - base.insert(base.end(), other.begin(), other.end()); + //---------------------------------------------------------------------------- + void Path::parseRectToVGPath() + { + CmdList commands; + CoordList coords; + commands.reserve(4); + coords.reserve(8); + + bool haveCorner = false; + SGVec2f topLeft = parseRectCornerRadius(_node, "left", "top", haveCorner); + if (haveCorner) { + commands.push_back(VG_MOVE_TO_ABS); + coords += {_rect.l(), _rect.t() + topLeft.y()}; + commands.push_back(VG_SCCWARC_TO_REL); + coords += {topLeft.x(), topLeft.y(), 0.0, topLeft.x(), -topLeft.y()}; + } else { + commands.push_back(VG_MOVE_TO_ABS); + coords += {_rect.l(), _rect.t()}; } - void Path::parseRectToVGPath() - { - CmdList commands; - CoordList coords; - commands.reserve(4); - coords.reserve(8); - - bool haveCorner = false; - SGVec2f topLeft = parseRectCornerRadius(_node, "left", "top", haveCorner); - if (haveCorner) { - commands.push_back(VG_MOVE_TO_ABS); - coords += {_rect.l(), _rect.t() + topLeft.y()}; - commands.push_back(VG_SCCWARC_TO_REL); - coords += {topLeft.x(), topLeft.y(), 0.0, topLeft.x(), -topLeft.y()}; - } else { - commands.push_back(VG_MOVE_TO_ABS); - coords += {_rect.l(), _rect.t()}; - } - - SGVec2f topRight = parseRectCornerRadius(_node, "right", "top", haveCorner); - if (haveCorner) { - commands.push_back(VG_HLINE_TO_ABS); - coords += {_rect.r() - topRight.x()}; - commands.push_back(VG_SCCWARC_TO_REL); - coords += {topRight.x(), topRight.y(), 0.0, topRight.x(), topRight.y()}; - } else { - commands.push_back(VG_HLINE_TO_ABS); - coords += {_rect.r()}; - } - - SGVec2f bottomRight = parseRectCornerRadius(_node, "right", "bottom", haveCorner); - if (haveCorner) { - commands.push_back(VG_VLINE_TO_ABS); - coords += {_rect.b() - bottomRight.y()}; - commands.push_back(VG_SCCWARC_TO_REL); - coords += {bottomRight.x(), bottomRight.y(), 0.0, -bottomRight.x(), bottomRight.y()}; - } else { - commands.push_back(VG_VLINE_TO_ABS); - coords += {_rect.b()}; - } - - SGVec2f bottomLeft = parseRectCornerRadius(_node, "left", "bottom", haveCorner); - if (haveCorner) { - commands.push_back(VG_HLINE_TO_ABS); - coords += {_rect.l() + bottomLeft.x()}; - commands.push_back(VG_SCCWARC_TO_REL); - coords += {bottomLeft.x(), bottomLeft.y(), 0.0, -bottomLeft.x(), -bottomLeft.y()}; - } else { - commands.push_back(VG_HLINE_TO_ABS); - coords += {_rect.l()}; - } - - commands.push_back(VG_CLOSE_PATH); - _path->setSegments(commands, coords); + SGVec2f topRight = parseRectCornerRadius(_node, "right", "top", haveCorner); + if (haveCorner) { + commands.push_back(VG_HLINE_TO_ABS); + coords += {_rect.r() - topRight.x()}; + commands.push_back(VG_SCCWARC_TO_REL); + coords += {topRight.x(), topRight.y(), 0.0, topRight.x(), topRight.y()}; + } else { + commands.push_back(VG_HLINE_TO_ABS); + coords += {_rect.r()}; } + + SGVec2f bottomRight = parseRectCornerRadius(_node, "right", "bottom", haveCorner); + if (haveCorner) { + commands.push_back(VG_VLINE_TO_ABS); + coords += {_rect.b() - bottomRight.y()}; + commands.push_back(VG_SCCWARC_TO_REL); + coords += {bottomRight.x(), bottomRight.y(), 0.0, -bottomRight.x(), bottomRight.y()}; + } else { + commands.push_back(VG_VLINE_TO_ABS); + coords += {_rect.b()}; + } + + SGVec2f bottomLeft = parseRectCornerRadius(_node, "left", "bottom", haveCorner); + if (haveCorner) { + commands.push_back(VG_HLINE_TO_ABS); + coords += {_rect.l() + bottomLeft.x()}; + commands.push_back(VG_SCCWARC_TO_REL); + coords += {bottomLeft.x(), bottomLeft.y(), 0.0, -bottomLeft.x(), -bottomLeft.y()}; + } else { + commands.push_back(VG_HLINE_TO_ABS); + coords += {_rect.l()}; + } + + commands.push_back(VG_CLOSE_PATH); + _path->setSegments(commands, coords); + } + } // namespace canvas } // namespace simgear diff --git a/simgear/canvas/elements/CanvasPath.hxx b/simgear/canvas/elements/CanvasPath.hxx index 2b7804f9..c6edf30e 100644 --- a/simgear/canvas/elements/CanvasPath.hxx +++ b/simgear/canvas/elements/CanvasPath.hxx @@ -40,8 +40,6 @@ namespace canvas ElementWeakPtr parent = 0 ); virtual ~Path(); - virtual void update(double dt); - virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const; /** Add a segment with the given command and coordinates */ @@ -68,10 +66,10 @@ namespace canvas void setSVGPath(const std::string& svgPath); - void setRect(const SGRect& r); - void setRoundRect(const SGRect& r, float radiusX, float radiusY = -1.0); - protected: + void setRect(const SGRectf& r); + void setRoundRect(const SGRectf& r, float radiusX, float radiusY = -1.0); + protected: enum PathAttributes { CMDS = LAST_ATTRIBUTE << 1, @@ -86,12 +84,14 @@ namespace canvas bool _hasSVG : 1; bool _hasRect : 1; - SGRect _rect; + SGRectf _rect; + + virtual void updateImpl(double dt); - void parseRectToVGPath(); - virtual void childRemoved(SGPropertyNode * child); virtual void childChanged(SGPropertyNode * child); + + void parseRectToVGPath(); }; } // namespace canvas diff --git a/simgear/canvas/elements/CanvasText.cxx b/simgear/canvas/elements/CanvasText.cxx index 77a94696..1ac81e5d 100644 --- a/simgear/canvas/elements/CanvasText.cxx +++ b/simgear/canvas/elements/CanvasText.cxx @@ -865,12 +865,12 @@ namespace canvas //---------------------------------------------------------------------------- osg::StateSet* Text::getOrCreateStateSet() { - if( !_transform.valid() ) - return 0; + if( !_scene_group.valid() ) + return nullptr; // Only check for StateSet on Transform, as the text stateset is shared // between all text instances using the same font (texture). - return _transform->getOrCreateStateSet(); + return _scene_group->getOrCreateStateSet(); } } // namespace canvas diff --git a/simgear/math/SGMisc.hxx b/simgear/math/SGMisc.hxx index 47e89f75..cd448b05 100644 --- a/simgear/math/SGMisc.hxx +++ b/simgear/math/SGMisc.hxx @@ -155,6 +155,12 @@ public: { return std::isnan(v); } + + static bool eq(const T& a, const T& b, const T& epsilon = SGLimits::epsilon()) + { return std::abs(a - b) < epsilon; } + + static bool neq(const T& a, const T& b, const T& epsilon = SGLimits::epsilon()) + { return !eq(a, b, epsilon); } }; #endif diff --git a/simgear/misc/sg_path.cxx b/simgear/misc/sg_path.cxx index 299a004c..bbb6a894 100644 --- a/simgear/misc/sg_path.cxx +++ b/simgear/misc/sg_path.cxx @@ -35,9 +35,16 @@ #include #include -#ifdef _WIN32 -# include +#if !defined(SG_WINDOWS) +# include +# include #endif + +#if defined(SG_WINDOWS) +# include +# include +#endif + #include "sg_path.hxx" #include @@ -52,13 +59,13 @@ using simgear::strutils::starts_with; static const char sgDirPathSep = '/'; static const char sgDirPathSepBad = '\\'; -#ifdef _WIN32 +#if defined(SG_WINDOWS) const char SGPath::pathListSep[] = ";"; // this is null-terminated #else const char SGPath::pathListSep[] = ":"; // ditto #endif -#ifdef _WIN32 +#if defined(SG_WINDOWS) #include // for CSIDL // TODO: replace this include file with the official header // included in the Windows 8.1 SDK @@ -1048,3 +1055,40 @@ std::string SGPath::fileUrl() const return {}; } } + +//------------------------------------------------------------------------------ +bool SGPath::touch() +{ + if (!permissionsAllowsWrite()) + { + SG_LOG(SG_IO, SG_WARN, "file touch failed: (" << *this << ")" + " reason: access denied" ); + return false; + } + + if (!exists()) { + SG_LOG(SG_IO, SG_WARN, "file touch failed: (" << *this << ")" + " reason: missing file"); + return false; + } +#if defined(SG_WINDOWS) + auto ws = wstr(); + // set this link for docs on behaviour here, about passing nullptr + // https://msdn.microsoft.com/en-us/library/aa273399(v=vs.60).aspx + if (_wutime(ws.c_str(), nullptr) != 0) { + SG_LOG(SG_IO, SG_WARN, "file touch failed: (" << *this << ")" + " reason: _wutime failed with error:" << simgear::strutils::error_string(errno)); + return false; + } +#else + if (::utime(path.c_str(), nullptr) != 0) { + SG_LOG(SG_IO, SG_WARN, "file touch failed: (" << *this << ")" + " reason: utime failed with error:" << simgear::strutils::error_string(errno)); + return false; + } +#endif + + // reset the cache flag so we re-stat() on next request + _cached = false; + return true; +} diff --git a/simgear/misc/sg_path.hxx b/simgear/misc/sg_path.hxx index a9ef7c03..af37d6ad 100644 --- a/simgear/misc/sg_path.hxx +++ b/simgear/misc/sg_path.hxx @@ -282,6 +282,13 @@ public: */ std::string fileUrl() const; + /** + * Update the file modification timestamp to be 'now'. The contents will + * not be changed. (Same as POSIX 'touch' command). Will fail if the file + * does not exist or permissions do not allow writing. + */ + bool touch(); + enum StandardLocation { HOME, diff --git a/simgear/nasal/cppbind/NasalContext.hxx b/simgear/nasal/cppbind/NasalContext.hxx index 4cbcc8cc..b1ba53d7 100644 --- a/simgear/nasal/cppbind/NasalContext.hxx +++ b/simgear/nasal/cppbind/NasalContext.hxx @@ -44,13 +44,6 @@ namespace nasal Hash newHash(); String newString(const char* str); - /** Create a new nasal vector and fill it with the given values */ - template - naRef newVector(Vals ... vals) - { - return newVector({to_nasal(vals)...}); - } - /** Raise a nasal runtime error */ template void runtimeError(const char* fmt, Args ... args) const @@ -70,6 +63,13 @@ namespace nasal return nasal::to_nasal(_ctx, array); } + /** Create a nasal vector filled with the given values */ + template + naRef to_nasal_vec(Vals ... vals) + { + return newVector({to_nasal(vals)...}); + } + template Me to_me(T arg) const { diff --git a/simgear/nasal/cppbind/detail/from_nasal_helper.hxx b/simgear/nasal/cppbind/detail/from_nasal_helper.hxx index 436dcb3c..a582bfe6 100644 --- a/simgear/nasal/cppbind/detail/from_nasal_helper.hxx +++ b/simgear/nasal/cppbind/detail/from_nasal_helper.hxx @@ -28,14 +28,13 @@ #include #include #include +#include #include #include -#include #include -#include -#include +#include #include #include @@ -143,9 +142,7 @@ namespace nasal * Convert a Nasal number to a C++ numeric type */ template - typename boost::enable_if< boost::is_arithmetic, - T - >::type + std::enable_if_t::value, T> from_nasal_helper(naContext c, naRef ref, const T*) { naRef num = naNumValue(ref); @@ -174,17 +171,39 @@ namespace nasal return vec; } + /** + * Convert a Nasal vector to a std::array + */ + template + std::array + from_nasal_helper(naContext c, naRef ref, const std::array*) + { + if( !naIsVector(ref) ) + throw bad_nasal_cast("Not a vector"); + + if( naVec_size(ref) != N ) + throw bad_nasal_cast( + "Expected vector with " + std::to_string(N) + " elements" + ); + + std::array arr; + + for(std::size_t i = 0; i < N; ++i) + arr[i] = from_nasal_helper(c, naVec_get(ref, i), static_cast(0)); + + return arr; + } + /** * Convert a Nasal vector of 2 elements to a 2d vector */ template - typename boost::enable_if, Vec2>::type + std::enable_if_t::value, Vec2> from_nasal_helper(naContext c, naRef ref, const Vec2*) { - std::vector vec = - from_nasal_helper(c, ref, static_cast*>(0)); - if( vec.size() != 2 ) - throw bad_nasal_cast("Expected vector with two elements"); + auto vec = + from_nasal_helper(c, ref, static_cast*>(0)); + return Vec2(vec[0], vec[1]); } @@ -194,10 +213,8 @@ namespace nasal template SGRect from_nasal_helper(naContext c, naRef ref, const SGRect*) { - std::vector vec = - from_nasal_helper(c, ref, static_cast*>(0)); - if( vec.size() != 4 ) - throw bad_nasal_cast("Expected vector with four elements"); + auto vec = + from_nasal_helper(c, ref, static_cast*>(0)); return SGRect(vec[0], vec[1], vec[2], vec[3]); } diff --git a/simgear/nasal/cppbind/detail/to_nasal_helper.hxx b/simgear/nasal/cppbind/detail/to_nasal_helper.hxx index 7d54fcb6..1098f08e 100644 --- a/simgear/nasal/cppbind/detail/to_nasal_helper.hxx +++ b/simgear/nasal/cppbind/detail/to_nasal_helper.hxx @@ -25,12 +25,13 @@ #include #include #include +#include #include -#include #include -#include +#include +#include #include #include #include @@ -75,11 +76,66 @@ namespace nasal naRef to_nasal_helper(naContext c, const free_function_t& func); + namespace detail + { + template + naRef array_to_nasal(naContext c, const T* arr, size_t size); + } + + /** + * Convert a fixed size array to a Nasal vector + */ + template + naRef to_nasal_helper(naContext c, const T(&array)[N]) + { + return detail::array_to_nasal(c, array, N); + } + + /** + * Convert a fixed size C++ array to a Nasal vector + */ + template + naRef to_nasal_helper(naContext c, const std::array& array) + { + return detail::array_to_nasal(c, array.data(), N); + } + + /** + * Convert a std::initializer_list to a Nasal vector + */ + template + naRef to_nasal_helper(naContext c, std::initializer_list list) + { + return detail::array_to_nasal(c, list.begin(), list.size()); + } + + /** + * Convert std::vector to a Nasal vector + */ + template< template class Vector, + class T, + class Alloc + > + std::enable_if_t< + std::is_same, std::vector>::value, + naRef + > + to_nasal_helper(naContext c, const Vector& vec) + { + return detail::array_to_nasal(c, vec.data(), vec.size()); + } + + /** + * Convert a std::map to a Nasal Hash + */ + template + naRef to_nasal_helper(naContext c, const std::map& map); + /** * Convert an enum value to the according numeric value */ template - typename boost::enable_if< boost::is_enum, naRef >::type + std::enable_if_t::value, naRef> to_nasal_helper(naContext c, T val) { return naNum(val); @@ -89,7 +145,7 @@ namespace nasal * Convert a numeric type to Nasal number */ template - typename boost::enable_if< boost::is_arithmetic, naRef >::type + std::enable_if_t::value, naRef> to_nasal_helper(naContext c, T num) { return naNum(num); @@ -99,67 +155,40 @@ namespace nasal * Convert a 2d vector to Nasal vector with 2 elements */ template - typename boost::enable_if, naRef>::type - to_nasal_helper(naContext c, const Vec2& vec); - - /** - * Convert a std::map to a Nasal Hash - */ - template - naRef to_nasal_helper(naContext c, const std::map& map); - - /** - * Convert a fixed size array to a Nasal vector - */ - template - naRef to_nasal_helper(naContext c, const T(&array)[N]); - - /** - * Convert std::vector to Nasal vector - */ - template< template class Vector, - class T, - class Alloc - > - typename boost::enable_if< boost::is_same< Vector, - std::vector - >, - naRef - >::type - to_nasal_helper(naContext c, const Vector& vec) - { - naRef ret = naNewVector(c); - naVec_setsize(c, ret, static_cast(vec.size())); - for(int i = 0; i < static_cast(vec.size()); ++i) - naVec_set(ret, i, to_nasal_helper(c, vec[i])); - return ret; - } - - //---------------------------------------------------------------------------- - template - typename boost::enable_if, naRef>::type + std::enable_if_t::value, naRef> to_nasal_helper(naContext c, const Vec2& vec) { - // We take just double because in Nasal every number is represented as - // double - double nasal_vec[2] = { + return to_nasal_helper(c, { + // We take just double because in Nasal every number is represented as + // double static_cast(vec[0]), static_cast(vec[1]) - }; - return to_nasal_helper(c, nasal_vec); + }); + } + + /** + * Convert a SGRect to a Nasal vector with position and size of the rect + */ + template + naRef to_nasal_helper(naContext c, const SGRect& rect) + { + return to_nasal_helper(c, { + static_cast(rect.x()), + static_cast(rect.y()), + static_cast(rect.width()), + static_cast(rect.height()) + }); } //---------------------------------------------------------------------------- template - naRef to_nasal_helper(naContext c, const SGRect& rect) + naRef detail::array_to_nasal(naContext c, const T* arr, size_t size) { - std::vector vec(4); - vec[0] = rect.x(); - vec[1] = rect.y(); - vec[2] = rect.width(); - vec[3] = rect.height(); - - return to_nasal_helper(c, vec); + naRef ret = naNewVector(c); + naVec_setsize(c, ret, static_cast(size)); + for(int i = 0; i < static_cast(size); ++i) + naVec_set(ret, i, to_nasal_helper(c, arr[i])); + return ret; } //---------------------------------------------------------------------------- @@ -182,17 +211,6 @@ namespace nasal return hash; } - //---------------------------------------------------------------------------- - template - naRef to_nasal_helper(naContext c, const T(&array)[N]) - { - naRef ret = naNewVector(c); - naVec_setsize(c, ret, static_cast(N)); - for(int i = 0; i < static_cast(N); ++i) - naVec_set(ret, i, to_nasal_helper(c, array[i])); - return ret; - } - } // namespace nasal #endif /* SG_TO_NASAL_HELPER_HXX_ */ diff --git a/simgear/nasal/cppbind/test/cppbind_test.cxx b/simgear/nasal/cppbind/test/cppbind_test.cxx index f2c704ef..73b16e41 100644 --- a/simgear/nasal/cppbind/test/cppbind_test.cxx +++ b/simgear/nasal/cppbind/test/cppbind_test.cxx @@ -117,6 +117,51 @@ naRef f_derivedGetX(const Derived& d, naContext c) } naRef f_freeFunction(nasal::CallContext c) { return c.requireArg(0); } +namespace std +{ + template + ostream& operator<<(ostream& strm, const array& vec) + { + for(auto const& v: vec) + strm << "'" << v << "',"; + return strm; + } +} + +BOOST_AUTO_TEST_CASE( cppbind_arrays ) +{ + TestContext ctx; + + naRef na_vec = ctx.to_nasal_vec(1., 2., 3.42); + BOOST_REQUIRE( naIsVector(na_vec) ); + BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(na_vec, 0)), 1); + BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(na_vec, 1)), 2); + BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(na_vec, 2)), 3.42); + + na_vec = ctx.to_nasal(std::initializer_list({1., 2., 3.42})); + BOOST_REQUIRE( naIsVector(na_vec) ); + BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(na_vec, 0)), 1); + BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(na_vec, 1)), 2); + BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(na_vec, 2)), 3.42); + + using arr_d3_t = std::array; + arr_d3_t std_arr = {1., 2., 3.42}; + na_vec = ctx.to_nasal(std_arr); + BOOST_REQUIRE( naIsVector(na_vec) ); + BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(na_vec, 0)), 1); + BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(na_vec, 1)), 2); + BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(na_vec, 2)), 3.42); + + double d_arr[] = {1., 2., 3.42}; + na_vec = ctx.to_nasal(d_arr); + BOOST_REQUIRE( naIsVector(na_vec) ); + BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(na_vec, 0)), 1); + BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(na_vec, 1)), 2); + BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(na_vec, 2)), 3.42); + + BOOST_CHECK_EQUAL(std_arr, ctx.from_nasal(na_vec)); +} + BOOST_AUTO_TEST_CASE( cppbind_misc_testing ) { TestContext c; @@ -439,7 +484,7 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing ) BOOST_AUTO_TEST_CASE( cppbind_context ) { nasal::Context ctx; - naRef vec = ctx.newVector(1, 2, 3.4, "test"); + naRef vec = ctx.to_nasal_vec(1, 2, 3.4, "test"); BOOST_REQUIRE( naIsVector(vec) ); BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(vec, 0)), 1); diff --git a/simgear/package/Root.cxx b/simgear/package/Root.cxx index a0918525..c8eac52a 100644 --- a/simgear/package/Root.cxx +++ b/simgear/package/Root.cxx @@ -164,13 +164,23 @@ public: // (eg Ibiblio) and retry up to the max count const int retries = (thumbnailCache[u].retryCount++); if (retries < 3) { - SG_LOG(SG_IO, SG_INFO, "Download failed for: " << u << ", will retry"); + SG_LOG(SG_IO, SG_DEBUG, "Download failed for: " << u << ", will retry"); thumbnailCache[u].requestPending = true; pendingThumbnails.push_back(u); } } else { // any other failure. thumbnailCache[u].requestPending = false; + + // if this was a cache refresh, let's report the cached data instead + SGPath cachePath = pathInCache(u); + if (cachePath.exists()) { + SG_LOG(SG_IO, SG_WARN, "Download failed for: " << u << ", will use old cached data"); + cachePath.touch(); // touch the file so we don't repeat this danxce + // kick a load from the cache + + queueLoadFromPersistentCache(u, cachePath); + } } downloadNextPendingThumbnail(); @@ -208,16 +218,23 @@ public: } } - void addToPersistentCache(const std::string& url, const std::string& imageBytes) + SGPath pathInCache(const std::string& url) const { - std::string hash = hashForUrl(url); + const auto hash = hashForUrl(url); // append the correct file suffix auto pos = url.rfind('.'); if (pos == std::string::npos) { - return; + return SGPath(); } - SGPath cachePath = path / "ThumbnailCache" / (hash + url.substr(pos)); + return path / "ThumbnailCache" / (hash + url.substr(pos)); + } + + void addToPersistentCache(const std::string& url, const std::string& imageBytes) + { + // this will over-write the existing file if we are refreshing, + // since we use 'truncatr' to open the new file + SGPath cachePath = pathInCache(url); sg_ofstream fstream(cachePath, std::ios::out | std::ios::trunc | std::ios::binary); fstream.write(imageBytes.data(), imageBytes.size()); fstream.close(); @@ -229,23 +246,17 @@ public: bool checkPersistentCache(const std::string& url) { - std::string hash = hashForUrl(url); - // append the correct file suffix - auto pos = url.rfind('.'); - if (pos == std::string::npos) { - return false; - } - - SGPath cachePath = path / "ThumbnailCache" / (hash + url.substr(pos)); + SGPath cachePath = pathInCache(url); if (!cachePath.exists()) { return false; } // check age, if it's too old, expire and download again int age = time(nullptr) - cachePath.modTime(); - if (age > SECONDS_PER_DAY * 7) { // cache for seven days - SG_LOG(SG_IO, SG_INFO, "expiring old cached thumbnail " << url); - cachePath.remove(); + const int cacheMaxAge = SECONDS_PER_DAY * 7; + if (age > cacheMaxAge) { // cache for seven days + // note we do *not* remove the file data here, since the + // cache refresh might fail return false; } @@ -263,7 +274,7 @@ public: entry.pathOnDisk = path; it = thumbnailCache.insert(it, std::make_pair(url, entry)); } else { - assert(it->second.pathOnDisk == path); + assert(it->second.pathOnDisk.isNull() || (it->second.pathOnDisk == path)); } if (it->second.requestPending) { diff --git a/simgear/props/PropertyBasedElement.cxx b/simgear/props/PropertyBasedElement.cxx index b53a3876..621a1b91 100644 --- a/simgear/props/PropertyBasedElement.cxx +++ b/simgear/props/PropertyBasedElement.cxx @@ -18,7 +18,7 @@ #include #include "PropertyBasedElement.hxx" -#include +#include namespace simgear { @@ -130,7 +130,7 @@ namespace simgear // character that followed it by the same character converted to ASCII // uppercase. - if( !boost::starts_with(name, DATA_PREFIX) ) + if( !strutils::starts_with(name, DATA_PREFIX) ) return std::string(); std::string data_name; diff --git a/simgear/props/PropertyBasedElement.hxx b/simgear/props/PropertyBasedElement.hxx index c43fef2a..ad019805 100644 --- a/simgear/props/PropertyBasedElement.hxx +++ b/simgear/props/PropertyBasedElement.hxx @@ -20,6 +20,7 @@ #define SG_PROPERTY_BASED_ELEMENT_HXX_ #include +#include #include namespace simgear @@ -120,11 +121,9 @@ namespace simgear * @see setDataProp */ template - typename boost::disable_if< - boost::is_same, - T - >::type getDataProp( const std::string& name, - const T& def = T() ) const + std::enable_if_t::value, T> + getDataProp( const std::string& name, + const T& def = {} ) const { SGPropertyNode* node = getDataProp(name); if( node ) @@ -140,11 +139,9 @@ namespace simgear * @see setDataProp */ template - typename boost::enable_if< - boost::is_same, - T - >::type getDataProp( const std::string& name, - SGPropertyNode* = NULL ) const + std::enable_if_t::value, T> + getDataProp( const std::string& name, + SGPropertyNode* = nullptr ) const { const std::string& attr = dataPropToAttrName(name); if( attr.empty() ) diff --git a/simgear/props/props.cxx b/simgear/props/props.cxx index b0dbd10c..1c21ecee 100644 --- a/simgear/props/props.cxx +++ b/simgear/props/props.cxx @@ -827,7 +827,7 @@ SGPropertyNode::trace_read () const * Last used attribute * Update as needed when enum Attribute is changed */ -const int SGPropertyNode::LAST_USED_ATTRIBUTE = PRESERVE; +const int SGPropertyNode::LAST_USED_ATTRIBUTE = PROTECTED; /** * Default constructor: always creates a root node. diff --git a/simgear/props/props.hxx b/simgear/props/props.hxx index 4c2bb242..18512f18 100644 --- a/simgear/props/props.hxx +++ b/simgear/props/props.hxx @@ -814,7 +814,8 @@ public: TRACE_READ = 16, TRACE_WRITE = 32, USERARCHIVE = 64, - PRESERVE = 128 + PRESERVE = 128, + PROTECTED = 1 << 8, // beware: if you add another attribute here, // also update value of "LAST_USED_ATTRIBUTE". }; @@ -1854,7 +1855,7 @@ private: mutable std::string _buffer; simgear::props::Type _type; bool _tied; - int _attr; + int _attr = NO_ATTR; // The right kind of pointer... union { diff --git a/simgear/props/props_io.cxx b/simgear/props/props_io.cxx index a0e0b90b..ee432b33 100644 --- a/simgear/props/props_io.cxx +++ b/simgear/props/props_io.cxx @@ -251,6 +251,9 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts) setFlag(mode, SGPropertyNode::USERARCHIVE, val, location); else if( att_name == "preserve" ) setFlag(mode, SGPropertyNode::PRESERVE, val, location); + // note we intentionally don't handle PROTECTED here, it's + // designed to be only set from compiled code, not loaded + // dynamically. // Check for an alias. else if( att_name == "alias" ) diff --git a/simgear/sound/sample_group.cxx b/simgear/sound/sample_group.cxx index bbd38590..12bbd3ba 100644 --- a/simgear/sound/sample_group.cxx +++ b/simgear/sound/sample_group.cxx @@ -137,10 +137,8 @@ void SGSampleGroup::update( double dt ) { _changed = false; } - sample_map_iterator sample_current = _samples.begin(); - sample_map_iterator sample_end = _samples.end(); - for ( ; sample_current != sample_end; ++sample_current ) { - SGSoundSample *sample = sample_current->second; + for (auto current =_samples.begin(); current !=_samples.end(); ++current) { + SGSoundSample *sample = current->second; if ( !sample->is_valid_source() && sample->is_playing() && !sample->test_out_of_range()) { start_playing_sample(sample); @@ -156,7 +154,7 @@ void SGSampleGroup::update( double dt ) { bool SGSampleGroup::add( SGSharedPtr sound, const std::string& refname ) { - sample_map_iterator sample_it = _samples.find( refname ); + auto sample_it = _samples.find( refname ); if ( sample_it != _samples.end() ) { // sample name already exists return false; @@ -170,7 +168,7 @@ bool SGSampleGroup::add( SGSharedPtr sound, // remove a sound effect, return true if successful bool SGSampleGroup::remove( const std::string &refname ) { - sample_map_iterator sample_it = _samples.find( refname ); + auto sample_it = _samples.find( refname ); if ( sample_it == _samples.end() ) { // sample was not found return false; @@ -187,7 +185,7 @@ bool SGSampleGroup::remove( const std::string &refname ) { // return true of the specified sound exists in the sound manager system bool SGSampleGroup::exists( const std::string &refname ) { - sample_map_iterator sample_it = _samples.find( refname ); + auto sample_it = _samples.find( refname ); if ( sample_it == _samples.end() ) { // sample was not found return false; @@ -200,7 +198,7 @@ bool SGSampleGroup::exists( const std::string &refname ) { // return a pointer to the SGSoundSample if the specified sound exists // in the sound manager system, otherwise return NULL SGSoundSample *SGSampleGroup::find( const std::string &refname ) { - sample_map_iterator sample_it = _samples.find( refname ); + auto sample_it = _samples.find( refname ); if ( sample_it == _samples.end() ) { // sample was not found return NULL; @@ -214,10 +212,8 @@ void SGSampleGroup::stop () { _pause = true; - sample_map_iterator sample_current = _samples.begin(); - sample_map_iterator sample_end = _samples.end(); - for ( ; sample_current != sample_end; ++sample_current ) { - SGSoundSample *sample = sample_current->second; + for (auto current =_samples.begin(); current !=_samples.end(); ++current) { + SGSoundSample *sample = current->second; _smgr->sample_destroy( sample ); } } @@ -228,11 +224,9 @@ SGSampleGroup::suspend () { if (_active && _pause == false) { _pause = true; - sample_map_iterator sample_current = _samples.begin(); - sample_map_iterator sample_end = _samples.end(); - for ( ; sample_current != sample_end; ++sample_current ) { + for (auto current =_samples.begin(); current !=_samples.end(); ++current) { #ifdef ENABLE_SOUND - SGSoundSample *sample = sample_current->second; + SGSoundSample *sample = current->second; _smgr->sample_suspend( sample ); #endif } @@ -246,10 +240,8 @@ SGSampleGroup::resume () { if (_active && _pause == true) { #ifdef ENABLE_SOUND - sample_map_iterator sample_current = _samples.begin(); - sample_map_iterator sample_end = _samples.end(); - for ( ; sample_current != sample_end; ++sample_current ) { - SGSoundSample *sample = sample_current->second; + for (auto current =_samples.begin(); current !=_samples.end(); ++current) { + SGSoundSample *sample = current->second; _smgr->sample_resume( sample ); } testForMgrError("resume"); @@ -319,10 +311,8 @@ void SGSampleGroup::update_pos_and_orientation() { velocity = toVec3f( hlOr.backTransform(_velocity*SG_FEET_TO_METER) ); } - sample_map_iterator sample_current = _samples.begin(); - sample_map_iterator sample_end = _samples.end(); - for ( ; sample_current != sample_end; ++sample_current ) { - SGSoundSample *sample = sample_current->second; + for (auto current =_samples.begin(); current !=_samples.end(); ++current ) { + SGSoundSample *sample = current->second; sample->set_master_volume( _volume ); sample->set_orientation( _orientation ); sample->set_rotation( ec2body ); diff --git a/simgear/sound/sample_group.hxx b/simgear/sound/sample_group.hxx index 8db767ff..a40dee47 100644 --- a/simgear/sound/sample_group.hxx +++ b/simgear/sound/sample_group.hxx @@ -40,8 +40,6 @@ typedef std::map < std::string, SGSharedPtr > sample_map; -typedef sample_map::iterator sample_map_iterator; -typedef sample_map::const_iterator const_sample_map_iterator; class SGSoundMgr; diff --git a/simgear/sound/soundmgr_aeonwave.cxx b/simgear/sound/soundmgr_aeonwave.cxx index 0ba9d33b..383c6039 100644 --- a/simgear/sound/soundmgr_aeonwave.cxx +++ b/simgear/sound/soundmgr_aeonwave.cxx @@ -36,7 +36,6 @@ #include #include -#include #include #include "soundmgr.hxx" @@ -50,17 +49,10 @@ // We keep track of the emitters ourselves. typedef std::map < unsigned int, aax::Emitter > source_map; -typedef source_map::iterator source_map_iterator; -typedef source_map::const_iterator const_source_map_iterator; // The AeonWave class keeps track of the buffers, so use a reference instead. typedef std::map < unsigned int, aax::Buffer& > buffer_map; -typedef buffer_map::iterator buffer_map_iterator; -typedef buffer_map::const_iterator const_buffer_map_iterator; - typedef std::map < std::string, SGSharedPtr > sample_group_map; -typedef sample_group_map::iterator sample_group_map_iterator; -typedef sample_group_map::const_iterator const_sample_group_map_iterator; #ifndef NDEBUG # define TRY(a) if ((a) == 0) printf("%i: %s\n", __LINE__, d->_aax.strerror()) @@ -83,8 +75,7 @@ public: ~SoundManagerPrivate() { - std::vector::iterator it; - for (it = _devices.begin(); it != _devices.end(); ++it) { + for (auto it = _devices.begin(); it != _devices.end(); ++it) { free((void*)*it); } _devices.clear(); @@ -117,7 +108,7 @@ public: buffer_map _buffers; aax::Buffer nullBuffer; aax::Buffer& get_buffer(unsigned int id) { - buffer_map_iterator buffer_it = _buffers.find(id); + auto buffer_it = _buffers.find(id); if ( buffer_it != _buffers.end() ) return buffer_it->second; SG_LOG(SG_SOUND, SG_ALERT, "unknown buffer id requested."); return nullBuffer; @@ -127,7 +118,7 @@ public: source_map _sources; aax::Emitter nullEmitter; aax::Emitter& get_emitter(unsigned int id) { - source_map_iterator source_it = _sources.find(id); + auto source_it = _sources.find(id); if ( source_it != _sources.end() ) return source_it->second; SG_LOG(SG_SOUND, SG_ALERT, "unknown source id requested."); return nullEmitter; @@ -149,6 +140,7 @@ SGSoundMgr::SGSoundMgr() : _changed(true), _volume(0.0), _velocity(SGVec3d::zeros()), + _bad_doppler(false), _renderer("unknown"), _vendor("unknown") { @@ -243,10 +235,9 @@ void SGSoundMgr::activate() if ( is_working() ) { _active = true; - sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); - sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); - for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { - SGSampleGroup *sgrp = sample_grp_current->second; + for ( auto current = d->_sample_groups.begin(); + current != d->_sample_groups.end(); ++current ) { + SGSampleGroup *sgrp = current->second; sgrp->activate(); } } @@ -258,10 +249,9 @@ void SGSoundMgr::stop() { #ifdef ENABLE_SOUND // first stop all sample groups - sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); - sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); - for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { - SGSampleGroup *sgrp = sample_grp_current->second; + for ( auto current = d->_sample_groups.begin(); + current != d->_sample_groups.end(); ++ current ) { + SGSampleGroup *sgrp = current->second; sgrp->stop(); } @@ -285,10 +275,9 @@ void SGSoundMgr::suspend() { #ifdef ENABLE_SOUND if (is_working()) { - sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); - sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); - for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { - SGSampleGroup *sgrp = sample_grp_current->second; + for (auto current = d->_sample_groups.begin(); + current != d->_sample_groups.end(); ++current ) { + SGSampleGroup *sgrp = current->second; sgrp->stop(); } _active = false; @@ -300,10 +289,9 @@ void SGSoundMgr::resume() { #ifdef ENABLE_SOUND if (is_working()) { - sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); - sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); - for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { - SGSampleGroup *sgrp = sample_grp_current->second; + for ( auto current = d->_sample_groups.begin(); + current != d->_sample_groups.end(); ++current ) { + SGSampleGroup *sgrp = current->second; sgrp->resume(); } _active = true; @@ -320,10 +308,9 @@ void SGSoundMgr::update( double dt ) d->update_pos_and_orientation(); } - sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); - sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); - for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { - SGSampleGroup *sgrp = sample_grp_current->second; + for ( auto current = d->_sample_groups.begin(); + current != d->_sample_groups.end(); ++current ) { + SGSampleGroup *sgrp = current->second; sgrp->update(dt); } @@ -360,7 +347,7 @@ void SGSoundMgr::update( double dt ) // add a sample group, return true if successful bool SGSoundMgr::add( SGSampleGroup *sgrp, const std::string& refname ) { - sample_group_map_iterator sample_grp_it = d->_sample_groups.find( refname ); + auto sample_grp_it = d->_sample_groups.find( refname ); if ( sample_grp_it != d->_sample_groups.end() ) { // sample group already exists return false; @@ -376,7 +363,7 @@ bool SGSoundMgr::add( SGSampleGroup *sgrp, const std::string& refname ) // remove a sound effect, return true if successful bool SGSoundMgr::remove( const std::string &refname ) { - sample_group_map_iterator sample_grp_it = d->_sample_groups.find( refname ); + auto sample_grp_it = d->_sample_groups.find( refname ); if ( sample_grp_it == d->_sample_groups.end() ) { // sample group was not found. return false; @@ -390,7 +377,7 @@ bool SGSoundMgr::remove( const std::string &refname ) // return true of the specified sound exists in the sound manager system bool SGSoundMgr::exists( const std::string &refname ) { - sample_group_map_iterator sample_grp_it = d->_sample_groups.find( refname ); + auto sample_grp_it = d->_sample_groups.find( refname ); return ( sample_grp_it != d->_sample_groups.end() ); } @@ -398,7 +385,7 @@ bool SGSoundMgr::exists( const std::string &refname ) { // return a pointer to the SGSampleGroup if the specified sound exists // in the sound manager system, otherwise return NULL SGSampleGroup *SGSoundMgr::find( const std::string &refname, bool create ) { - sample_group_map_iterator sample_grp_it = d->_sample_groups.find( refname ); + auto sample_grp_it = d->_sample_groups.find( refname ); if ( sample_grp_it == d->_sample_groups.end() ) { // sample group was not found. if (create) { @@ -432,7 +419,7 @@ unsigned int SGSoundMgr::request_source() // Free up a source id void SGSoundMgr::release_source( unsigned int source ) { - source_map_iterator source_it = d->_sources.find(source); + auto source_it = d->_sources.find(source); if ( source_it != d->_sources.end() ) { aax::Emitter& emitter = source_it->second; @@ -527,7 +514,7 @@ void SGSoundMgr::release_buffer(SGSoundSample *sample) if ( !sample->is_queue() ) { unsigned int buffer = sample->get_buffer(); - buffer_map_iterator buffer_it = d->_buffers.find(buffer); + auto buffer_it = d->_buffers.find(buffer); if ( buffer_it != d->_buffers.end() ) { sample->no_valid_buffer(); diff --git a/simgear/sound/soundmgr_openal.cxx b/simgear/sound/soundmgr_openal.cxx index f437cee2..64a706df 100644 --- a/simgear/sound/soundmgr_openal.cxx +++ b/simgear/sound/soundmgr_openal.cxx @@ -36,8 +36,6 @@ #include #include -#include - #include "soundmgr.hxx" #include "readwav.hxx" #include "soundmgr_openal_private.hxx" @@ -283,10 +281,9 @@ void SGSoundMgr::activate() if ( is_working() ) { _active = true; - sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); - sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); - for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { - SGSampleGroup *sgrp = sample_grp_current->second; + for ( auto current = d->_sample_groups.begin(); + current != d->_sample_groups.end(); ++current ) { + SGSampleGroup *sgrp = current->second; sgrp->activate(); } } @@ -298,25 +295,23 @@ void SGSoundMgr::stop() { #ifdef ENABLE_SOUND // first stop all sample groups - sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); - sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); - for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { - SGSampleGroup *sgrp = sample_grp_current->second; + for ( auto current = d->_sample_groups.begin(); + current != d->_sample_groups.end(); ++current ) { + SGSampleGroup *sgrp = current->second; sgrp->stop(); } // clear all OpenAL sources - BOOST_FOREACH(ALuint source, d->_free_sources) { + for(ALuint source : d->_free_sources) { alDeleteSources( 1 , &source ); testForError("SGSoundMgr::stop: delete sources"); } d->_free_sources.clear(); // clear any OpenAL buffers before shutting down - buffer_map_iterator buffers_current = d->_buffers.begin(); - buffer_map_iterator buffers_end = d->_buffers.end(); - for ( ; buffers_current != buffers_end; ++buffers_current ) { - refUint ref = buffers_current->second; + for ( auto current = d->_buffers.begin(); + current != d->_buffers.begin(); ++current ) { + refUint ref = current->second; ALuint buffer = ref.id; alDeleteBuffers(1, &buffer); testForError("SGSoundMgr::stop: delete buffers"); @@ -342,10 +337,9 @@ void SGSoundMgr::suspend() { #ifdef ENABLE_SOUND if (is_working()) { - sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); - sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); - for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { - SGSampleGroup *sgrp = sample_grp_current->second; + for ( auto current = d->_sample_groups.begin(); + current != d->_sample_groups.end(); ++current ) { + SGSampleGroup *sgrp = current->second; sgrp->stop(); } _active = false; @@ -357,10 +351,9 @@ void SGSoundMgr::resume() { #ifdef ENABLE_SOUND if (is_working()) { - sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); - sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); - for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { - SGSampleGroup *sgrp = sample_grp_current->second; + for ( auto current = d->_sample_groups.begin(); + current != d->_sample_groups.end(); ++current ) { + SGSampleGroup *sgrp = current->second; sgrp->resume(); } _active = true; @@ -379,10 +372,9 @@ void SGSoundMgr::update( double dt ) d->update_pos_and_orientation(); } - sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); - sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); - for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { - SGSampleGroup *sgrp = sample_grp_current->second; + for ( auto current = d->_sample_groups.begin(); + current != d->_sample_groups.end(); ++current ) { + SGSampleGroup *sgrp = current->second; sgrp->update(dt); } @@ -420,7 +412,7 @@ if (isNaN(toVec3f(_velocity).data())) printf("NaN in listener velocity\n"); // add a sample group, return true if successful bool SGSoundMgr::add( SGSampleGroup *sgrp, const std::string& refname ) { - sample_group_map_iterator sample_grp_it = d->_sample_groups.find( refname ); + auto sample_grp_it = d->_sample_groups.find( refname ); if ( sample_grp_it != d->_sample_groups.end() ) { // sample group already exists return false; @@ -436,7 +428,7 @@ bool SGSoundMgr::add( SGSampleGroup *sgrp, const std::string& refname ) // remove a sound effect, return true if successful bool SGSoundMgr::remove( const std::string &refname ) { - sample_group_map_iterator sample_grp_it = d->_sample_groups.find( refname ); + auto sample_grp_it = d->_sample_groups.find( refname ); if ( sample_grp_it == d->_sample_groups.end() ) { // sample group was not found. return false; @@ -450,7 +442,7 @@ bool SGSoundMgr::remove( const std::string &refname ) // return true of the specified sound exists in the sound manager system bool SGSoundMgr::exists( const std::string &refname ) { - sample_group_map_iterator sample_grp_it = d->_sample_groups.find( refname ); + auto sample_grp_it = d->_sample_groups.find( refname ); return ( sample_grp_it != d->_sample_groups.end() ); } @@ -458,7 +450,7 @@ bool SGSoundMgr::exists( const std::string &refname ) { // return a pointer to the SGSampleGroup if the specified sound exists // in the sound manager system, otherwise return NULL SGSampleGroup *SGSoundMgr::find( const std::string &refname, bool create ) { - sample_group_map_iterator sample_grp_it = d->_sample_groups.find( refname ); + auto sample_grp_it = d->_sample_groups.find( refname ); if ( sample_grp_it == d->_sample_groups.end() ) { // sample group was not found. if (create) { @@ -508,9 +500,7 @@ unsigned int SGSoundMgr::request_source() // Free up a source id for further use void SGSoundMgr::release_source( unsigned int source ) { - vector::iterator it; - - it = std::find(d->_sources_in_use.begin(), d->_sources_in_use.end(), source); + auto it = std::find(d->_sources_in_use.begin(), d->_sources_in_use.end(), source); if ( it != d->_sources_in_use.end() ) { #ifdef ENABLE_SOUND ALint result; @@ -538,7 +528,7 @@ unsigned int SGSoundMgr::request_buffer(SGSoundSample *sample) void *sample_data = NULL; // see if the sample name is already cached - buffer_map_iterator buffer_it = d->_buffers.find( sample_name ); + auto buffer_it = d->_buffers.find( sample_name ); if ( buffer_it != d->_buffers.end() ) { buffer_it->second.refctr++; buffer = buffer_it->second.id; @@ -632,7 +622,7 @@ void SGSoundMgr::release_buffer(SGSoundSample *sample) if ( !sample->is_queue() ) { std::string sample_name = sample->get_sample_name(); - buffer_map_iterator buffer_it = d->_buffers.find( sample_name ); + auto buffer_it = d->_buffers.find( sample_name ); if ( buffer_it == d->_buffers.end() ) { // buffer was not found return; diff --git a/simgear/sound/soundmgr_openal_private.hxx b/simgear/sound/soundmgr_openal_private.hxx index 70ba23af..e6407378 100644 --- a/simgear/sound/soundmgr_openal_private.hxx +++ b/simgear/sound/soundmgr_openal_private.hxx @@ -64,12 +64,7 @@ struct refUint { }; typedef std::map < std::string, refUint > buffer_map; -typedef buffer_map::iterator buffer_map_iterator; -typedef buffer_map::const_iterator const_buffer_map_iterator; - typedef std::map < std::string, SGSharedPtr > sample_group_map; -typedef sample_group_map::iterator sample_group_map_iterator; -typedef sample_group_map::const_iterator const_sample_group_map_iterator; inline bool isNaN(float *v) { return (SGMisc::isNaN(v[0]) || SGMisc::isNaN(v[1]) || SGMisc::isNaN(v[2])); diff --git a/simgear/structure/SGBinding.cxx b/simgear/structure/SGBinding.cxx index 320e13a1..1f87ca95 100644 --- a/simgear/structure/SGBinding.cxx +++ b/simgear/structure/SGBinding.cxx @@ -41,12 +41,6 @@ SGBinding::SGBinding(const SGPropertyNode* node, SGPropertyNode* root) read(node, root); } -SGBinding::~SGBinding() -{ - if(_arg && _arg->getParent()) - _arg->getParent()->removeChild(_arg->getName(), _arg->getIndex()); -} - void SGBinding::clear() { diff --git a/simgear/structure/SGBinding.hxx b/simgear/structure/SGBinding.hxx index 3574a524..ed3a951c 100644 --- a/simgear/structure/SGBinding.hxx +++ b/simgear/structure/SGBinding.hxx @@ -58,13 +58,14 @@ public: /** * Destructor. */ - virtual ~SGBinding (); + virtual ~SGBinding () = default; /** - * clear internal state of the binding back to empty. This is useful - * if you don't want the 'remove on delete' behaviour of the - * destructor. + * Clear internal state of the binding back to empty. + * + * This was particularly useful when SGBinding's destructor had its 'remove + * on delete' behaviour, however this is not the case anymore. */ void clear(); diff --git a/simgear/timing/timestamp.cxx b/simgear/timing/timestamp.cxx index f7e9fdf4..7553d322 100644 --- a/simgear/timing/timestamp.cxx +++ b/simgear/timing/timestamp.cxx @@ -29,6 +29,7 @@ #include #include +#include #ifdef HAVE_UNISTD_H # include // for gettimeofday() and the _POSIX_TIMERS define @@ -98,6 +99,21 @@ void SGTimeStamp::stamp() #endif } +void SGTimeStamp::systemClockHoursAndMinutes() +{ + using namespace std; + using namespace std::chrono; + + typedef duration >::type> days; + + system_clock::time_point now = system_clock::now(); + system_clock::duration tp = now.time_since_epoch(); + tp -= duration_cast(tp); + + _sec = duration_cast(tp).count(); + _nsec = duration_cast(tp - seconds(_sec)).count(); +} + // sleep based timing loop. // // Calling sleep, even usleep() on linux is less accurate than diff --git a/simgear/timing/timestamp.hxx b/simgear/timing/timestamp.hxx index ac9ca142..266fd2ab 100644 --- a/simgear/timing/timestamp.hxx +++ b/simgear/timing/timestamp.hxx @@ -78,6 +78,13 @@ public: /** Update stored time to current time (seconds and nanoseconds) */ void stamp(); + /** Update stored time to current system clock (seconds and nanoseconds) + * non monotonic, keeping only hours, minutes, seconds and decimals, + * so restart at 0 at midnight. + * using the std::chrono libs + */ + void systemClockHoursAndMinutes(); + /** Set the time from a double value */ void setTime(const double& seconds) { diff --git a/version b/version index 310bd2fc..26b1d26a 100644 --- a/version +++ b/version @@ -1 +1 @@ -2017.4.0 +2018.2.0