1
0
Fork 0

Expose character-aspect-ratio and do some clean up

- Fix stupid memory corruption bug
 - Fix bounding box calculations
 - Fix docs
 - Fix text size
 - Expose setting background color
 - Expose trigger for updating elements
 - Untie nodes if deleting according element
 - Allow deleting canvas, text and group elements
 - Allow creating groups as children of groups
This commit is contained in:
Thomas Geymayer 2012-05-20 19:14:00 +02:00
parent 17ec3278ed
commit 023021a879
14 changed files with 394 additions and 152 deletions

View file

@ -2,7 +2,7 @@ Canvas - A 2D Drawing API
=========================
Author: Thomas Geymayer <admin@tomprogs.at>
Revision: 2012/05/04
Revision: 2012/05/18
Introduction
------------
@ -22,11 +22,11 @@ Creating a canvas
A new canvas can be instantiated by creating a node /canvas/texture[<INDEX>]
with at least the following children:
<size-x type="int"> The width of the underlying texture
<size-y type="int"> The height of the underlying texture
<size n="0" type="int"> The width of the underlying texture
<size n="1" type="int"> The height of the underlying texture
<view-width type="int"> The width of the canvas
<view-height type="int"> The height of the canvas
<view n="0" type="int"> The width of the canvas
<view n="1" type="int"> The height of the canvas
The dimensions of the canvas are needed to be able to use textures with
different resolutions but use the same units for rendering to the canvas.
@ -60,6 +60,7 @@ only drawing Text is possible:
<red type="float">
<green type="float">
<blue type="float">
<alpha type="float">
</NAME>
* Text:
@ -71,7 +72,9 @@ only drawing Text is possible:
2. aircraft-dir
3. $FG_DATA/Fonts
4. Default osg font paths
<size type="float"> The font size (default: 32)
<character-size type="float"> The font size (default: 32)
<character-aspect-ratio type="float"> Ratio between character height and width
(default: 1)
<tf> A 3x3 transformation matrix specified by 6 values
(child elements <a>, ..., <f>) See
http://www.w3.org/TR/SVG/coords.html#TransformMatrixDefined
@ -129,17 +132,24 @@ Example
<canvas>
<texture>
<size-x type="int">384</size-x>
<size-y type="int">512</size-y>
<view-width type="int">768</view-width>
<view-height type="int">1024</view-height>
<size n="0" type="int">384</size-x>
<size n="1" type="int">512</size-y>
<view n="0" type="int">768</view-width>
<view n="1" type="int">1024</view-height>
<mipmapping type="bool">false</mipmapping>
<coverage-samples type="int">0</coverage-samples>
<color-samples type="int">0</color-samples>
<color-background>
<red type="float">0</red>
<green type="float">0.02</green>
<blue type="float">0</blue>
<alpha type="float">1</alpha>
</color-background>
<group>
<text>
<text type="string">TEST MESSAGE</text>
<font type="string">helvetica_bold.txf</font>
<character-size type="float">40</character-size>
<tf>
<!-- Translate (18|50) -->
<tx>18</tx>

View file

