diff --git a/simgear/canvas/Canvas.cxx b/simgear/canvas/Canvas.cxx index 1beef721..9b3ae44c 100644 --- a/simgear/canvas/Canvas.cxx +++ b/simgear/canvas/Canvas.cxx @@ -226,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() ) @@ -251,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() ) { diff --git a/simgear/canvas/CanvasWindow.cxx b/simgear/canvas/CanvasWindow.cxx index 65dc9fbb..0e6b52bd 100644 --- a/simgear/canvas/CanvasWindow.cxx +++ b/simgear/canvas/CanvasWindow.cxx @@ -98,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 8d08a56a..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; diff --git a/simgear/canvas/elements/CanvasElement.cxx b/simgear/canvas/elements/CanvasElement.cxx index 795a1d95..7efcd6f0 100644 --- a/simgear/canvas/elements/CanvasElement.cxx +++ b/simgear/canvas/elements/CanvasElement.cxx @@ -210,14 +210,14 @@ 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. - for(osg::Group* parent: group->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 @@ -225,7 +225,7 @@ namespace canvas removeListener(); _parent = nullptr; - _transform = nullptr; + _scene_group = nullptr; } //---------------------------------------------------------------------------- @@ -243,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); } //---------------------------------------------------------------------------- @@ -393,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; } @@ -404,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), @@ -485,9 +461,6 @@ namespace canvas { if( child->getNameString() == NAME_TRANSFORM ) { - if( !_transform.valid() ) - return; - if( child->getIndex() >= static_cast(_transform_types.size()) ) { SG_LOG @@ -563,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; @@ -617,7 +594,7 @@ namespace canvas } if( !_scissor ) - _scissor = new RelativeScissor(_transform.get()); + _scissor = new RelativeScissor(_scene_group.get()); // , , , _scissor->x() = values[3]; @@ -641,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 @@ -674,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; } @@ -709,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(); } //---------------------------------------------------------------------------- @@ -789,7 +704,7 @@ namespace canvas PropertyBasedElement(node), _canvas( canvas ), _parent( parent ), - _transform( new osg::MatrixTransform ), + _scene_group( new osg::MatrixTransform ), _style( parent_style ) { staticInit(); @@ -802,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) ); } //---------------------------------------------------------------------------- @@ -898,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); } //---------------------------------------------------------------------------- @@ -910,10 +835,10 @@ 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; } //---------------------------------------------------------------------------- @@ -923,5 +848,96 @@ namespace canvas 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 d7944b36..fe22aa3c 100644 --- a/simgear/canvas/elements/CanvasElement.hxx +++ b/simgear/canvas/elements/CanvasElement.hxx @@ -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. @@ -254,8 +258,8 @@ namespace canvas 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 = nullptr; @@ -585,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 922985b8..02696cde 100644 --- a/simgear/canvas/elements/CanvasGroup.cxx +++ b/simgear/canvas/elements/CanvasGroup.cxx @@ -45,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, @@ -132,28 +132,28 @@ namespace canvas //---------------------------------------------------------------------------- ElementPtr Group::getElementById(const std::string& id) { - if( !_transform.valid() ) + if( !_scene_group.valid() ) { - warnTransformExpired("getElementById"); + 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); } - for(auto group: groups) + for(auto group: child_groups) { - ElementPtr el = group->getElementById(id); - if( el ) + if( ElementPtr el = group->getElementById(id) ) return el; } @@ -163,32 +163,26 @@ namespace canvas //---------------------------------------------------------------------------- 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; } @@ -203,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); } @@ -219,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; @@ -254,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) { @@ -263,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); @@ -290,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; @@ -330,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 @@ -366,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 ( @@ -380,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"); + 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); 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 e2166b30..4c3aaec9 100644 --- a/simgear/canvas/elements/CanvasImage.cxx +++ b/simgear/canvas/elements/CanvasImage.cxx @@ -155,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) @@ -400,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) { diff --git a/simgear/canvas/elements/CanvasImage.hxx b/simgear/canvas/elements/CanvasImage.hxx index 5ec50ab4..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); @@ -109,6 +108,8 @@ namespace canvas SRC_CANVAS = DEST_SIZE << 1 }; + virtual void updateImpl(double dt); + virtual void childChanged(SGPropertyNode * child); void setupDefaultDimensions(); diff --git a/simgear/canvas/elements/CanvasMap.cxx b/simgear/canvas/elements/CanvasMap.cxx index 2100cd31..35763198 100644 --- a/simgear/canvas/elements/CanvasMap.cxx +++ b/simgear/canvas/elements/CanvasMap.cxx @@ -85,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; @@ -113,8 +113,6 @@ namespace canvas geo_node->setDirty(false); } _projection_dirty = false; - - Group::update(dt); } //---------------------------------------------------------------------------- diff --git a/simgear/canvas/elements/CanvasMap.hxx b/simgear/canvas/elements/CanvasMap.hxx index f1e61ed9..ca0521f0 100644 --- a/simgear/canvas/elements/CanvasMap.hxx +++ b/simgear/canvas/elements/CanvasMap.hxx @@ -45,17 +45,17 @@ 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); + + 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>; diff --git a/simgear/canvas/elements/CanvasPath.cxx b/simgear/canvas/elements/CanvasPath.cxx index c8b6414c..a118aa84 100644 --- a/simgear/canvas/elements/CanvasPath.cxx +++ b/simgear/canvas/elements/CanvasPath.cxx @@ -690,40 +690,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 { @@ -829,6 +795,39 @@ 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) { diff --git a/simgear/canvas/elements/CanvasPath.hxx b/simgear/canvas/elements/CanvasPath.hxx index 1c2d2878..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 */ @@ -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