canvas: Refactor and protect against expired pointers

This commit is contained in:
Thomas Geymayer
2018-01-28 00:40:37 +01:00
parent 087ea4c5f3
commit 4edd3f45b7
14 changed files with 497 additions and 475 deletions

View File

@@ -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<osg::Group> 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() )
{

View File

@@ -98,16 +98,10 @@ namespace canvas
Image::valueChanged(node);
}
//----------------------------------------------------------------------------
osg::Group* Window::getGroup()
{
return getMatrixTransform();
}
//----------------------------------------------------------------------------
const SGVec2<float> Window::getPosition() const
{
const osg::Matrix& m = getMatrixTransform()->getMatrix();
auto const& m = getMatrix();
return SGVec2<float>( m(3, 0), m(3, 1) );
}

View File

@@ -70,7 +70,6 @@ namespace canvas
virtual void update(double delta_time_sec);
virtual void valueChanged(SGPropertyNode* node);
osg::Group* getGroup();
const SGVec2<float> getPosition() const;
const SGRect<float> getScreenRegion() const;

View File

@@ -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<int>(_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());
// <top>, <right>, <bottom>, <left>
_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<osg::Geode> 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

View File

@@ -49,6 +49,7 @@ namespace canvas
public PropertyBasedElement
{
public:
using SceneGroupWeakPtr = osg::observer_ptr<osg::MatrixTransform>;
/**
* 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<osg::MatrixTransform> _transform;
std::vector<TransformType> _transform_types;
SceneGroupWeakPtr _scene_group;
std::vector<TransformType> _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<osg::Drawable> _drawable;

View File

@@ -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<GroupPtr> 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<GroupPtr> child_groups;
for(size_t i = 0; i < _scene_group->getNumChildren(); ++i)
{
const ElementPtr& el = getChildByIndex(i);
if( el->get<std::string>("id") == id )
return el;
Group* group = dynamic_cast<Group*>(el.get());
if( group )
groups.push_back(group);
if( Group* child_group = dynamic_cast<Group*>(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<osg::MatrixTransform> tf = child->getMatrixTransform();
size_t index = _transform->getChildIndex(tf),
// Keep reference to prevent deleting while removing and re-inserting later
osg::ref_ptr<osg::MatrixTransform> 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<OSGUserData*>(_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<OSGUserData*>(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);

View File

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

View File

@@ -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<CullCallback*>
#else
dynamic_cast<CullCallback*>
#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<osg::Image> 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<float>& 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<float>& 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<MouseEvent*>(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<KeyboardEvent*>(event.get()) )
{
handled |= src_canvas->handleKeyboardEvent(keyboard_event);
}
return handled;
}
//----------------------------------------------------------------------------
void Image::updateImpl(double dt)
{
Element::updateImpl(dt);
osg::Texture2D* texture = dynamic_cast<osg::Texture2D*>
(
_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<CullCallback*>
#else
dynamic_cast<CullCallback*>
#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<osg::Image> 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<float>& 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<float>& 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<MouseEvent*>(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<KeyboardEvent*>(event.get()) )
{
handled |= src_canvas->handleKeyboardEvent(keyboard_event);
}
return handled;
}
//----------------------------------------------------------------------------
void Image::childChanged(SGPropertyNode* child)
{

View File

@@ -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();

View File

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

View File

@@ -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<SGPropertyNode*, std::shared_ptr<GeoNodePair>>;

View File

@@ -690,40 +690,6 @@ namespace canvas
}
//----------------------------------------------------------------------------
void Path::update(double dt)
{
if( _attributes_dirty & (CMDS | COORDS) )
{
_path->setSegments
(
_node->getChildValues<VGubyte, int>("cmd"),
_node->getChildValues<VGfloat, float>("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<VGubyte, int>("cmd"),
_node->getChildValues<VGfloat, float>("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)
{

View File

@@ -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<float> _rect;
SGRectf _rect;
virtual void updateImpl(double dt);
void parseRectToVGPath();
virtual void childRemoved(SGPropertyNode * child);
virtual void childChanged(SGPropertyNode * child);
void parseRectToVGPath();
};
} // namespace canvas

View File

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