@ -6,6 +6,7 @@ set(SOURCES
elements/element.cxx
elements/group.cxx
elements/text.cxx
property_helper.cxx
)
set(HEADERS
@ -14,6 +15,7 @@ set(HEADERS
elements/element.hxx
elements/group.hxx
elements/text.hxx
property_helper.hxx
)
flightgear_component(Canvas "${SOURCES}" "${HEADERS}")

View file

@ -18,6 +18,7 @@
#include "canvas.hxx"
#include "elements/group.hxx"
#include <Canvas/property_helper.hxx>
#include <osg/Camera>
#include <osg/Geode>
@ -25,9 +26,6 @@
#include <iostream>
//#include <Main/globals.hxx>
//#include <Viewer/renderer.hxx>
//------------------------------------------------------------------------------
/**
* Callback used to disable/enable rendering to the texture if it is not
@ -97,8 +95,9 @@ Canvas::Canvas():
_view_width(-1),
_view_height(-1),
_status(0),
_node(0),
_sampling_dirty(false)
_sampling_dirty(false),
_color_dirty(true),
_node(0)
{
setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y);
@ -110,7 +109,10 @@ Canvas::Canvas():
//------------------------------------------------------------------------------
Canvas::~Canvas()
{
clearPlacements();
unbind();
_node = 0;
}
//------------------------------------------------------------------------------
@ -122,23 +124,21 @@ int Canvas::getStatus() const
//------------------------------------------------------------------------------
void Canvas::reset(SGPropertyNode* node)
{
if( _node )
{
_node->untie("size[0]");
_node->untie("size[1]");
_node->untie("view[0]");
_node->untie("view[1]");
_node->untie("status");
_node->untie("status-msg");
_node->removeChangeListener(this);
_node = 0;
}
if( node )
SG_LOG
(
SG_GL,
SG_INFO,
"Canvas::reset() texture[" << node->getIndex() << "]"
);
unbind();
_node = node;
setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y);
if( node )
if( _node )
{
_node = node;
_node->tie
(
"size[0]",
@ -174,6 +174,14 @@ void Canvas::reset(SGPropertyNode* node)
SGRawValueMethods<Canvas, const char*>(*this, &Canvas::getStatusMsg)
);
_node->addChangeListener(this);
canvas::linkColorNodes
(
"color-background",
_node,
_color_background,
osg::Vec4f(0,0,0,1)
);
}
}
@ -217,6 +225,17 @@ void Canvas::update(double delta_time_sec)
);
_sampling_dirty = false;
}
if( _color_dirty )
{
_texture.getCamera()->setClearColor
(
osg::Vec4( _color_background[0]->getFloatValue(),
_color_background[1]->getFloatValue(),
_color_background[2]->getFloatValue(),
_color_background[3]->getFloatValue() )
);
_color_dirty = false;
}
while( !_dirty_placements.empty() )
{
@ -345,8 +364,6 @@ void Canvas::childAdded( SGPropertyNode * parent,
{
_dirty_placements.push_back(child);
}
// else
// std::cout << "Canvas::childAdded: " << child->getPath() << std::endl;
}
//------------------------------------------------------------------------------
@ -358,15 +375,19 @@ void Canvas::childRemoved( SGPropertyNode * parent,
if( child->getNameString() == "placement" )
clearPlacements(child->getIndex());
else
std::cout << "Canvas::childRemoved: " << child->getPath() << std::endl;
}
//----------------------------------------------------------------------------
void Canvas::valueChanged(SGPropertyNode * node)
{
if( node->getParent()->getParent() == _node
&& node->getParent()->getNameString() == "placement" )
if( node->getParent()->getParent() == _node )
{
if( !_color_background.empty()
&& _color_background[0]->getParent() == node->getParent() )
{
_color_dirty = true;
}
else if( node->getParent()->getNameString() == "placement" )
{
// prevent double updates...
for( size_t i = 0; i < _dirty_placements.size(); ++i )
@ -377,6 +398,7 @@ void Canvas::valueChanged(SGPropertyNode * node)
_dirty_placements.push_back(node->getParent());
}
}
else if( node->getParent() == _node )
{
if( node->getNameString() == "mipmapping"
@ -428,3 +450,26 @@ void Canvas::clearPlacements(int index)
parent->removeChild(group);
}
}
//------------------------------------------------------------------------------
void Canvas::clearPlacements()
{
for(size_t i = 0; i < _placements.size(); ++i)
clearPlacements(i);
_placements.clear();
}
//------------------------------------------------------------------------------
void Canvas::unbind()
{
if( !_node )
return;
_node->untie("size[0]");
_node->untie("size[1]");
_node->untie("view[0]");
_node->untie("view[1]");
_node->untie("status");
_node->untie("status-msg");
_node->removeChangeListener(this);
}

View file

@ -73,6 +73,9 @@ class Canvas:
private:
Canvas(const Canvas&); // = delete;
Canvas& operator=(const Canvas&); // = delete;
int _size_x,
_size_y,
_view_width,
@ -81,10 +84,13 @@ class Canvas:
int _status;
std::string _status_msg;
FGODGauge _texture;
SGPropertyNode *_node;
bool _sampling_dirty,
_color_dirty;
bool _sampling_dirty;
FGODGauge _texture;
SGPropertyNode_ptr _node;
std::vector<SGPropertyNode_ptr> _color_background;
osg::ref_ptr<osg::NodeCallback> _camera_callback;
osg::ref_ptr<osg::NodeCallback> _cull_callback;
@ -96,6 +102,9 @@ class Canvas:
void setStatusFlags(unsigned int flags, bool set = true);
void clearPlacements(int index);
void clearPlacements();
void unbind();
};
#endif /* CANVAS_HXX_ */

View file

@ -73,7 +73,8 @@ void CanvasMgr::unbind()
void CanvasMgr::update(double delta_time_sec)
{
for( size_t i = 0; i < _canvases.size(); ++i )
_canvases[i].update(delta_time_sec);
if( _canvases[i] )
_canvases[i]->update(delta_time_sec);
}
//------------------------------------------------------------------------------
@ -85,8 +86,6 @@ void CanvasMgr::childAdded( SGPropertyNode * parent,
if( child->getNameString() == "texture" )
textureAdded(child);
else
std::cout << "CanvasMgr::childAdded: " << child->getPath() << std::endl;
}
//------------------------------------------------------------------------------
@ -96,7 +95,16 @@ void CanvasMgr::childRemoved( SGPropertyNode * parent,
if( parent != _props )
return;
std::cout << "CanvasMgr::childRemoved: " << child->getPath() << std::endl;
if( child->getNameString() == "texture" )
{
size_t index = child->getIndex();
if( index >= _canvases.size() )
SG_LOG(SG_GL, SG_WARN, "can't removed unknown texture[" << index << "]!");
else
// remove the canvas...
_canvases[index].reset();
}
}
//------------------------------------------------------------------------------
@ -108,17 +116,16 @@ void CanvasMgr::textureAdded(SGPropertyNode* node)
{
if( index > _canvases.size() )
SG_LOG(SG_GL, SG_WARN, "Skipping unused texture slot(s)!");
SG_LOG(SG_GL, SG_INFO, "Add new texture[" << index << "]");
_canvases.resize(index + 1);
_canvases[index];
}
else
{
SG_LOG(SG_GL, SG_WARN, "texture[" << index << "] already exists!");
}
_canvases[index].reset(node);
_canvases[index].reset( new Canvas() );
_canvases[index]->reset(node);
}
//------------------------------------------------------------------------------
@ -132,13 +139,3 @@ void CanvasMgr::triggerChangeRecursive(SGPropertyNode* node)
for( int i = 0; i < node->nChildren(); ++i )
triggerChangeRecursive( node->getChild(i) );
}
//------------------------------------------------------------------------------
template<class T>
T CanvasMgr::getParam(const SGPropertyNode* node, const char* prop)
{
const SGPropertyNode* child = node->getChild(prop);
if( !child )
throw std::runtime_error(std::string("Missing property ") + prop);
return getValue<T>(child);
}

