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