Merge branch 'next' of ssh://git.code.sf.net/p/flightgear/simgear into next

This commit is contained in:
gallaert
2018-02-22 22:33:47 +00:00
38 changed files with 1116 additions and 968 deletions
+13 -19
View File
@@ -22,8 +22,10 @@
#include "CanvasEventManager.hxx" #include "CanvasEventManager.hxx"
#include "CanvasEventVisitor.hxx" #include "CanvasEventVisitor.hxx"
#include "CanvasPlacement.hxx" #include "CanvasPlacement.hxx"
#include <simgear/canvas/events/KeyboardEvent.hxx> #include <simgear/canvas/events/KeyboardEvent.hxx>
#include <simgear/canvas/events/MouseEvent.hxx> #include <simgear/canvas/events/MouseEvent.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/scene/util/parse_color.hxx> #include <simgear/scene/util/parse_color.hxx>
#include <simgear/scene/util/RenderConstants.hxx> #include <simgear/scene/util/RenderConstants.hxx>
@@ -32,9 +34,6 @@
#include <osgText/Text> #include <osgText/Text>
#include <osgViewer/Viewer> #include <osgViewer/Viewer>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/foreach.hpp>
namespace simgear namespace simgear
{ {
namespace canvas namespace canvas
@@ -64,18 +63,9 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
Canvas::Canvas(SGPropertyNode* node): Canvas::Canvas(SGPropertyNode* node):
PropertyBasedElement(node), PropertyBasedElement(node),
_canvas_mgr(0),
_event_manager(new EventManager), _event_manager(new EventManager),
_size_x(-1),
_size_y(-1),
_view_width(-1),
_view_height(-1),
_status(node, "status"), _status(node, "status"),
_status_msg(node, "status-msg"), _status_msg(node, "status-msg")
_sampling_dirty(false),
_render_dirty(true),
_visible(true),
_render_always(false)
{ {
_status = 0; _status = 0;
setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y); setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y);
@@ -236,6 +226,10 @@ namespace canvas
if( _status & STATUS_DIRTY ) 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); _texture.setSize(_size_x, _size_y);
if( !_texture.serviceable() ) if( !_texture.serviceable() )
@@ -261,7 +255,7 @@ namespace canvas
parseColor(_node->getStringValue("background"), clear_color); parseColor(_node->getStringValue("background"), clear_color);
camera->setClearColor(clear_color); camera->setClearColor(clear_color);
camera->addChild(_root_group->getMatrixTransform()); camera->addChild(root_scene_group);
if( _texture.serviceable() ) if( _texture.serviceable() )
{ {
@@ -281,7 +275,7 @@ namespace canvas
if( _visible || _render_always ) 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 // TODO should we check if the image the child canvas is displayed
// within is really visible? // within is really visible?
@@ -293,7 +287,7 @@ namespace canvas
if( _render_dirty ) if( _render_dirty )
{ {
// Also mark all canvases this canvas is displayed within as 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(); CanvasPtr canvas = canvas_weak.lock();
if( canvas ) if( canvas )
@@ -522,8 +516,8 @@ namespace canvas
{ {
const std::string& name = node->getNameString(); const std::string& name = node->getNameString();
if( boost::starts_with(name, "status") if( strutils::starts_with(name, "status")
|| boost::starts_with(name, "data-") ) || strutils::starts_with(name, "data-") )
return; return;
_render_dirty = true; _render_dirty = true;
@@ -538,7 +532,7 @@ namespace canvas
if( !placements.empty() ) if( !placements.empty() )
{ {
bool placement_dirty = false; bool placement_dirty = false;
BOOST_FOREACH(PlacementPtr& placement, placements) for(auto& placement: placements)
{ {
// check if change can be directly handled by placement // check if change can be directly handled by placement
if( placement->getProps() == node->getParent() if( placement->getProps() == node->getParent()
+13 -11
View File
@@ -33,7 +33,7 @@
#include <osg/NodeCallback> #include <osg/NodeCallback>
#include <osg/observer_ptr> #include <osg/observer_ptr>
#include <boost/scoped_ptr.hpp> #include <memory>
#include <string> #include <string>
namespace simgear namespace simgear
@@ -211,21 +211,21 @@ namespace canvas
protected: protected:
CanvasMgr *_canvas_mgr; CanvasMgr *_canvas_mgr {nullptr};
boost::scoped_ptr<EventManager> _event_manager; std::unique_ptr<EventManager> _event_manager;
int _size_x, int _size_x {-1},
_size_y, _size_y {-1},
_view_width, _view_width {-1},
_view_height; _view_height {-1};
PropertyObject<int> _status; PropertyObject<int> _status;
PropertyObject<std::string> _status_msg; PropertyObject<std::string> _status_msg;
bool _sampling_dirty, bool _sampling_dirty {false},
_render_dirty, _render_dirty {true},
_visible; _visible {true};
ODGauge _texture; ODGauge _texture;
@@ -235,7 +235,9 @@ namespace canvas
ElementWeakPtr _focus_element; ElementWeakPtr _focus_element;
CullCallbackPtr _cull_callback; 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<SGPropertyNode*> _dirty_placements; std::vector<SGPropertyNode*> _dirty_placements;
std::vector<Placements> _placements; std::vector<Placements> _placements;
+3 -14
View File
@@ -22,13 +22,11 @@
#include "CanvasWindow.hxx" #include "CanvasWindow.hxx"
#include <simgear/canvas/Canvas.hxx> #include <simgear/canvas/Canvas.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/scene/util/OsgMath.hxx> #include <simgear/scene/util/OsgMath.hxx>
#include <osgGA/GUIEventHandler> #include <osgGA/GUIEventHandler>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/foreach.hpp>
namespace simgear namespace simgear
{ {
namespace canvas namespace canvas
@@ -43,9 +41,6 @@ namespace canvas
const Style& parent_style, const Style& parent_style,
Element* parent ): Element* parent ):
Image(canvas, node, parent_style, parent), Image(canvas, node, parent_style, parent),
_attributes_dirty(0),
_resizable(false),
_capture_events(true),
_resize_top(node, "resize-top"), _resize_top(node, "resize-top"),
_resize_right(node, "resize-right"), _resize_right(node, "resize-right"),
_resize_bottom(node, "resize-bottom"), _resize_bottom(node, "resize-bottom"),
@@ -92,7 +87,7 @@ namespace canvas
_capture_events = node->getBoolValue(); _capture_events = node->getBoolValue();
else if( name == "decoration-border" ) else if( name == "decoration-border" )
parseDecorationBorder(node->getStringValue()); parseDecorationBorder(node->getStringValue());
else if( boost::starts_with(name, "shadow-") else if( strutils::starts_with(name, "shadow-")
|| name == "content-size" ) || name == "content-size" )
_attributes_dirty |= DECORATION; _attributes_dirty |= DECORATION;
else else
@@ -103,16 +98,10 @@ namespace canvas
Image::valueChanged(node); Image::valueChanged(node);
} }
//----------------------------------------------------------------------------
osg::Group* Window::getGroup()
{
return getMatrixTransform();
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
const SGVec2<float> Window::getPosition() const 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) ); return SGVec2<float>( m(3, 0), m(3, 1) );
} }
+3 -4
View File
@@ -70,7 +70,6 @@ namespace canvas
virtual void update(double delta_time_sec); virtual void update(double delta_time_sec);
virtual void valueChanged(SGPropertyNode* node); virtual void valueChanged(SGPropertyNode* node);
osg::Group* getGroup();
const SGVec2<float> getPosition() const; const SGVec2<float> getPosition() const;
const SGRect<float> getScreenRegion() const; const SGRect<float> getScreenRegion() const;
@@ -104,7 +103,7 @@ namespace canvas
DECORATION = 1 DECORATION = 1
}; };
uint32_t _attributes_dirty; uint32_t _attributes_dirty {0};
CanvasPtr _canvas_decoration; CanvasPtr _canvas_decoration;
CanvasWeakPtr _canvas_content; CanvasWeakPtr _canvas_content;
@@ -113,8 +112,8 @@ namespace canvas
ImagePtr _image_content, ImagePtr _image_content,
_image_shadow; _image_shadow;
bool _resizable, bool _resizable {false},
_capture_events; _capture_events {true};
PropertyObject<int> _resize_top, PropertyObject<int> _resize_top,
_resize_right, _resize_right,
+174 -163
View File
@@ -31,10 +31,6 @@
#include <osg/StateAttribute> #include <osg/StateAttribute>
#include <osg/Version> #include <osg/Version>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/foreach.hpp>
#include <boost/make_shared.hpp>
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
@@ -214,22 +210,22 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Element::onDestroy() void Element::onDestroy()
{ {
if( !_transform.valid() ) if( !_scene_group.valid() )
return; return;
// The transform node keeps a reference on this element, so ensure it is // The transform node keeps a reference on this element, so ensure it is
// deleted. // 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 // Hide in case someone still holds a reference
setVisible(false); setVisible(false);
removeListener(); removeListener();
_parent = 0; _parent = nullptr;
_transform = 0; _scene_group = nullptr;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -247,29 +243,8 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Element::update(double dt) void Element::update(double dt)
{ {
if( !isVisible() ) if( isVisible() )
return; updateImpl(dt);
// 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;
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -341,7 +316,8 @@ namespace canvas
if( listeners == _listener.end() ) if( listeners == _listener.end() )
return false; return false;
BOOST_FOREACH(EventListener const& listener, listeners->second) for(auto const& listener: listeners->second)
{
try try
{ {
listener(event); listener(event);
@@ -354,6 +330,7 @@ namespace canvas
"canvas::Element: event handler error: '" << ex.what() << "'" "canvas::Element: event handler error: '" << ex.what() << "'"
); );
} }
}
return true; return true;
} }
@@ -395,9 +372,9 @@ namespace canvas
getBoundingBox() getBoundingBox()
#endif #endif
.contains(osg::Vec3f(local_pos, 0)); .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 // ... 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 else
return false; return false;
} }
@@ -406,35 +383,32 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Element::setVisible(bool visible) void Element::setVisible(bool visible)
{ {
if( _transform.valid() ) if( _scene_group.valid() )
// TODO check if we need another nodemask // TODO check if we need another nodemask
_transform->setNodeMask(visible ? 0xffffffff : 0); _scene_group->setNodeMask(visible ? 0xffffffff : 0);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool Element::isVisible() const 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(); return _scene_group.get();
}
//----------------------------------------------------------------------------
osg::MatrixTransform const* Element::getMatrixTransform() const
{
return _transform.get();
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
osg::Vec2f Element::posToLocal(const osg::Vec2f& pos) const osg::Vec2f Element::posToLocal(const osg::Vec2f& pos) const
{ {
getMatrix(); if( !_scene_group )
if (! _transform) return osg::Vec2f(pos[0], pos[1]); // TODO log warning?
const osg::Matrix& m = _transform->getInverseMatrix(); return pos;
updateMatrix();
const osg::Matrix& m = _scene_group->getInverseMatrix();
return osg::Vec2f return osg::Vec2f
( (
m(0, 0) * pos[0] + m(1, 0) * pos[1] + m(3, 0), 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( child->getNameString() == NAME_TRANSFORM )
{ {
if( !_transform.valid() )
return;
if( child->getIndex() >= static_cast<int>(_transform_types.size()) ) if( child->getIndex() >= static_cast<int>(_transform_types.size()) )
{ {
SG_LOG SG_LOG
@@ -526,7 +497,7 @@ namespace canvas
if( parent == _node ) if( parent == _node )
{ {
const std::string& name = child->getNameString(); const std::string& name = child->getNameString();
if( boost::starts_with(name, "data-") ) if( strutils::starts_with(name, "data-") )
return; return;
else if( StyleInfo const* style_info = getStyleInfo(name) ) else if( StyleInfo const* style_info = getStyleInfo(name) )
{ {
@@ -541,7 +512,7 @@ namespace canvas
} }
else if( name == "update" ) else if( name == "update" )
return update(0); return update(0);
else if( boost::starts_with(name, "blend-") ) else if( strutils::starts_with(name, "blend-") )
return (void)(_attributes_dirty |= BLEND_FUNC); return (void)(_attributes_dirty |= BLEND_FUNC);
} }
else if( parent else if( parent
@@ -565,6 +536,10 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Element::setClip(const std::string& clip) void Element::setClip(const std::string& clip)
{ {
if( !_scene_group )
// TODO warn?
return;
osg::StateSet* ss = getOrCreateStateSet(); osg::StateSet* ss = getOrCreateStateSet();
if( !ss ) if( !ss )
return; return;
@@ -578,8 +553,8 @@ namespace canvas
// TODO generalize CSS property parsing // TODO generalize CSS property parsing
const std::string RECT("rect("); const std::string RECT("rect(");
if( !boost::ends_with(clip, ")") if( !strutils::ends_with(clip, ")")
|| !boost::starts_with(clip, RECT) ) || !strutils::starts_with(clip, RECT) )
{ {
SG_LOG(SG_GENERAL, SG_WARN, "Canvas: invalid clip: " << clip); SG_LOG(SG_GENERAL, SG_WARN, "Canvas: invalid clip: " << clip);
return; return;
@@ -619,7 +594,7 @@ namespace canvas
} }
if( !_scissor ) if( !_scissor )
_scissor = new RelativeScissor(_transform.get()); _scissor = new RelativeScissor(_scene_group.get());
// <top>, <right>, <bottom>, <left> // <top>, <right>, <bottom>, <left>
_scissor->x() = values[3]; _scissor->x() = values[3];
@@ -643,26 +618,26 @@ namespace canvas
_scissor->_coord_reference = rf; _scissor->_coord_reference = rf;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Element::setRotation(unsigned int index, double r) void Element::setRotation(unsigned int index, double r)
{ {
_node->getChild(NAME_TRANSFORM, index, true)->setDoubleValue("rot", r); _node->getChild(NAME_TRANSFORM, index, true)->setDoubleValue("rot", r);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Element::setTranslation(unsigned int index, double x, double y) void Element::setTranslation(unsigned int index, double x, double y)
{ {
SGPropertyNode* tf = _node->getChild(NAME_TRANSFORM, index, true); SGPropertyNode* tf = _node->getChild(NAME_TRANSFORM, index, true);
tf->getChild("t", 0, true)->setDoubleValue(x); tf->getChild("t", 0, true)->setDoubleValue(x);
tf->getChild("t", 1, true)->setDoubleValue(y); tf->getChild("t", 1, true)->setDoubleValue(y);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Element::setTransformEnabled(unsigned int index, bool enabled) void Element::setTransformEnabled(unsigned int index, bool enabled)
{ {
SGPropertyNode* tf = _node->getChild(NAME_TRANSFORM, index, true); SGPropertyNode* tf = _node->getChild(NAME_TRANSFORM, index, true);
tf->setBoolValue("enabled", enabled); tf->setBoolValue("enabled", enabled);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
osg::BoundingBox Element::getBoundingBox() const osg::BoundingBox Element::getBoundingBox() const
@@ -676,8 +651,8 @@ namespace canvas
osg::BoundingBox bb; osg::BoundingBox bb;
if( _transform.valid() ) if( _scene_group.valid() )
bb.expandBy(_transform->getBound()); bb.expandBy( _scene_group->getBound() );
return bb; return bb;
} }
@@ -711,73 +686,11 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
osg::Matrix Element::getMatrix() const osg::Matrix Element::getMatrix() const
{ {
if( !_transform ) if( !_scene_group )
return osg::Matrix::identity(); return osg::Matrix::identity();
if( !(_attributes_dirty & TRANSFORM) ) updateMatrix();
return _transform->getMatrix(); return _scene_group->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;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -791,11 +704,8 @@ namespace canvas
PropertyBasedElement(node), PropertyBasedElement(node),
_canvas( canvas ), _canvas( canvas ),
_parent( parent ), _parent( parent ),
_attributes_dirty( 0 ), _scene_group( new osg::MatrixTransform ),
_transform( new osg::MatrixTransform ), _style( parent_style )
_style( parent_style ),
_scissor( 0 ),
_drawable( 0 )
{ {
staticInit(); staticInit();
@@ -807,15 +717,15 @@ namespace canvas
); );
// Ensure elements are drawn in order they appear in the element tree // Ensure elements are drawn in order they appear in the element tree
_transform->getOrCreateStateSet() _scene_group
->setRenderBinDetails ->getOrCreateStateSet()
( ->setRenderBinDetails(
0, 0,
"PreOrderBin", "PreOrderBin",
osg::StateSet::OVERRIDE_RENDERBIN_DETAILS 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 ) void Element::setDrawable( osg::Drawable* drawable )
{ {
_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); geode->addDrawable(_drawable);
_transform->addChild(geode); _scene_group->addChild(geode);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -915,18 +835,109 @@ namespace canvas
{ {
if( _drawable.valid() ) if( _drawable.valid() )
return _drawable->getOrCreateStateSet(); return _drawable->getOrCreateStateSet();
if( _transform.valid() ) else if( _scene_group.valid() )
return _transform->getOrCreateStateSet(); return _scene_group->getOrCreateStateSet();
else
return 0; return nullptr;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Element::setupStyle() void Element::setupStyle()
{ {
BOOST_FOREACH( Style::value_type style, _style ) for(auto const& style: _style)
setStyle(style.second); 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 canvas
} // namespace simgear } // namespace simgear
+22 -13
View File
@@ -24,13 +24,13 @@
#include <simgear/canvas/CanvasEvent.hxx> #include <simgear/canvas/CanvasEvent.hxx>
#include <simgear/props/PropertyBasedElement.hxx> #include <simgear/props/PropertyBasedElement.hxx>
#include <simgear/misc/stdint.hxx> // for uint32_t #include <simgear/misc/stdint.hxx> // for uint32_t
#include <simgear/std/type_traits.hxx>
#include <osg/BoundingBox> #include <osg/BoundingBox>
#include <osg/MatrixTransform> #include <osg/MatrixTransform>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/type_traits/is_base_of.hpp>
namespace osg namespace osg
{ {
@@ -49,6 +49,7 @@ namespace canvas
public PropertyBasedElement public PropertyBasedElement
{ {
public: public:
using SceneGroupWeakPtr = osg::observer_ptr<osg::MatrixTransform>;
/** /**
* Store pointer to window as user data * Store pointer to window as user data
@@ -142,8 +143,11 @@ namespace canvas
*/ */
virtual bool isVisible() const; 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. * Transform position to local coordinages.
@@ -217,13 +221,14 @@ namespace canvas
*/ */
template<typename Derived> template<typename Derived>
static static
typename boost::enable_if< std::enable_if_t<
boost::is_base_of<Element, Derived>, std::is_base_of<Element, Derived>::value,
ElementPtr ElementPtr
>::type create( const CanvasWeakPtr& canvas, >
const SGPropertyNode_ptr& node, create( const CanvasWeakPtr& canvas,
const Style& style = Style(), const SGPropertyNode_ptr& node,
Element* parent = NULL ) const Style& style = Style(),
Element* parent = NULL )
{ {
return ElementPtr( new Derived(canvas, node, style, parent) ); return ElementPtr( new Derived(canvas, node, style, parent) );
} }
@@ -251,13 +256,13 @@ namespace canvas
CanvasWeakPtr _canvas; CanvasWeakPtr _canvas;
ElementWeakPtr _parent; ElementWeakPtr _parent;
mutable uint32_t _attributes_dirty; mutable uint32_t _attributes_dirty = 0;
osg::observer_ptr<osg::MatrixTransform> _transform; SceneGroupWeakPtr _scene_group;
std::vector<TransformType> _transform_types; std::vector<TransformType> _transform_types;
Style _style; Style _style;
RelativeScissor *_scissor; RelativeScissor *_scissor = nullptr;
typedef std::vector<EventListener> Listener; typedef std::vector<EventListener> Listener;
typedef std::map<int, Listener> ListenerMap; typedef std::map<int, Listener> ListenerMap;
@@ -584,6 +589,10 @@ namespace canvas
void setupStyle(); void setupStyle();
void updateMatrix() const;
virtual void updateImpl(double dt);
private: private:
osg::ref_ptr<osg::Drawable> _drawable; osg::ref_ptr<osg::Drawable> _drawable;
+71 -74
View File
@@ -23,13 +23,10 @@
#include "CanvasMap.hxx" #include "CanvasMap.hxx"
#include "CanvasPath.hxx" #include "CanvasPath.hxx"
#include "CanvasText.hxx" #include "CanvasText.hxx"
#include <simgear/canvas/CanvasEventVisitor.hxx> #include <simgear/canvas/CanvasEventVisitor.hxx>
#include <simgear/canvas/events/MouseEvent.hxx> #include <simgear/canvas/events/MouseEvent.hxx>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/lambda/core.hpp>
namespace simgear namespace simgear
{ {
namespace canvas namespace canvas
@@ -48,7 +45,7 @@ namespace canvas
ElementFactories Group::_child_factories; ElementFactories Group::_child_factories;
const std::string Group::TYPE_NAME = "group"; const std::string Group::TYPE_NAME = "group";
void warnTransformExpired(const char* member_name) void warnSceneGroupExpired(const char* member_name)
{ {
SG_LOG( SG_GENERAL, SG_LOG( SG_GENERAL,
SG_WARN, SG_WARN,
@@ -135,63 +132,57 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
ElementPtr Group::getElementById(const std::string& id) ElementPtr Group::getElementById(const std::string& id)
{ {
if( !_transform.valid() ) if( !_scene_group.valid() )
{ {
warnTransformExpired("getElementById"); warnSceneGroupExpired("getElementById");
return ElementPtr(); return {};
} }
std::vector<GroupPtr> groups; // TODO check search algorithm. Not completely breadth-first and might be
for(size_t i = 0; i < _transform->getNumChildren(); ++i) // 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); const ElementPtr& el = getChildByIndex(i);
if( el->get<std::string>("id") == id ) if( el->get<std::string>("id") == id )
return el; return el;
Group* group = dynamic_cast<Group*>(el.get()); if( Group* child_group = dynamic_cast<Group*>(el.get()) )
if( group ) child_groups.push_back(child_group);
groups.push_back(group);
} }
BOOST_FOREACH( GroupPtr group, groups ) for(auto group: child_groups)
{ {
ElementPtr el = group->getElementById(id); if( ElementPtr el = group->getElementById(id) )
if( el )
return el; return el;
} }
return ElementPtr(); return {};
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Group::clearEventListener() void Group::clearEventListener()
{ {
if( !_transform.valid() )
return warnTransformExpired("clearEventListener");
for(size_t i = 0; i < _transform->getNumChildren(); ++i)
getChildByIndex(i)->clearEventListener();
Element::clearEventListener(); Element::clearEventListener();
}
//---------------------------------------------------------------------------- if( !_scene_group.valid() )
void Group::update(double dt) return warnSceneGroupExpired("clearEventListener");
{
for(size_t i = 0; i < _transform->getNumChildren(); ++i)
getChildByIndex(i)->update(dt);
Element::update(dt); for(size_t i = 0; i < _scene_group->getNumChildren(); ++i)
getChildByIndex(i)->clearEventListener();
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool Group::traverse(EventVisitor& visitor) bool Group::traverse(EventVisitor& visitor)
{ {
// Iterate in reverse order as last child is displayed on top if( _scene_group.valid() )
for(size_t i = _transform->getNumChildren(); i --> 0;)
{ {
if( getChildByIndex(i)->accept(visitor) ) // Iterate in reverse order as last child is displayed on top
return true; for(size_t i = _scene_group->getNumChildren(); i --> 0;)
{
if( getChildByIndex(i)->accept(visitor) )
return true;
}
} }
return false; return false;
} }
@@ -206,13 +197,13 @@ namespace canvas
bool handled = setStyleImpl(style, style_info); bool handled = setStyleImpl(style, style_info);
if( style_info->inheritable ) if( style_info->inheritable )
{ {
if( !_transform.valid() ) if( !_scene_group.valid() )
{ {
warnTransformExpired("setStyle"); warnSceneGroupExpired("setStyle");
return false; 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); handled |= getChildByIndex(i)->setStyle(style, style_info);
} }
@@ -222,26 +213,20 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
osg::BoundingBox Group::getTransformedBounds(const osg::Matrix& m) const osg::BoundingBox Group::getTransformedBounds(const osg::Matrix& m) const
{ {
osg::BoundingBox bb; if( !_scene_group.valid() )
if( !_transform.valid() )
{ {
warnTransformExpired("getTransformedBounds"); warnSceneGroupExpired("getTransformedBounds");
return bb; 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); auto child = getChildByIndex(i);
if( !child->getMatrixTransform()->getNodeMask() ) if( !child || !child->isVisible() )
continue; continue;
bb.expandBy bb.expandBy( child->getTransformedBounds(child->getMatrix() * m) );
(
child->getTransformedBounds
(
child->getMatrixTransform()->getMatrix() * m
)
);
} }
return bb; return bb;
@@ -257,6 +242,15 @@ namespace canvas
return ElementFactory(); 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) void Group::childAdded(SGPropertyNode* child)
{ {
@@ -266,13 +260,13 @@ namespace canvas
ElementFactory child_factory = getChildFactory( child->getNameString() ); ElementFactory child_factory = getChildFactory( child->getNameString() );
if( child_factory ) if( child_factory )
{ {
if( !_transform.valid() ) if( !_scene_group.valid() )
return warnTransformExpired("childAdded"); return warnSceneGroupExpired("childAdded");
ElementPtr element = child_factory(_canvas, child, _style, this); ElementPtr element = child_factory(_canvas, child, _style, this);
// Add to osg scene graph... // Add to osg scene graph...
_transform->addChild( element->getMatrixTransform() ); _scene_group->addChild(element->getSceneGroup());
// ...and ensure correct ordering // ...and ensure correct ordering
handleZIndexChanged(element); handleZIndexChanged(element);
@@ -293,7 +287,7 @@ namespace canvas
if( getChildFactory(node->getNameString()) ) if( getChildFactory(node->getNameString()) )
{ {
if( !_transform.valid() ) if( !_scene_group.valid() )
// If transform is destroyed also all children are destroyed, so we can // If transform is destroyed also all children are destroyed, so we can
// not do anything here. // not do anything here.
return; return;
@@ -323,7 +317,7 @@ namespace canvas
void Group::childChanged(SGPropertyNode* node) void Group::childChanged(SGPropertyNode* node)
{ {
SGPropertyNode* parent = node->getParent(); SGPropertyNode* parent = node->getParent();
SGPropertyNode* grand_parent = parent ? parent->getParent() : NULL; SGPropertyNode* grand_parent = parent ? parent->getParent() : nullptr;
if( grand_parent == _node if( grand_parent == _node
&& node->getNameString() == "z-index" ) && node->getNameString() == "z-index" )
@@ -333,16 +327,18 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Group::handleZIndexChanged(ElementPtr child, int z_index) void Group::handleZIndexChanged(ElementPtr child, int z_index)
{ {
if( !child || !_transform.valid() ) if( !child || !_scene_group.valid() )
return; return;
osg::ref_ptr<osg::MatrixTransform> tf = child->getMatrixTransform(); // Keep reference to prevent deleting while removing and re-inserting later
size_t index = _transform->getChildIndex(tf), osg::ref_ptr<osg::MatrixTransform> tf = child->getSceneGroup();
size_t index = _scene_group->getChildIndex(tf),
index_new = index; index_new = index;
for(;; ++index_new) for(;; ++index_new)
{ {
if( index_new + 1 == _transform->getNumChildren() ) if( index_new + 1 == _scene_group->getNumChildren() )
break; break;
// Move to end of block with same index (= move upwards until the next // Move to end of block with same index (= move upwards until the next
@@ -369,8 +365,8 @@ namespace canvas
return; return;
} }
_transform->removeChild(index); _scene_group->removeChild(index);
_transform->insertChild(index_new, tf); _scene_group->insertChild(index_new, tf);
SG_LOG SG_LOG
( (
@@ -383,26 +379,27 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
ElementPtr Group::getChildByIndex(size_t index) const ElementPtr Group::getChildByIndex(size_t index) const
{ {
assert(_transform.valid()); assert( _scene_group.valid() );
OSGUserData* ud =
static_cast<OSGUserData*>(_transform->getChild(index)->getUserData()); auto child = _scene_group->getChild(index);
assert(ud); if( !child )
if (ud) return {};
return ud->element;
return nullptr; auto ud = static_cast<OSGUserData*>(child->getUserData());
return ud ? ud->element : ElementPtr();
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
ElementPtr Group::findChild( const SGPropertyNode* node, ElementPtr Group::findChild( const SGPropertyNode* node,
const std::string& id ) const const std::string& id ) const
{ {
if( !_transform.valid() ) if( !_scene_group.valid() )
{ {
warnTransformExpired("findChild"); warnSceneGroupExpired("findChild");
return ElementPtr(); return {};
} }
for(size_t i = 0; i < _transform->getNumChildren(); ++i) for(size_t i = 0; i < _scene_group->getNumChildren(); ++i)
{ {
ElementPtr el = getChildByIndex(i); ElementPtr el = getChildByIndex(i);
@@ -418,7 +415,7 @@ namespace canvas
} }
} }
return ElementPtr(); return {};
} }
} // namespace canvas } // namespace canvas
+2 -2
View File
@@ -88,8 +88,6 @@ namespace canvas
virtual void clearEventListener(); virtual void clearEventListener();
virtual void update(double dt);
virtual bool traverse(EventVisitor& visitor); virtual bool traverse(EventVisitor& visitor);
virtual bool setStyle( const SGPropertyNode* child, virtual bool setStyle( const SGPropertyNode* child,
@@ -107,6 +105,8 @@ namespace canvas
*/ */
virtual ElementFactory getChildFactory(const std::string& type) const; virtual ElementFactory getChildFactory(const std::string& type) const;
virtual void updateImpl(double dt);
virtual void childAdded(SGPropertyNode * child); virtual void childAdded(SGPropertyNode * child);
virtual void childRemoved(SGPropertyNode * child); virtual void childRemoved(SGPropertyNode * child);
virtual void childChanged(SGPropertyNode * child); virtual void childChanged(SGPropertyNode * child);
+195 -192
View File
@@ -117,9 +117,7 @@ namespace canvas
ElementWeakPtr parent ): ElementWeakPtr parent ):
Element(canvas, node, parent_style, parent), Element(canvas, node, parent_style, parent),
_texture(new osg::Texture2D), _texture(new osg::Texture2D),
_node_src_rect( node->getNode("source", 0, true) ), _node_src_rect( node->getNode("source", 0, true) )
_src_rect(0,0),
_region(0,0)
{ {
staticInit(); staticInit();
@@ -157,22 +155,207 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
Image::~Image() Image::~Image()
{ {
if( _http_request ) { if( _http_request )
Canvas::getSystemAdapter()->getHTTPClient()->cancelRequest(_http_request, "image destroyed"); {
} 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*> osg::Texture2D* texture = dynamic_cast<osg::Texture2D*>
( (
_geom->getOrCreateStateSet() _geom->getOrCreateStateSet()
->getTextureAttribute(0, osg::StateAttribute::TEXTURE) ->getTextureAttribute(0, osg::StateAttribute::TEXTURE)
); );
simgear::canvas::CanvasPtr canvas = _src_canvas.lock(); auto canvas = _src_canvas.lock();
if( (_attributes_dirty & SRC_CANVAS) if( (_attributes_dirty & SRC_CANVAS)
// check if texture has changed (eg. due to resizing) // 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<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) void Image::childChanged(SGPropertyNode* child)
{ {
@@ -634,7 +635,9 @@ namespace canvas
// Abort pending request // Abort pending request
if( _http_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(); _http_request.reset();
} }
+6 -5
View File
@@ -53,7 +53,6 @@ namespace canvas
ElementWeakPtr parent = 0 ); ElementWeakPtr parent = 0 );
virtual ~Image(); virtual ~Image();
virtual void update(double dt);
virtual void valueChanged(SGPropertyNode* child); virtual void valueChanged(SGPropertyNode* child);
void setSrcCanvas(CanvasPtr canvas); void setSrcCanvas(CanvasPtr canvas);
@@ -100,8 +99,8 @@ namespace canvas
* *
*/ */
void setSourceRect(const SGRect<float>& sourceRect); void setSourceRect(const SGRect<float>& sourceRect);
protected:
protected:
enum ImageAttributes enum ImageAttributes
{ {
SRC_RECT = LAST_ATTRIBUTE << 1, // Source image rectangle SRC_RECT = LAST_ATTRIBUTE << 1, // Source image rectangle
@@ -109,6 +108,8 @@ namespace canvas
SRC_CANVAS = DEST_SIZE << 1 SRC_CANVAS = DEST_SIZE << 1
}; };
virtual void updateImpl(double dt);
virtual void childChanged(SGPropertyNode * child); virtual void childChanged(SGPropertyNode * child);
void setupDefaultDimensions(); void setupDefaultDimensions();
@@ -134,9 +135,9 @@ namespace canvas
osg::ref_ptr<osg::Vec2Array> _texCoords; osg::ref_ptr<osg::Vec2Array> _texCoords;
osg::ref_ptr<osg::Vec4Array> _colors; osg::ref_ptr<osg::Vec4Array> _colors;
SGPropertyNode *_node_src_rect; SGPropertyNode *_node_src_rect = nullptr;
SGRect<float> _src_rect, SGRect<float> _src_rect {0, 0},
_region; _region {0, 0};
SVGpreserveAspectRatio _preserve_aspect_ratio; SVGpreserveAspectRatio _preserve_aspect_ratio;
+33 -32
View File
@@ -18,13 +18,14 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#include <simgear_config.h> #include <simgear_config.h>
#include "CanvasMap.hxx" #include "CanvasMap.hxx"
#include "map/geo_node_pair.hxx" #include "map/geo_node_pair.hxx"
#include "map/projection.hxx" #include "map/projection.hxx"
#include <cmath> #include <simgear/misc/strutils.hxx>
#include <boost/algorithm/string/predicate.hpp> #include <cmath>
#define LOG_GEO_RET(msg) \ #define LOG_GEO_RET(msg) \
{\ {\
@@ -73,13 +74,8 @@ namespace canvas
Group(canvas, node, parent_style, parent) Group(canvas, node, parent_style, parent)
{ {
staticInit(); staticInit();
if (node->getChild(PROJECTION) &&
(node->getChild(PROJECTION)->getStringValue() == WEB_MERCATOR)) { projectionNodeChanged(node->getChild(PROJECTION));
_projection = (boost::shared_ptr<HorizontalProjection>) new WebMercatorProjection();
} else {
_projection = (boost::shared_ptr<HorizontalProjection>) new SansonFlamsteedProjection();
}
_projection_dirty = true;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -89,13 +85,13 @@ namespace canvas
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Map::update(double dt) void Map::updateImpl(double dt)
{ {
for( GeoNodes::iterator it = _geo_nodes.begin(); Group::updateImpl(dt);
it != _geo_nodes.end();
++it ) for(auto& it: _geo_nodes)
{ {
GeoNodePair* geo_node = it->second.get(); GeoNodePair* geo_node = it.second.get();
if( !geo_node->isComplete() if( !geo_node->isComplete()
|| (!geo_node->isDirty() && !_projection_dirty) ) || (!geo_node->isDirty() && !_projection_dirty) )
continue; continue;
@@ -117,14 +113,12 @@ namespace canvas
geo_node->setDirty(false); geo_node->setDirty(false);
} }
_projection_dirty = false; _projection_dirty = false;
Group::update(dt);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Map::childAdded(SGPropertyNode* parent, SGPropertyNode* child) 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()); _geo_nodes[child].reset(new GeoNodePair());
else if( parent != _node && child->getNameString() == HDG ) else if( parent != _node && child->getNameString() == HDG )
_hdg_nodes.insert(child); _hdg_nodes.insert(child);
@@ -135,7 +129,7 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Map::childRemoved(SGPropertyNode* parent, SGPropertyNode* child) 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 // TODO remove from other node
_geo_nodes.erase(child); _geo_nodes.erase(child);
else if( parent != _node && child->getName() == HDG ) else if( parent != _node && child->getName() == HDG )
@@ -157,7 +151,7 @@ namespace canvas
{ {
const std::string& name = child->getNameString(); const std::string& name = child->getNameString();
if( boost::ends_with(name, GEO) ) if( strutils::ends_with(name, GEO) )
return geoNodeChanged(child); return geoNodeChanged(child);
else if( name == HDG ) else if( name == HDG )
return hdgNodeChanged(child); return hdgNodeChanged(child);
@@ -188,24 +182,31 @@ namespace canvas
_projection->setRange(child->getDoubleValue()); _projection->setRange(child->getDoubleValue());
else if( child->getNameString() == SCREEN_RANGE ) else if( child->getNameString() == SCREEN_RANGE )
_projection->setScreenRange(child->getDoubleValue()); _projection->setScreenRange(child->getDoubleValue());
else if( child->getNameString() == PROJECTION ) { else if( child->getNameString() == PROJECTION )
if (child->getStringValue() == WEB_MERCATOR) { projectionNodeChanged(child);
_projection = (boost::shared_ptr<HorizontalProjection>) new WebMercatorProjection(); else
} else {
_projection = (boost::shared_ptr<HorizontalProjection>) 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
return Group::childChanged(child); return Group::childChanged(child);
_projection_dirty = true; _projection_dirty = true;
} }
//----------------------------------------------------------------------------
void Map::projectionNodeChanged(SGPropertyNode* child)
{
if(child && child->getStringValue() == WEB_MERCATOR)
_projection = std::make_shared<WebMercatorProjection>();
else
_projection = std::make_shared<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;
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Map::geoNodeChanged(SGPropertyNode* child) void Map::geoNodeChanged(SGPropertyNode* child)
{ {
+22 -26
View File
@@ -22,9 +22,9 @@
#include "CanvasGroup.hxx" #include "CanvasGroup.hxx"
#include <boost/shared_ptr.hpp> #include <memory>
#include <boost/unordered_map.hpp> #include <unordered_map>
#include <boost/unordered_set.hpp> #include <unordered_set>
namespace simgear namespace simgear
{ {
@@ -45,45 +45,41 @@ namespace canvas
ElementWeakPtr parent = 0 ); ElementWeakPtr parent = 0 );
virtual ~Map(); 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: protected:
virtual void updateImpl(double dt);
virtual void childChanged(SGPropertyNode * child); void updateProjection(SGPropertyNode* type_node);
typedef boost::unordered_map< SGPropertyNode*, virtual void childAdded( SGPropertyNode* parent,
boost::shared_ptr<GeoNodePair> SGPropertyNode* child );
> GeoNodes; virtual void childRemoved( SGPropertyNode* parent,
typedef boost::unordered_set<SGPropertyNode*> NodeSet; SGPropertyNode* child );
virtual void valueChanged(SGPropertyNode* child);
virtual void childChanged(SGPropertyNode* child);
using GeoNodes =
std::unordered_map<SGPropertyNode*, std::shared_ptr<GeoNodePair>>;
using NodeSet = std::unordered_set<SGPropertyNode*>;
GeoNodes _geo_nodes; GeoNodes _geo_nodes;
NodeSet _hdg_nodes; NodeSet _hdg_nodes;
boost::shared_ptr<HorizontalProjection> _projection; std::shared_ptr<HorizontalProjection> _projection;
bool _projection_dirty; bool _projection_dirty = false;
struct GeoCoord struct GeoCoord
{ {
GeoCoord():
type(INVALID),
value(0)
{}
enum enum
{ {
INVALID, INVALID,
LATITUDE, LATITUDE,
LONGITUDE LONGITUDE
} type; } type = INVALID;
double value; double value = 0;
}; };
void geoNodeChanged(SGPropertyNode * child); void projectionNodeChanged(SGPropertyNode* child);
void hdgNodeChanged(SGPropertyNode * child); void geoNodeChanged(SGPropertyNode* child);
void hdgNodeChanged(SGPropertyNode* child);
GeoCoord parseGeoCoord(const std::string& val) const; GeoCoord parseGeoCoord(const std::string& val) const;
}; };
+179 -160
View File
@@ -206,23 +206,13 @@ namespace canvas
return SGVec2f(-1.0f, -1.0f); return SGVec2f(-1.0f, -1.0f);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class Path::PathDrawable: class Path::PathDrawable:
public osg::Drawable public osg::Drawable
{ {
public: public:
PathDrawable(Path* path): PathDrawable(Path* path):
_path_element(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)
{ {
setSupportsDisplayList(false); setSupportsDisplayList(false);
setDataVariance(Object::DYNAMIC); 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<uint8_t>(SGMiscf::clip(opacity, 0.f, 1.f) * 255);
_attributes_dirty |= FILL_COLOR;
}
/** /**
* Set path fill rule ("pseudo-nonzero" or "evenodd") * Set path fill rule ("pseudo-nonzero" or "evenodd")
* *
@@ -310,7 +310,7 @@ namespace canvas
else if( parseColor(stroke, _stroke_color) ) else if( parseColor(stroke, _stroke_color) )
{ {
_mode |= VG_STROKE_PATH; _mode |= VG_STROKE_PATH;
_attributes_dirty |= STROKE_COLOR; _attributes_dirty |= STROKE_COLOR;
} }
else 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<uint8_t>(SGMiscf::clip(opacity, 0.f, 1.f) * 255);
_attributes_dirty |= STROKE_COLOR;
}
/** /**
* Set stroke width * Set stroke width
*/ */
@@ -390,31 +400,22 @@ namespace canvas
osg::StateAttribute const* blend_func = osg::StateAttribute const* blend_func =
state->getLastAppliedAttribute(osg::StateAttribute::BLENDFUNC); 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 // Setup paint
if( _mode & VG_STROKE_PATH ) 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); vgSetPaint(_paint, VG_STROKE_PATH);
vgSetf(VG_STROKE_LINE_WIDTH, _stroke_width); vgSetf(VG_STROKE_LINE_WIDTH, _stroke_width);
@@ -426,6 +427,19 @@ namespace canvas
} }
if( _mode & VG_FILL_PATH ) 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); vgSetPaint(_paint_fill, VG_FILL_PATH);
vgSeti(VG_FILL_RULE, _fill_rule); vgSeti(VG_FILL_RULE, _fill_rule);
@@ -579,22 +593,24 @@ namespace canvas
Path *_path_element; Path *_path_element;
mutable VGPath _path; mutable VGPath _path {VG_INVALID_HANDLE};
mutable VGPaint _paint; mutable VGPaint _paint {VG_INVALID_HANDLE};
mutable VGPaint _paint_fill; mutable VGPaint _paint_fill {VG_INVALID_HANDLE};
mutable uint32_t _attributes_dirty; mutable uint32_t _attributes_dirty {~0u};
CmdList _cmds; CmdList _cmds;
CoordList _coords; CoordList _coords;
VGbitfield _mode; VGbitfield _mode {0};
osg::Vec4f _fill_color; osg::Vec4f _fill_color;
VGFillRule _fill_rule; uint8_t _fill_opacity {255};
VGFillRule _fill_rule {VG_EVEN_ODD};
osg::Vec4f _stroke_color; osg::Vec4f _stroke_color;
VGfloat _stroke_width; uint8_t _stroke_opacity {255};
VGfloat _stroke_width {1};
std::vector<VGfloat> _stroke_dash; std::vector<VGfloat> _stroke_dash;
VGCapStyle _stroke_linecap; VGCapStyle _stroke_linecap {VG_CAP_BUTT};
VGJoinStyle _stroke_linejoin; VGJoinStyle _stroke_linejoin {VG_JOIN_MITER};
osg::Vec3f transformPoint( const osg::Matrix& m, osg::Vec3f transformPoint( const osg::Matrix& m,
osg::Vec2f pos ) const osg::Vec2f pos ) const
@@ -670,8 +686,10 @@ namespace canvas
PathDrawableRef Path::*path = &Path::_path; PathDrawableRef Path::*path = &Path::_path;
addStyle("fill", "color", &PathDrawable::setFill, path); addStyle("fill", "color", &PathDrawable::setFill, path);
addStyle("fill-opacity", "numeric", &PathDrawable::setFillOpacity, path);
addStyle("fill-rule", "", &PathDrawable::setFillRule, path); addStyle("fill-rule", "", &PathDrawable::setFillRule, path);
addStyle("stroke", "color", &PathDrawable::setStroke, path); addStyle("stroke", "color", &PathDrawable::setStroke, path);
addStyle("stroke-opacity", "numeric", &PathDrawable::setStrokeOpacity, path);
addStyle("stroke-width", "numeric", &PathDrawable::setStrokeWidth, path); addStyle("stroke-width", "numeric", &PathDrawable::setStrokeWidth, path);
addStyle("stroke-dasharray", "", &PathDrawable::setStrokeDashArray, path); addStyle("stroke-dasharray", "", &PathDrawable::setStrokeDashArray, path);
addStyle("stroke-linecap", "", &PathDrawable::setStrokeLinecap, 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<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 osg::BoundingBox Path::getTransformedBounds(const osg::Matrix& m) const
{ {
@@ -839,36 +823,70 @@ namespace canvas
_node->getChild("border-radius", 1, true)->setDoubleValue(radiusY); _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) void Path::childChanged(SGPropertyNode* child)
{ {
const std::string& name = child->getNameString(); const std::string& name = child->getNameString();
const std::string &prName = child->getParent()->getNameString(); const std::string &prName = child->getParent()->getNameString();
if (simgear::strutils::starts_with(name, "border-")) if( strutils::starts_with(name, "border-") )
{ {
_attributes_dirty |= RECT; _attributes_dirty |= RECT;
return; return;
} }
if (prName == "rect") { if (prName == "rect")
_hasRect = true; {
if (name == "left") { _hasRect = true;
_rect.setLeft(child->getDoubleValue()); if (name == "left") {
} else if (name == "top") { _rect.setLeft(child->getDoubleValue());
_rect.setTop(child->getDoubleValue()); } else if (name == "top") {
} else if (name == "right") { _rect.setTop(child->getDoubleValue());
_rect.setRight(child->getDoubleValue()); } else if (name == "right") {
} else if (name == "bottom") { _rect.setRight(child->getDoubleValue());
_rect.setBottom(child->getDoubleValue()); } else if (name == "bottom") {
} else if (name == "width") { _rect.setBottom(child->getDoubleValue());
_rect.setWidth(child->getDoubleValue()); } else if (name == "width") {
} else if (name == "height") { _rect.setWidth(child->getDoubleValue());
_rect.setHeight(child->getDoubleValue()); } else if (name == "height") {
} _rect.setHeight(child->getDoubleValue());
_attributes_dirty |= RECT;
return;
} }
_attributes_dirty |= RECT;
return;
}
if( child->getParent() != _node ) if( child->getParent() != _node )
return; return;
@@ -904,67 +922,68 @@ namespace canvas
return values; return values;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void operator+=(CoordList& base, const std::initializer_list<VGfloat>& other)
{
base.insert(base.end(), other.begin(), other.end());
}
void operator+=(CoordList& base, const std::initializer_list<VGfloat>& other) //----------------------------------------------------------------------------
{ void Path::parseRectToVGPath()
base.insert(base.end(), other.begin(), other.end()); {
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() SGVec2f topRight = parseRectCornerRadius(_node, "right", "top", haveCorner);
{ if (haveCorner) {
CmdList commands; commands.push_back(VG_HLINE_TO_ABS);
CoordList coords; coords += {_rect.r() - topRight.x()};
commands.reserve(4); commands.push_back(VG_SCCWARC_TO_REL);
coords.reserve(8); coords += {topRight.x(), topRight.y(), 0.0, topRight.x(), topRight.y()};
} else {
bool haveCorner = false; commands.push_back(VG_HLINE_TO_ABS);
SGVec2f topLeft = parseRectCornerRadius(_node, "left", "top", haveCorner); coords += {_rect.r()};
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 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 canvas
} // namespace simgear } // namespace simgear
+7 -7
View File
@@ -40,8 +40,6 @@ namespace canvas
ElementWeakPtr parent = 0 ); ElementWeakPtr parent = 0 );
virtual ~Path(); virtual ~Path();
virtual void update(double dt);
virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const; virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const;
/** Add a segment with the given command and coordinates */ /** Add a segment with the given command and coordinates */
@@ -68,10 +66,10 @@ namespace canvas
void setSVGPath(const std::string& svgPath); void setSVGPath(const std::string& svgPath);
void setRect(const SGRect<float>& r); void setRect(const SGRectf& r);
void setRoundRect(const SGRect<float>& r, float radiusX, float radiusY = -1.0); void setRoundRect(const SGRectf& r, float radiusX, float radiusY = -1.0);
protected:
protected:
enum PathAttributes enum PathAttributes
{ {
CMDS = LAST_ATTRIBUTE << 1, CMDS = LAST_ATTRIBUTE << 1,
@@ -86,12 +84,14 @@ namespace canvas
bool _hasSVG : 1; bool _hasSVG : 1;
bool _hasRect : 1; bool _hasRect : 1;
SGRect<float> _rect; SGRectf _rect;
void parseRectToVGPath(); virtual void updateImpl(double dt);
virtual void childRemoved(SGPropertyNode * child); virtual void childRemoved(SGPropertyNode * child);
virtual void childChanged(SGPropertyNode * child); virtual void childChanged(SGPropertyNode * child);
void parseRectToVGPath();
}; };
} // namespace canvas } // namespace canvas
+3 -3
View File
@@ -865,12 +865,12 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
osg::StateSet* Text::getOrCreateStateSet() osg::StateSet* Text::getOrCreateStateSet()
{ {
if( !_transform.valid() ) if( !_scene_group.valid() )
return 0; return nullptr;
// Only check for StateSet on Transform, as the text stateset is shared // Only check for StateSet on Transform, as the text stateset is shared
// between all text instances using the same font (texture). // between all text instances using the same font (texture).
return _transform->getOrCreateStateSet(); return _scene_group->getOrCreateStateSet();
} }
} // namespace canvas } // namespace canvas
+6
View File
@@ -155,6 +155,12 @@ public:
{ {
return std::isnan(v); return std::isnan(v);
} }
static bool eq(const T& a, const T& b, const T& epsilon = SGLimits<T>::epsilon())
{ return std::abs(a - b) < epsilon; }
static bool neq(const T& a, const T& b, const T& epsilon = SGLimits<T>::epsilon())
{ return !eq(a, b, epsilon); }
}; };
#endif #endif
+48 -4
View File
@@ -35,9 +35,16 @@
#include <fstream> #include <fstream>
#include <cstdlib> #include <cstdlib>
#ifdef _WIN32 #if !defined(SG_WINDOWS)
# include <direct.h> # include <sys/types.h>
# include <utime.h>
#endif #endif
#if defined(SG_WINDOWS)
# include <direct.h>
# include <sys/utime.h>
#endif
#include "sg_path.hxx" #include "sg_path.hxx"
#include <boost/algorithm/string/case_conv.hpp> #include <boost/algorithm/string/case_conv.hpp>
@@ -52,13 +59,13 @@ using simgear::strutils::starts_with;
static const char sgDirPathSep = '/'; static const char sgDirPathSep = '/';
static const char sgDirPathSepBad = '\\'; static const char sgDirPathSepBad = '\\';
#ifdef _WIN32 #if defined(SG_WINDOWS)
const char SGPath::pathListSep[] = ";"; // this is null-terminated const char SGPath::pathListSep[] = ";"; // this is null-terminated
#else #else
const char SGPath::pathListSep[] = ":"; // ditto const char SGPath::pathListSep[] = ":"; // ditto
#endif #endif
#ifdef _WIN32 #if defined(SG_WINDOWS)
#include <ShlObj.h> // for CSIDL #include <ShlObj.h> // for CSIDL
// TODO: replace this include file with the official <versionhelpers.h> header // TODO: replace this include file with the official <versionhelpers.h> header
// included in the Windows 8.1 SDK // included in the Windows 8.1 SDK
@@ -1048,3 +1055,40 @@ std::string SGPath::fileUrl() const
return {}; 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;
}
+7
View File
@@ -282,6 +282,13 @@ public:
*/ */
std::string fileUrl() const; 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 enum StandardLocation
{ {
HOME, HOME,
+7 -7
View File
@@ -44,13 +44,6 @@ namespace nasal
Hash newHash(); Hash newHash();
String newString(const char* str); String newString(const char* str);
/** Create a new nasal vector and fill it with the given values */
template<class... Vals>
naRef newVector(Vals ... vals)
{
return newVector({to_nasal(vals)...});
}
/** Raise a nasal runtime error */ /** Raise a nasal runtime error */
template<class... Args> template<class... Args>
void runtimeError(const char* fmt, Args ... args) const void runtimeError(const char* fmt, Args ... args) const
@@ -70,6 +63,13 @@ namespace nasal
return nasal::to_nasal(_ctx, array); return nasal::to_nasal(_ctx, array);
} }
/** Create a nasal vector filled with the given values */
template<class... Vals>
naRef to_nasal_vec(Vals ... vals)
{
return newVector({to_nasal(vals)...});
}
template<class T> template<class T>
Me to_me(T arg) const Me to_me(T arg) const
{ {
@@ -28,14 +28,13 @@
#include <simgear/nasal/cppbind/NasalMe.hxx> #include <simgear/nasal/cppbind/NasalMe.hxx>
#include <simgear/nasal/cppbind/NasalMethodHolder.hxx> #include <simgear/nasal/cppbind/NasalMethodHolder.hxx>
#include <simgear/nasal/cppbind/NasalObjectHolder.hxx> #include <simgear/nasal/cppbind/NasalObjectHolder.hxx>
#include <simgear/std/type_traits.hxx>
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
#include <simgear/structure/SGSharedPtr.hxx> #include <simgear/structure/SGSharedPtr.hxx>
#include <boost/bind.hpp>
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>
#include <array>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -143,9 +142,7 @@ namespace nasal
* Convert a Nasal number to a C++ numeric type * Convert a Nasal number to a C++ numeric type
*/ */
template<class T> template<class T>
typename boost::enable_if< boost::is_arithmetic<T>, std::enable_if_t<std::is_arithmetic<T>::value, T>
T
>::type
from_nasal_helper(naContext c, naRef ref, const T*) from_nasal_helper(naContext c, naRef ref, const T*)
{ {
naRef num = naNumValue(ref); naRef num = naNumValue(ref);
@@ -174,17 +171,39 @@ namespace nasal
return vec; return vec;
} }
/**
* Convert a Nasal vector to a std::array
*/
template<class T, std::size_t N>
std::array<T, N>
from_nasal_helper(naContext c, naRef ref, const std::array<T, N>*)
{
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<T, N> arr;
for(std::size_t i = 0; i < N; ++i)
arr[i] = from_nasal_helper(c, naVec_get(ref, i), static_cast<T*>(0));
return arr;
}
/** /**
* Convert a Nasal vector of 2 elements to a 2d vector * Convert a Nasal vector of 2 elements to a 2d vector
*/ */
template<class Vec2> template<class Vec2>
typename boost::enable_if<is_vec2<Vec2>, Vec2>::type std::enable_if_t<is_vec2<Vec2>::value, Vec2>
from_nasal_helper(naContext c, naRef ref, const Vec2*) from_nasal_helper(naContext c, naRef ref, const Vec2*)
{ {
std::vector<double> vec = auto vec =
from_nasal_helper(c, ref, static_cast<std::vector<double>*>(0)); from_nasal_helper(c, ref, static_cast<std::array<double, 2>*>(0));
if( vec.size() != 2 )
throw bad_nasal_cast("Expected vector with two elements");
return Vec2(vec[0], vec[1]); return Vec2(vec[0], vec[1]);
} }
@@ -194,10 +213,8 @@ namespace nasal
template<class T> template<class T>
SGRect<T> from_nasal_helper(naContext c, naRef ref, const SGRect<T>*) SGRect<T> from_nasal_helper(naContext c, naRef ref, const SGRect<T>*)
{ {
std::vector<double> vec = auto vec =
from_nasal_helper(c, ref, static_cast<std::vector<double>*>(0)); from_nasal_helper(c, ref, static_cast<std::array<double, 4>*>(0));
if( vec.size() != 4 )
throw bad_nasal_cast("Expected vector with four elements");
return SGRect<T>(vec[0], vec[1], vec[2], vec[3]); return SGRect<T>(vec[0], vec[1], vec[2], vec[3]);
} }
@@ -25,12 +25,13 @@
#include <simgear/math/SGMath.hxx> #include <simgear/math/SGMath.hxx>
#include <simgear/math/SGRect.hxx> #include <simgear/math/SGRect.hxx>
#include <simgear/nasal/cppbind/cppbind_fwd.hxx> #include <simgear/nasal/cppbind/cppbind_fwd.hxx>
#include <simgear/std/type_traits.hxx>
#include <boost/function/function_fwd.hpp> #include <boost/function/function_fwd.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/call_traits.hpp> #include <boost/call_traits.hpp>
#include <boost/type_traits.hpp>
#include <array>
#include <initializer_list>
#include <map> #include <map>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -75,11 +76,66 @@ namespace nasal
naRef to_nasal_helper(naContext c, const free_function_t& func); naRef to_nasal_helper(naContext c, const free_function_t& func);
namespace detail
{
template<class T>
naRef array_to_nasal(naContext c, const T* arr, size_t size);
}
/**
* Convert a fixed size array to a Nasal vector
*/
template<class T, size_t N>
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<class T, size_t N>
naRef to_nasal_helper(naContext c, const std::array<T, N>& array)
{
return detail::array_to_nasal(c, array.data(), N);
}
/**
* Convert a std::initializer_list to a Nasal vector
*/
template<class T>
naRef to_nasal_helper(naContext c, std::initializer_list<T> list)
{
return detail::array_to_nasal(c, list.begin(), list.size());
}
/**
* Convert std::vector to a Nasal vector
*/
template< template<class T, class Alloc> class Vector,
class T,
class Alloc
>
std::enable_if_t<
std::is_same<Vector<T,Alloc>, std::vector<T,Alloc>>::value,
naRef
>
to_nasal_helper(naContext c, const Vector<T, Alloc>& vec)
{
return detail::array_to_nasal(c, vec.data(), vec.size());
}
/**
* Convert a std::map to a Nasal Hash
*/
template<class Value>
naRef to_nasal_helper(naContext c, const std::map<std::string, Value>& map);
/** /**
* Convert an enum value to the according numeric value * Convert an enum value to the according numeric value
*/ */
template<class T> template<class T>
typename boost::enable_if< boost::is_enum<T>, naRef >::type std::enable_if_t<std::is_enum<T>::value, naRef>
to_nasal_helper(naContext c, T val) to_nasal_helper(naContext c, T val)
{ {
return naNum(val); return naNum(val);
@@ -89,7 +145,7 @@ namespace nasal
* Convert a numeric type to Nasal number * Convert a numeric type to Nasal number
*/ */
template<class T> template<class T>
typename boost::enable_if< boost::is_arithmetic<T>, naRef >::type std::enable_if_t<std::is_arithmetic<T>::value, naRef>
to_nasal_helper(naContext c, T num) to_nasal_helper(naContext c, T num)
{ {
return naNum(num); return naNum(num);
@@ -99,67 +155,40 @@ namespace nasal
* Convert a 2d vector to Nasal vector with 2 elements * Convert a 2d vector to Nasal vector with 2 elements
*/ */
template<class Vec2> template<class Vec2>
typename boost::enable_if<is_vec2<Vec2>, naRef>::type std::enable_if_t<is_vec2<Vec2>::value, naRef>
to_nasal_helper(naContext c, const Vec2& vec);
/**
* Convert a std::map to a Nasal Hash
*/
template<class Value>
naRef to_nasal_helper(naContext c, const std::map<std::string, Value>& map);
/**
* Convert a fixed size array to a Nasal vector
*/
template<class T, size_t N>
naRef to_nasal_helper(naContext c, const T(&array)[N]);
/**
* Convert std::vector to Nasal vector
*/
template< template<class T, class Alloc> class Vector,
class T,
class Alloc
>
typename boost::enable_if< boost::is_same< Vector<T,Alloc>,
std::vector<T,Alloc>
>,
naRef
>::type
to_nasal_helper(naContext c, const Vector<T, Alloc>& vec)
{
naRef ret = naNewVector(c);
naVec_setsize(c, ret, static_cast<int>(vec.size()));
for(int i = 0; i < static_cast<int>(vec.size()); ++i)
naVec_set(ret, i, to_nasal_helper(c, vec[i]));
return ret;
}
//----------------------------------------------------------------------------
template<class Vec2>
typename boost::enable_if<is_vec2<Vec2>, naRef>::type
to_nasal_helper(naContext c, const Vec2& vec) to_nasal_helper(naContext c, const Vec2& vec)
{ {
// We take just double because in Nasal every number is represented as return to_nasal_helper(c, {
// double // We take just double because in Nasal every number is represented as
double nasal_vec[2] = { // double
static_cast<double>(vec[0]), static_cast<double>(vec[0]),
static_cast<double>(vec[1]) static_cast<double>(vec[1])
}; });
return to_nasal_helper(c, nasal_vec); }
/**
* Convert a SGRect to a Nasal vector with position and size of the rect
*/
template<class T>
naRef to_nasal_helper(naContext c, const SGRect<T>& rect)
{
return to_nasal_helper(c, {
static_cast<double>(rect.x()),
static_cast<double>(rect.y()),
static_cast<double>(rect.width()),
static_cast<double>(rect.height())
});
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
template<class T> template<class T>
naRef to_nasal_helper(naContext c, const SGRect<T>& rect) naRef detail::array_to_nasal(naContext c, const T* arr, size_t size)
{ {
std::vector<double> vec(4); naRef ret = naNewVector(c);
vec[0] = rect.x(); naVec_setsize(c, ret, static_cast<int>(size));
vec[1] = rect.y(); for(int i = 0; i < static_cast<int>(size); ++i)
vec[2] = rect.width(); naVec_set(ret, i, to_nasal_helper(c, arr[i]));
vec[3] = rect.height(); return ret;
return to_nasal_helper(c, vec);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -182,17 +211,6 @@ namespace nasal
return hash; return hash;
} }
//----------------------------------------------------------------------------
template<class T, size_t N>
naRef to_nasal_helper(naContext c, const T(&array)[N])
{
naRef ret = naNewVector(c);
naVec_setsize(c, ret, static_cast<int>(N));
for(int i = 0; i < static_cast<int>(N); ++i)
naVec_set(ret, i, to_nasal_helper(c, array[i]));
return ret;
}
} // namespace nasal } // namespace nasal
#endif /* SG_TO_NASAL_HELPER_HXX_ */ #endif /* SG_TO_NASAL_HELPER_HXX_ */
+46 -1
View File
@@ -117,6 +117,51 @@ naRef f_derivedGetX(const Derived& d, naContext c)
} }
naRef f_freeFunction(nasal::CallContext c) { return c.requireArg<naRef>(0); } naRef f_freeFunction(nasal::CallContext c) { return c.requireArg<naRef>(0); }
namespace std
{
template<class T, std::size_t N>
ostream& operator<<(ostream& strm, const array<T, N>& 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<int>(naVec_get(na_vec, 0)), 1);
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(na_vec, 1)), 2);
BOOST_CHECK_EQUAL(ctx.from_nasal<double>(naVec_get(na_vec, 2)), 3.42);
na_vec = ctx.to_nasal(std::initializer_list<double>({1., 2., 3.42}));
BOOST_REQUIRE( naIsVector(na_vec) );
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(na_vec, 0)), 1);
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(na_vec, 1)), 2);
BOOST_CHECK_EQUAL(ctx.from_nasal<double>(naVec_get(na_vec, 2)), 3.42);
using arr_d3_t = std::array<double, 3>;
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<int>(naVec_get(na_vec, 0)), 1);
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(na_vec, 1)), 2);
BOOST_CHECK_EQUAL(ctx.from_nasal<double>(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<int>(naVec_get(na_vec, 0)), 1);
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(na_vec, 1)), 2);
BOOST_CHECK_EQUAL(ctx.from_nasal<double>(naVec_get(na_vec, 2)), 3.42);
BOOST_CHECK_EQUAL(std_arr, ctx.from_nasal<arr_d3_t>(na_vec));
}
BOOST_AUTO_TEST_CASE( cppbind_misc_testing ) BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
{ {
TestContext c; TestContext c;
@@ -439,7 +484,7 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
BOOST_AUTO_TEST_CASE( cppbind_context ) BOOST_AUTO_TEST_CASE( cppbind_context )
{ {
nasal::Context ctx; 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_REQUIRE( naIsVector(vec) );
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(vec, 0)), 1); BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(vec, 0)), 1);
+28 -17
View File
@@ -164,13 +164,23 @@ public:
// (eg Ibiblio) and retry up to the max count // (eg Ibiblio) and retry up to the max count
const int retries = (thumbnailCache[u].retryCount++); const int retries = (thumbnailCache[u].retryCount++);
if (retries < 3) { 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; thumbnailCache[u].requestPending = true;
pendingThumbnails.push_back(u); pendingThumbnails.push_back(u);
} }
} else { } else {
// any other failure. // any other failure.
thumbnailCache[u].requestPending = false; 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(); 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 // append the correct file suffix
auto pos = url.rfind('.'); auto pos = url.rfind('.');
if (pos == std::string::npos) { 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); sg_ofstream fstream(cachePath, std::ios::out | std::ios::trunc | std::ios::binary);
fstream.write(imageBytes.data(), imageBytes.size()); fstream.write(imageBytes.data(), imageBytes.size());
fstream.close(); fstream.close();
@@ -229,23 +246,17 @@ public:
bool checkPersistentCache(const std::string& url) bool checkPersistentCache(const std::string& url)
{ {
std::string hash = hashForUrl(url); SGPath cachePath = pathInCache(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));
if (!cachePath.exists()) { if (!cachePath.exists()) {
return false; return false;
} }
// check age, if it's too old, expire and download again // check age, if it's too old, expire and download again
int age = time(nullptr) - cachePath.modTime(); int age = time(nullptr) - cachePath.modTime();
if (age > SECONDS_PER_DAY * 7) { // cache for seven days const int cacheMaxAge = SECONDS_PER_DAY * 7;
SG_LOG(SG_IO, SG_INFO, "expiring old cached thumbnail " << url); if (age > cacheMaxAge) { // cache for seven days
cachePath.remove(); // note we do *not* remove the file data here, since the
// cache refresh might fail
return false; return false;
} }
@@ -263,7 +274,7 @@ public:
entry.pathOnDisk = path; entry.pathOnDisk = path;
it = thumbnailCache.insert(it, std::make_pair(url, entry)); it = thumbnailCache.insert(it, std::make_pair(url, entry));
} else { } else {
assert(it->second.pathOnDisk == path); assert(it->second.pathOnDisk.isNull() || (it->second.pathOnDisk == path));
} }
if (it->second.requestPending) { if (it->second.requestPending) {
+2 -2
View File
@@ -18,7 +18,7 @@
#include <simgear_config.h> #include <simgear_config.h>
#include "PropertyBasedElement.hxx" #include "PropertyBasedElement.hxx"
#include <boost/algorithm/string/predicate.hpp> #include <simgear/misc/strutils.hxx>
namespace simgear namespace simgear
{ {
@@ -130,7 +130,7 @@ namespace simgear
// character that followed it by the same character converted to ASCII // character that followed it by the same character converted to ASCII
// uppercase. // uppercase.
if( !boost::starts_with(name, DATA_PREFIX) ) if( !strutils::starts_with(name, DATA_PREFIX) )
return std::string(); return std::string();
std::string data_name; std::string data_name;
+7 -10
View File
@@ -20,6 +20,7 @@
#define SG_PROPERTY_BASED_ELEMENT_HXX_ #define SG_PROPERTY_BASED_ELEMENT_HXX_
#include <simgear/props/props.hxx> #include <simgear/props/props.hxx>
#include <simgear/std/type_traits.hxx>
#include <simgear/structure/SGWeakReferenced.hxx> #include <simgear/structure/SGWeakReferenced.hxx>
namespace simgear namespace simgear
@@ -120,11 +121,9 @@ namespace simgear
* @see setDataProp * @see setDataProp
*/ */
template<class T> template<class T>
typename boost::disable_if< std::enable_if_t<!std::is_same<T, SGPropertyNode*>::value, T>
boost::is_same<T, SGPropertyNode*>, getDataProp( const std::string& name,
T const T& def = {} ) const
>::type getDataProp( const std::string& name,
const T& def = T() ) const
{ {
SGPropertyNode* node = getDataProp<SGPropertyNode*>(name); SGPropertyNode* node = getDataProp<SGPropertyNode*>(name);
if( node ) if( node )
@@ -140,11 +139,9 @@ namespace simgear
* @see setDataProp * @see setDataProp
*/ */
template<class T> template<class T>
typename boost::enable_if< std::enable_if_t<std::is_same<T, SGPropertyNode*>::value, T>
boost::is_same<T, SGPropertyNode*>, getDataProp( const std::string& name,
T SGPropertyNode* = nullptr ) const
>::type getDataProp( const std::string& name,
SGPropertyNode* = NULL ) const
{ {
const std::string& attr = dataPropToAttrName(name); const std::string& attr = dataPropToAttrName(name);
if( attr.empty() ) if( attr.empty() )
+1 -1
View File
@@ -827,7 +827,7 @@ SGPropertyNode::trace_read () const
* Last used attribute * Last used attribute
* Update as needed when enum Attribute is changed * 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. * Default constructor: always creates a root node.
+3 -2
View File
@@ -814,7 +814,8 @@ public:
TRACE_READ = 16, TRACE_READ = 16,
TRACE_WRITE = 32, TRACE_WRITE = 32,
USERARCHIVE = 64, USERARCHIVE = 64,
PRESERVE = 128 PRESERVE = 128,
PROTECTED = 1 << 8,
// beware: if you add another attribute here, // beware: if you add another attribute here,
// also update value of "LAST_USED_ATTRIBUTE". // also update value of "LAST_USED_ATTRIBUTE".
}; };
@@ -1854,7 +1855,7 @@ private:
mutable std::string _buffer; mutable std::string _buffer;
simgear::props::Type _type; simgear::props::Type _type;
bool _tied; bool _tied;
int _attr; int _attr = NO_ATTR;
// The right kind of pointer... // The right kind of pointer...
union { union {
+3
View File
@@ -251,6 +251,9 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
setFlag(mode, SGPropertyNode::USERARCHIVE, val, location); setFlag(mode, SGPropertyNode::USERARCHIVE, val, location);
else if( att_name == "preserve" ) else if( att_name == "preserve" )
setFlag(mode, SGPropertyNode::PRESERVE, val, location); 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. // Check for an alias.
else if( att_name == "alias" ) else if( att_name == "alias" )
+14 -24
View File
@@ -137,10 +137,8 @@ void SGSampleGroup::update( double dt ) {
_changed = false; _changed = false;
} }
sample_map_iterator sample_current = _samples.begin(); for (auto current =_samples.begin(); current !=_samples.end(); ++current) {
sample_map_iterator sample_end = _samples.end(); SGSoundSample *sample = current->second;
for ( ; sample_current != sample_end; ++sample_current ) {
SGSoundSample *sample = sample_current->second;
if ( !sample->is_valid_source() && sample->is_playing() && !sample->test_out_of_range()) { if ( !sample->is_valid_source() && sample->is_playing() && !sample->test_out_of_range()) {
start_playing_sample(sample); start_playing_sample(sample);
@@ -156,7 +154,7 @@ void SGSampleGroup::update( double dt ) {
bool SGSampleGroup::add( SGSharedPtr<SGSoundSample> sound, bool SGSampleGroup::add( SGSharedPtr<SGSoundSample> sound,
const std::string& refname ) const std::string& refname )
{ {
sample_map_iterator sample_it = _samples.find( refname ); auto sample_it = _samples.find( refname );
if ( sample_it != _samples.end() ) { if ( sample_it != _samples.end() ) {
// sample name already exists // sample name already exists
return false; return false;
@@ -170,7 +168,7 @@ bool SGSampleGroup::add( SGSharedPtr<SGSoundSample> sound,
// remove a sound effect, return true if successful // remove a sound effect, return true if successful
bool SGSampleGroup::remove( const std::string &refname ) { 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() ) { if ( sample_it == _samples.end() ) {
// sample was not found // sample was not found
return false; 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 // return true of the specified sound exists in the sound manager system
bool SGSampleGroup::exists( const std::string &refname ) { 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() ) { if ( sample_it == _samples.end() ) {
// sample was not found // sample was not found
return false; return false;
@@ -200,7 +198,7 @@ bool SGSampleGroup::exists( const std::string &refname ) {
// return a pointer to the SGSoundSample if the specified sound exists // return a pointer to the SGSoundSample if the specified sound exists
// in the sound manager system, otherwise return NULL // in the sound manager system, otherwise return NULL
SGSoundSample *SGSampleGroup::find( const std::string &refname ) { 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() ) { if ( sample_it == _samples.end() ) {
// sample was not found // sample was not found
return NULL; return NULL;
@@ -214,10 +212,8 @@ void
SGSampleGroup::stop () SGSampleGroup::stop ()
{ {
_pause = true; _pause = true;
sample_map_iterator sample_current = _samples.begin(); for (auto current =_samples.begin(); current !=_samples.end(); ++current) {
sample_map_iterator sample_end = _samples.end(); SGSoundSample *sample = current->second;
for ( ; sample_current != sample_end; ++sample_current ) {
SGSoundSample *sample = sample_current->second;
_smgr->sample_destroy( sample ); _smgr->sample_destroy( sample );
} }
} }
@@ -228,11 +224,9 @@ SGSampleGroup::suspend ()
{ {
if (_active && _pause == false) { if (_active && _pause == false) {
_pause = true; _pause = true;
sample_map_iterator sample_current = _samples.begin(); for (auto current =_samples.begin(); current !=_samples.end(); ++current) {
sample_map_iterator sample_end = _samples.end();
for ( ; sample_current != sample_end; ++sample_current ) {
#ifdef ENABLE_SOUND #ifdef ENABLE_SOUND
SGSoundSample *sample = sample_current->second; SGSoundSample *sample = current->second;
_smgr->sample_suspend( sample ); _smgr->sample_suspend( sample );
#endif #endif
} }
@@ -246,10 +240,8 @@ SGSampleGroup::resume ()
{ {
if (_active && _pause == true) { if (_active && _pause == true) {
#ifdef ENABLE_SOUND #ifdef ENABLE_SOUND
sample_map_iterator sample_current = _samples.begin(); for (auto current =_samples.begin(); current !=_samples.end(); ++current) {
sample_map_iterator sample_end = _samples.end(); SGSoundSample *sample = current->second;
for ( ; sample_current != sample_end; ++sample_current ) {
SGSoundSample *sample = sample_current->second;
_smgr->sample_resume( sample ); _smgr->sample_resume( sample );
} }
testForMgrError("resume"); testForMgrError("resume");
@@ -319,10 +311,8 @@ void SGSampleGroup::update_pos_and_orientation() {
velocity = toVec3f( hlOr.backTransform(_velocity*SG_FEET_TO_METER) ); velocity = toVec3f( hlOr.backTransform(_velocity*SG_FEET_TO_METER) );
} }
sample_map_iterator sample_current = _samples.begin(); for (auto current =_samples.begin(); current !=_samples.end(); ++current ) {
sample_map_iterator sample_end = _samples.end(); SGSoundSample *sample = current->second;
for ( ; sample_current != sample_end; ++sample_current ) {
SGSoundSample *sample = sample_current->second;
sample->set_master_volume( _volume ); sample->set_master_volume( _volume );
sample->set_orientation( _orientation ); sample->set_orientation( _orientation );
sample->set_rotation( ec2body ); sample->set_rotation( ec2body );
-2
View File
@@ -40,8 +40,6 @@
typedef std::map < std::string, SGSharedPtr<SGSoundSample> > sample_map; typedef std::map < std::string, SGSharedPtr<SGSoundSample> > sample_map;
typedef sample_map::iterator sample_map_iterator;
typedef sample_map::const_iterator const_sample_map_iterator;
class SGSoundMgr; class SGSoundMgr;
+25 -38
View File
@@ -36,7 +36,6 @@
#include <cstring> #include <cstring>
#include <cassert> #include <cassert>
#include <boost/foreach.hpp>
#include <aax/aeonwave.hpp> #include <aax/aeonwave.hpp>
#include "soundmgr.hxx" #include "soundmgr.hxx"
@@ -50,17 +49,10 @@
// We keep track of the emitters ourselves. // We keep track of the emitters ourselves.
typedef std::map < unsigned int, aax::Emitter > source_map; 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. // The AeonWave class keeps track of the buffers, so use a reference instead.
typedef std::map < unsigned int, aax::Buffer& > buffer_map; 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<SGSampleGroup> > sample_group_map; typedef std::map < std::string, SGSharedPtr<SGSampleGroup> > 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 #ifndef NDEBUG
# define TRY(a) if ((a) == 0) printf("%i: %s\n", __LINE__, d->_aax.strerror()) # define TRY(a) if ((a) == 0) printf("%i: %s\n", __LINE__, d->_aax.strerror())
@@ -83,8 +75,7 @@ public:
~SoundManagerPrivate() ~SoundManagerPrivate()
{ {
std::vector<const char*>::iterator it; for (auto it = _devices.begin(); it != _devices.end(); ++it) {
for (it = _devices.begin(); it != _devices.end(); ++it) {
free((void*)*it); free((void*)*it);
} }
_devices.clear(); _devices.clear();
@@ -117,7 +108,7 @@ public:
buffer_map _buffers; buffer_map _buffers;
aax::Buffer nullBuffer; aax::Buffer nullBuffer;
aax::Buffer& get_buffer(unsigned int id) { 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; if ( buffer_it != _buffers.end() ) return buffer_it->second;
SG_LOG(SG_SOUND, SG_ALERT, "unknown buffer id requested."); SG_LOG(SG_SOUND, SG_ALERT, "unknown buffer id requested.");
return nullBuffer; return nullBuffer;
@@ -127,7 +118,7 @@ public:
source_map _sources; source_map _sources;
aax::Emitter nullEmitter; aax::Emitter nullEmitter;
aax::Emitter& get_emitter(unsigned int id) { 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; if ( source_it != _sources.end() ) return source_it->second;
SG_LOG(SG_SOUND, SG_ALERT, "unknown source id requested."); SG_LOG(SG_SOUND, SG_ALERT, "unknown source id requested.");
return nullEmitter; return nullEmitter;
@@ -149,6 +140,7 @@ SGSoundMgr::SGSoundMgr() :
_changed(true), _changed(true),
_volume(0.0), _volume(0.0),
_velocity(SGVec3d::zeros()), _velocity(SGVec3d::zeros()),
_bad_doppler(false),
_renderer("unknown"), _renderer("unknown"),
_vendor("unknown") _vendor("unknown")
{ {
@@ -243,10 +235,9 @@ void SGSoundMgr::activate()
if ( is_working() ) { if ( is_working() ) {
_active = true; _active = true;
sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); for ( auto current = d->_sample_groups.begin();
sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); current != d->_sample_groups.end(); ++current ) {
for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { SGSampleGroup *sgrp = current->second;
SGSampleGroup *sgrp = sample_grp_current->second;
sgrp->activate(); sgrp->activate();
} }
} }
@@ -258,10 +249,9 @@ void SGSoundMgr::stop()
{ {
#ifdef ENABLE_SOUND #ifdef ENABLE_SOUND
// first stop all sample groups // first stop all sample groups
sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); for ( auto current = d->_sample_groups.begin();
sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); current != d->_sample_groups.end(); ++ current ) {
for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { SGSampleGroup *sgrp = current->second;
SGSampleGroup *sgrp = sample_grp_current->second;
sgrp->stop(); sgrp->stop();
} }
@@ -285,10 +275,9 @@ void SGSoundMgr::suspend()
{ {
#ifdef ENABLE_SOUND #ifdef ENABLE_SOUND
if (is_working()) { if (is_working()) {
sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); for (auto current = d->_sample_groups.begin();
sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); current != d->_sample_groups.end(); ++current ) {
for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { SGSampleGroup *sgrp = current->second;
SGSampleGroup *sgrp = sample_grp_current->second;
sgrp->stop(); sgrp->stop();
} }
_active = false; _active = false;
@@ -300,10 +289,9 @@ void SGSoundMgr::resume()
{ {
#ifdef ENABLE_SOUND #ifdef ENABLE_SOUND
if (is_working()) { if (is_working()) {
sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); for ( auto current = d->_sample_groups.begin();
sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); current != d->_sample_groups.end(); ++current ) {
for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { SGSampleGroup *sgrp = current->second;
SGSampleGroup *sgrp = sample_grp_current->second;
sgrp->resume(); sgrp->resume();
} }
_active = true; _active = true;
@@ -320,10 +308,9 @@ void SGSoundMgr::update( double dt )
d->update_pos_and_orientation(); d->update_pos_and_orientation();
} }
sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); for ( auto current = d->_sample_groups.begin();
sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); current != d->_sample_groups.end(); ++current ) {
for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { SGSampleGroup *sgrp = current->second;
SGSampleGroup *sgrp = sample_grp_current->second;
sgrp->update(dt); sgrp->update(dt);
} }
@@ -360,7 +347,7 @@ void SGSoundMgr::update( double dt )
// add a sample group, return true if successful // add a sample group, return true if successful
bool SGSoundMgr::add( SGSampleGroup *sgrp, const std::string& refname ) 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() ) { if ( sample_grp_it != d->_sample_groups.end() ) {
// sample group already exists // sample group already exists
return false; return false;
@@ -376,7 +363,7 @@ bool SGSoundMgr::add( SGSampleGroup *sgrp, const std::string& refname )
// remove a sound effect, return true if successful // remove a sound effect, return true if successful
bool SGSoundMgr::remove( const std::string &refname ) 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() ) { if ( sample_grp_it == d->_sample_groups.end() ) {
// sample group was not found. // sample group was not found.
return false; 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 // return true of the specified sound exists in the sound manager system
bool SGSoundMgr::exists( const std::string &refname ) { 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() ); 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 // return a pointer to the SGSampleGroup if the specified sound exists
// in the sound manager system, otherwise return NULL // in the sound manager system, otherwise return NULL
SGSampleGroup *SGSoundMgr::find( const std::string &refname, bool create ) { 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() ) { if ( sample_grp_it == d->_sample_groups.end() ) {
// sample group was not found. // sample group was not found.
if (create) { if (create) {
@@ -432,7 +419,7 @@ unsigned int SGSoundMgr::request_source()
// Free up a source id // Free up a source id
void SGSoundMgr::release_source( unsigned int source ) 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() ) if ( source_it != d->_sources.end() )
{ {
aax::Emitter& emitter = source_it->second; aax::Emitter& emitter = source_it->second;
@@ -527,7 +514,7 @@ void SGSoundMgr::release_buffer(SGSoundSample *sample)
if ( !sample->is_queue() ) if ( !sample->is_queue() )
{ {
unsigned int buffer = sample->get_buffer(); 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() ) if ( buffer_it != d->_buffers.end() )
{ {
sample->no_valid_buffer(); sample->no_valid_buffer();
+26 -36
View File
@@ -36,8 +36,6 @@
#include <cstring> #include <cstring>
#include <cassert> #include <cassert>
#include <boost/foreach.hpp>
#include "soundmgr.hxx" #include "soundmgr.hxx"
#include "readwav.hxx" #include "readwav.hxx"
#include "soundmgr_openal_private.hxx" #include "soundmgr_openal_private.hxx"
@@ -283,10 +281,9 @@ void SGSoundMgr::activate()
if ( is_working() ) { if ( is_working() ) {
_active = true; _active = true;
sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); for ( auto current = d->_sample_groups.begin();
sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); current != d->_sample_groups.end(); ++current ) {
for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { SGSampleGroup *sgrp = current->second;
SGSampleGroup *sgrp = sample_grp_current->second;
sgrp->activate(); sgrp->activate();
} }
} }
@@ -298,25 +295,23 @@ void SGSoundMgr::stop()
{ {
#ifdef ENABLE_SOUND #ifdef ENABLE_SOUND
// first stop all sample groups // first stop all sample groups
sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); for ( auto current = d->_sample_groups.begin();
sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); current != d->_sample_groups.end(); ++current ) {
for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { SGSampleGroup *sgrp = current->second;
SGSampleGroup *sgrp = sample_grp_current->second;
sgrp->stop(); sgrp->stop();
} }
// clear all OpenAL sources // clear all OpenAL sources
BOOST_FOREACH(ALuint source, d->_free_sources) { for(ALuint source : d->_free_sources) {
alDeleteSources( 1 , &source ); alDeleteSources( 1 , &source );
testForError("SGSoundMgr::stop: delete sources"); testForError("SGSoundMgr::stop: delete sources");
} }
d->_free_sources.clear(); d->_free_sources.clear();
// clear any OpenAL buffers before shutting down // clear any OpenAL buffers before shutting down
buffer_map_iterator buffers_current = d->_buffers.begin(); for ( auto current = d->_buffers.begin();
buffer_map_iterator buffers_end = d->_buffers.end(); current != d->_buffers.begin(); ++current ) {
for ( ; buffers_current != buffers_end; ++buffers_current ) { refUint ref = current->second;
refUint ref = buffers_current->second;
ALuint buffer = ref.id; ALuint buffer = ref.id;
alDeleteBuffers(1, &buffer); alDeleteBuffers(1, &buffer);
testForError("SGSoundMgr::stop: delete buffers"); testForError("SGSoundMgr::stop: delete buffers");
@@ -342,10 +337,9 @@ void SGSoundMgr::suspend()
{ {
#ifdef ENABLE_SOUND #ifdef ENABLE_SOUND
if (is_working()) { if (is_working()) {
sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); for ( auto current = d->_sample_groups.begin();
sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); current != d->_sample_groups.end(); ++current ) {
for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { SGSampleGroup *sgrp = current->second;
SGSampleGroup *sgrp = sample_grp_current->second;
sgrp->stop(); sgrp->stop();
} }
_active = false; _active = false;
@@ -357,10 +351,9 @@ void SGSoundMgr::resume()
{ {
#ifdef ENABLE_SOUND #ifdef ENABLE_SOUND
if (is_working()) { if (is_working()) {
sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); for ( auto current = d->_sample_groups.begin();
sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); current != d->_sample_groups.end(); ++current ) {
for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { SGSampleGroup *sgrp = current->second;
SGSampleGroup *sgrp = sample_grp_current->second;
sgrp->resume(); sgrp->resume();
} }
_active = true; _active = true;
@@ -379,10 +372,9 @@ void SGSoundMgr::update( double dt )
d->update_pos_and_orientation(); d->update_pos_and_orientation();
} }
sample_group_map_iterator sample_grp_current = d->_sample_groups.begin(); for ( auto current = d->_sample_groups.begin();
sample_group_map_iterator sample_grp_end = d->_sample_groups.end(); current != d->_sample_groups.end(); ++current ) {
for ( ; sample_grp_current != sample_grp_end; ++sample_grp_current ) { SGSampleGroup *sgrp = current->second;
SGSampleGroup *sgrp = sample_grp_current->second;
sgrp->update(dt); 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 // add a sample group, return true if successful
bool SGSoundMgr::add( SGSampleGroup *sgrp, const std::string& refname ) 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() ) { if ( sample_grp_it != d->_sample_groups.end() ) {
// sample group already exists // sample group already exists
return false; return false;
@@ -436,7 +428,7 @@ bool SGSoundMgr::add( SGSampleGroup *sgrp, const std::string& refname )
// remove a sound effect, return true if successful // remove a sound effect, return true if successful
bool SGSoundMgr::remove( const std::string &refname ) 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() ) { if ( sample_grp_it == d->_sample_groups.end() ) {
// sample group was not found. // sample group was not found.
return false; 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 // return true of the specified sound exists in the sound manager system
bool SGSoundMgr::exists( const std::string &refname ) { 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() ); 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 // return a pointer to the SGSampleGroup if the specified sound exists
// in the sound manager system, otherwise return NULL // in the sound manager system, otherwise return NULL
SGSampleGroup *SGSoundMgr::find( const std::string &refname, bool create ) { 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() ) { if ( sample_grp_it == d->_sample_groups.end() ) {
// sample group was not found. // sample group was not found.
if (create) { if (create) {
@@ -508,9 +500,7 @@ unsigned int SGSoundMgr::request_source()
// Free up a source id for further use // Free up a source id for further use
void SGSoundMgr::release_source( unsigned int source ) void SGSoundMgr::release_source( unsigned int source )
{ {
vector<ALuint>::iterator it; auto it = std::find(d->_sources_in_use.begin(), d->_sources_in_use.end(), source);
it = std::find(d->_sources_in_use.begin(), d->_sources_in_use.end(), source);
if ( it != d->_sources_in_use.end() ) { if ( it != d->_sources_in_use.end() ) {
#ifdef ENABLE_SOUND #ifdef ENABLE_SOUND
ALint result; ALint result;
@@ -538,7 +528,7 @@ unsigned int SGSoundMgr::request_buffer(SGSoundSample *sample)
void *sample_data = NULL; void *sample_data = NULL;
// see if the sample name is already cached // 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() ) { if ( buffer_it != d->_buffers.end() ) {
buffer_it->second.refctr++; buffer_it->second.refctr++;
buffer = buffer_it->second.id; buffer = buffer_it->second.id;
@@ -632,7 +622,7 @@ void SGSoundMgr::release_buffer(SGSoundSample *sample)
if ( !sample->is_queue() ) if ( !sample->is_queue() )
{ {
std::string sample_name = sample->get_sample_name(); 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() ) { if ( buffer_it == d->_buffers.end() ) {
// buffer was not found // buffer was not found
return; return;
@@ -64,12 +64,7 @@ struct refUint {
}; };
typedef std::map < std::string, refUint > buffer_map; 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<SGSampleGroup> > sample_group_map; typedef std::map < std::string, SGSharedPtr<SGSampleGroup> > 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) { inline bool isNaN(float *v) {
return (SGMisc<float>::isNaN(v[0]) || SGMisc<float>::isNaN(v[1]) || SGMisc<float>::isNaN(v[2])); return (SGMisc<float>::isNaN(v[0]) || SGMisc<float>::isNaN(v[1]) || SGMisc<float>::isNaN(v[2]));
-6
View File
@@ -41,12 +41,6 @@ SGBinding::SGBinding(const SGPropertyNode* node, SGPropertyNode* root)
read(node, root); read(node, root);
} }
SGBinding::~SGBinding()
{
if(_arg && _arg->getParent())
_arg->getParent()->removeChild(_arg->getName(), _arg->getIndex());
}
void void
SGBinding::clear() SGBinding::clear()
{ {
+5 -4
View File
@@ -58,13 +58,14 @@ public:
/** /**
* Destructor. * Destructor.
*/ */
virtual ~SGBinding (); virtual ~SGBinding () = default;
/** /**
* clear internal state of the binding back to empty. This is useful * Clear internal state of the binding back to empty.
* if you don't want the 'remove on delete' behaviour of the *
* destructor. * This was particularly useful when SGBinding's destructor had its 'remove
* on delete' behaviour, however this is not the case anymore.
*/ */
void clear(); void clear();
+16
View File
@@ -29,6 +29,7 @@
#include <ctime> #include <ctime>
#include <cerrno> #include <cerrno>
#include <chrono>
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
# include <unistd.h> // for gettimeofday() and the _POSIX_TIMERS define # include <unistd.h> // for gettimeofday() and the _POSIX_TIMERS define
@@ -98,6 +99,21 @@ void SGTimeStamp::stamp()
#endif #endif
} }
void SGTimeStamp::systemClockHoursAndMinutes()
{
using namespace std;
using namespace std::chrono;
typedef duration<int, ratio_multiply<hours::period, ratio<24> >::type> days;
system_clock::time_point now = system_clock::now();
system_clock::duration tp = now.time_since_epoch();
tp -= duration_cast<days>(tp);
_sec = duration_cast<seconds>(tp).count();
_nsec = duration_cast<nanoseconds>(tp - seconds(_sec)).count();
}
// sleep based timing loop. // sleep based timing loop.
// //
// Calling sleep, even usleep() on linux is less accurate than // Calling sleep, even usleep() on linux is less accurate than
+7
View File
@@ -78,6 +78,13 @@ public:
/** Update stored time to current time (seconds and nanoseconds) */ /** Update stored time to current time (seconds and nanoseconds) */
void stamp(); 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 */ /** Set the time from a double value */
void setTime(const double& seconds) void setTime(const double& seconds)
{ {
+1 -1
View File
@@ -1 +1 @@
2017.4.0 2018.2.0