View file

@ -26,6 +26,7 @@
#include <vector>
class Canvas;
typedef boost::shared_ptr<Canvas> CanvasPtr;
class CanvasMgr:
public SGSubsystem,
@ -55,7 +56,7 @@ class CanvasMgr:
SGPropertyNode_ptr _props;
/** The actual canvases */
std::vector<Canvas> _canvases;
std::vector<CanvasPtr> _canvases;
void textureAdded(SGPropertyNode* node);
@ -65,12 +66,6 @@ class CanvasMgr:
*/
void triggerChangeRecursive(SGPropertyNode* node);
/**
* Get the value of a property or throw an exception if it doesn't exist.
*/
template<class T>
T getParam(const SGPropertyNode* node, const char* prop);
};
#endif /* CANVAS_MGR_H_ */

View file

@ -17,10 +17,13 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "element.hxx"
#include <cassert>
#include <Canvas/property_helper.hxx>
#include <osg/Drawable>
#include <cassert>
#include <cstring>
namespace canvas
{
const std::string NAME_TRANSFORM = "tf";
@ -33,12 +36,6 @@ namespace canvas
}
//----------------------------------------------------------------------------
SGPropertyNode* Element::getPropertyNode()
{
return _node;
}
//----------------------------------------------------------------------------
void Element::update(double dt)
{
@ -97,7 +94,7 @@ namespace canvas
colorChanged( osg::Vec4( _color[0]->getFloatValue(),
_color[1]->getFloatValue(),
_color[2]->getFloatValue(),
1 ) );
_color[3]->getFloatValue() ) );
_attributes_dirty &= ~COLOR;
}
@ -106,18 +103,19 @@ namespace canvas
colorFillChanged( osg::Vec4( _color_fill[0]->getFloatValue(),
_color_fill[1]->getFloatValue(),
_color_fill[2]->getFloatValue(),
1 ) );
_color_fill[3]->getFloatValue() ) );
_attributes_dirty &= ~COLOR_FILL;
}
if( _drawable && (_attributes_dirty & BOUNDING_BOX) )
if( !_bounding_box.empty() )
{
_bounding_box[0]->setFloatValue(_drawable->getBound()._min.x());
_bounding_box[1]->setFloatValue(_drawable->getBound()._min.y());
_bounding_box[2]->setFloatValue(_drawable->getBound()._max.x());
_bounding_box[3]->setFloatValue(_drawable->getBound()._max.y());
assert( _drawable );
_attributes_dirty &= ~BOUNDING_BOX;
const osg::BoundingBox& bb = _drawable->getBound();
_bounding_box[0]->setFloatValue(bb._min.x());
_bounding_box[1]->setFloatValue(bb._min.y());
_bounding_box[2]->setFloatValue(bb._max.x());
_bounding_box[3]->setFloatValue(bb._max.y());
}
}
@ -128,29 +126,22 @@ namespace canvas
}
//----------------------------------------------------------------------------
Element::Element(SGPropertyNode* node, uint32_t attributes_used):
_node( node ),
_drawable( 0 ),
Element::Element(SGPropertyNode_ptr node, uint32_t attributes_used):
_attributes_used( attributes_used ),
_attributes_dirty( 0 ),
_attributes_dirty( attributes_used ),
_transform_dirty( false ),
_transform( new osg::MatrixTransform )
_transform( new osg::MatrixTransform ),
_node( node ),
_drawable( 0 )
{
assert( _node );
_node->addChangeListener(this);
if( _attributes_used & COLOR )
linkColorNodes("color", _color, osg::Vec4f(0,1,0,1));
linkColorNodes("color", _node, _color, osg::Vec4f(0,1,0,1));
if( _attributes_used & COLOR_FILL )
linkColorNodes("color-fill", _color_fill);
if( _attributes_used & BOUNDING_BOX )
{
SGPropertyNode* bb = _node->getChild("bounding-box", 0, true);
_bounding_box[0] = bb->getChild("x-min", 0, true);
_bounding_box[1] = bb->getChild("y-min", 0, true);
_bounding_box[2] = bb->getChild("x-max", 0, true);
_bounding_box[3] = bb->getChild("y-max", 0, true);
}
linkColorNodes("color-fill", _node, _color_fill);
SG_LOG
(
@ -161,22 +152,19 @@ namespace canvas
}
//----------------------------------------------------------------------------
void Element::linkColorNodes( const char* name,
SGPropertyNode** nodes,
const osg::Vec4& def )
void Element::setDrawable( osg::Drawable* drawable )
{
// Don't tie to allow the usage of aliases
SGPropertyNode* color = _node->getChild(name, 0, true);
_drawable = drawable;
assert( _drawable );
static const char* color_names[] = {"red", "green", "blue"};
for( size_t i = 0; i < sizeof(color_names)/sizeof(color_names[0]); ++i )
if( _attributes_used & BOUNDING_BOX )
{
color->setFloatValue
(
color_names[i],
color->getFloatValue(color_names[i], def[i])
);
nodes[i] = color->getChild(color_names[i]);
SGPropertyNode* bb_node = _node->getChild("bounding-box", 0, true);
_bounding_box.resize(4);
_bounding_box[0] = bb_node->getChild("min-x", 0, true);
_bounding_box[1] = bb_node->getChild("min-y", 0, true);
_bounding_box[2] = bb_node->getChild("max-x", 0, true);
_bounding_box[3] = bb_node->getChild("max-y", 0, true);
}
}
@ -254,13 +242,18 @@ namespace canvas
{
if( parent->getNameString() == NAME_TRANSFORM )
_transform_dirty = true;
else if( parent->getNameString() == NAME_COLOR )
else if( !_color.empty() && _color[0]->getParent() == parent )
_attributes_dirty |= COLOR;
else if( parent->getNameString() == NAME_COLOR_FILL )
else if( !_color_fill.empty() && _color_fill[0]->getParent() == parent )
_attributes_dirty |= COLOR_FILL;
}
else if( parent == _node )
{
if( child->getNameString() == "update" )
update(0);
else
childChanged(child);
}
}
} // namespace canvas

View file

@ -36,7 +36,6 @@ namespace canvas
{
public:
virtual ~Element() = 0;
SGPropertyNode* getPropertyNode();
/**
* Called every frame to update internal state
@ -53,7 +52,8 @@ namespace canvas
{
COLOR = 0x0001,
COLOR_FILL = 0x0002,
BOUNDING_BOX = 0x0004
BOUNDING_BOX = 0x0004,
LAST_ATTRIBUTE = BOUNDING_BOX
};
enum TransformType
@ -65,9 +65,6 @@ namespace canvas
TT_SCALE
};
SGPropertyNode *_node;
osg::Drawable *_drawable;
uint32_t _attributes_used;
uint32_t _attributes_dirty;
@ -75,11 +72,12 @@ namespace canvas
osg::ref_ptr<osg::MatrixTransform> _transform;
std::vector<TransformType> _transform_types;
SGPropertyNode *_bounding_box[4]; ///<! x-min, y-min, x-max, y-max
SGPropertyNode *_color[3];
SGPropertyNode *_color_fill[3];
SGPropertyNode_ptr _node;
std::vector<SGPropertyNode_ptr> _color,
_color_fill;
std::vector<SGPropertyNode_ptr> _bounding_box;
Element(SGPropertyNode* node, uint32_t attributes_used = 0);
Element(SGPropertyNode_ptr node, uint32_t attributes_used = 0);
virtual void childAdded(SGPropertyNode * child) {}
virtual void childRemoved(SGPropertyNode * child){}
@ -88,11 +86,12 @@ namespace canvas
virtual void colorChanged(const osg::Vec4& color) {}
virtual void colorFillChanged(const osg::Vec4& color){}
void linkColorNodes( const char* name,
SGPropertyNode** nodes,
const osg::Vec4& def = osg::Vec4(1,1,0,1) );
void setDrawable( osg::Drawable* drawable );
private:
osg::Drawable *_drawable;
Element(const Element&);// = delete
virtual void childAdded( SGPropertyNode * parent,

View file

@ -23,7 +23,7 @@ namespace canvas
{
//----------------------------------------------------------------------------
Group::Group(SGPropertyNode* node):
Group::Group(SGPropertyNode_ptr node):
Element(node)
{
@ -39,7 +39,10 @@ namespace canvas
void Group::update(double dt)
{
for( size_t i = 0; i < _children.size(); ++i )
{
if( _children[i] )
_children[i]->update(dt);
}
Element::update(dt);
}
@ -47,19 +50,58 @@ namespace canvas
//----------------------------------------------------------------------------
void Group::childAdded(SGPropertyNode* child)
{
boost::shared_ptr<Element> element;
if( child->getNameString() == "text" )
{
_children.push_back( boost::shared_ptr<Element>(new Text(child)) );
_transform->addChild( _children.back()->getMatrixTransform() );
}
element.reset( new Text(child) );
else if( child->getNameString() == "group" )
element.reset( new Group(child) );
else
std::cout << "New unknown child: " << child->getDisplayName() << std::endl;
SG_LOG
(
SG_GL,
SG_WARN,
"canvas::Group unknown child: " << child->getDisplayName()
);
if( !element )
return;
// Add to osg scene graph...
_transform->addChild( element->getMatrixTransform() );
// ...and build up canvas hierarchy
size_t index = child->getIndex();
if( index >= _children.size() )
_children.resize(index + 1);
_children[index] = element;
}
//----------------------------------------------------------------------------
void Group::childRemoved(SGPropertyNode* child)
{
if( child->getNameString() == "text"
|| child->getNameString() == "group" )
{
size_t index = child->getIndex();
if( index >= _children.size() )
SG_LOG
(
SG_GL,
SG_WARN,
"can't removed unknown child " << child->getDisplayName()
);
else
{
boost::shared_ptr<Element>& element = _children[index];
if( element )
_transform->removeChild(element->getMatrixTransform());
element.reset();
}
}
}
} // namespace canvas

View file

@ -26,17 +26,19 @@
namespace canvas
{
typedef boost::shared_ptr<Element> ElementPtr;
class Group:
public Element
{
public:
Group(SGPropertyNode* node);
Group(SGPropertyNode_ptr node);
virtual ~Group();
virtual void update(double dt);
protected:
std::vector<boost::shared_ptr<Element> > _children;
std::vector<ElementPtr> _children;
virtual void childAdded(SGPropertyNode * child);
virtual void childRemoved(SGPropertyNode * child);

View file

@ -17,26 +17,30 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "text.hxx"
#include <osgText/Text>
#include <Canvas/property_helper.hxx>
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include <osgText/Text>
namespace canvas
{
//----------------------------------------------------------------------------
Text::Text(SGPropertyNode* node):
Text::Text(SGPropertyNode_ptr node):
Element(node, COLOR | COLOR_FILL | BOUNDING_BOX),
_text( new osgText::Text )
_text( new osgText::Text ),
_font_size( 0 ),
_font_aspect( 0 )
{
_drawable = _text;
_text->setCharacterSizeMode(osgText::Text::SCREEN_COORDS);
setDrawable(_text);
_text->setCharacterSizeMode(osgText::Text::OBJECT_COORDS);
_text->setAxisAlignment(osgText::Text::USER_DEFINED_ROTATION);
_text->setRotation(osg::Quat(osg::PI, osg::X_AXIS));
// font size and property node
float character_size = _node->getFloatValue("size", 32);
_text->setCharacterSize( character_size );
_node->setFloatValue("size", character_size);
_font_size = getChildDefault<float>(_node, "character-size", 32);
_font_aspect = getChildDefault<float>(_node, "character-aspect-ratio", 1);
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
geode->addDrawable(_text);
@ -82,7 +86,30 @@ namespace canvas
//----------------------------------------------------------------------------
Text::~Text()
{
if( _node )
{
_node->untie("alignment");
_node->untie("padding");
_node->untie("draw-mode");
}
_node = 0;
}
//----------------------------------------------------------------------------
void Text::update(double dt)
{
Element::update(dt);
if( _attributes_dirty & FONT_SIZE )
{
_text->setCharacterSize
(
_font_size->getFloatValue(),
_font_aspect->getFloatValue()
);
_attributes_dirty &= ~FONT_SIZE;
}
}
//----------------------------------------------------------------------------
@ -123,16 +150,12 @@ namespace canvas
//----------------------------------------------------------------------------
void Text::childChanged(SGPropertyNode* child)
{
if( child->getNameString() == "text" )
if( _font_size == child || _font_aspect == child )
_attributes_dirty |= FONT_SIZE;
else if( child->getNameString() == "text" )
_text->setText( child->getStringValue() );
else if( child->getNameString() == "size" )
_text->setCharacterSize( child->getFloatValue() );
else if( child->getNameString() == "font" )
setFont( child->getStringValue() );
else
return;
_attributes_dirty |= BOUNDING_BOX;
}
//----------------------------------------------------------------------------

View file

@ -32,17 +32,28 @@ namespace canvas
public Element
{
public:
Text(SGPropertyNode* node);
Text(SGPropertyNode_ptr node);
virtual ~Text();
virtual void update(double dt);
void setFont(const char* name);
void setAlignment(const char* align);
const char* getAlignment() const;
protected:
enum TextAttributes
{
FONT_SIZE = LAST_ATTRIBUTE << 1, // Font size and aspect ration
};
osg::ref_ptr<osgText::Text> _text;
SGPropertyNode_ptr _font_size,
_font_aspect;
virtual void childChanged(SGPropertyNode * child);
virtual void colorChanged(const osg::Vec4& color);
virtual void colorFillChanged(const osg::Vec4& color);

View file

@ -0,0 +1,47 @@
// Some helper functions for accessing the property tree
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "property_helper.hxx"
#include <cassert>
namespace canvas
{
//----------------------------------------------------------------------------
void linkColorNodes( const char* name,
SGPropertyNode* parent,
std::vector<SGPropertyNode_ptr>& nodes,
const osg::Vec4& def )
{
static const char* channels[] = {"red", "green", "blue", "alpha"};
static const size_t num_channels = sizeof(channels)/sizeof(channels[0]);
assert(name);
assert(parent);
// Don't tie to allow the usage of aliases
SGPropertyNode_ptr color = parent->getChild(name, 0, true);
// We need to be carefull do not get any unitialized nodes or null pointers
// because while creating the node a valueChanged event will be triggered.
nodes.clear();
nodes.reserve(num_channels);
for( size_t i = 0; i < num_channels; ++i )
nodes.push_back( getChildDefault(color, channels[i], def[i]) );
}
}

View file

@ -0,0 +1,67 @@
// Some helper functions for accessing the property tree
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef PROPERTY_HELPER_HXX_
#define PROPERTY_HELPER_HXX_
#include <simgear/props/props.hxx>
#include <osg/Vec4>
namespace canvas
{
/**
* Get property node with default value
*/
template<typename T>
SGPropertyNode* getChildDefault( SGPropertyNode* parent,
const char* name,
T def_val )
{
SGPropertyNode* node = parent->getNode(name);
if( node )
// also set value for existing nodes to enforce type...
def_val = getValue<T>(node);
else
node = parent->getChild(name, 0, true);
setValue(node, def_val);
return node;
}
/**
* @param name Name of color node
* @param parent Parent for color channel nodes
* @param nodes Vector to push color nodes into
* @param def Default color
*
* <name>
* <red type="float">def[0] or existing value</red>
* <green type="float">def[1] or existing value</green>
* <blue type="float">def[2] or existing value</blue>
* <alpha type="float">def[3] or existing value</alpha>
* </name>
*/
void linkColorNodes( const char* name,
SGPropertyNode* parent,
std::vector<SGPropertyNode_ptr>& nodes,
const osg::Vec4& def = osg::Vec4(0,0,0,0) );
} // namespace canvas
#endif /* PROPERTY_HELPER_HXX_ */