Refactor Canvas and add some helpers.
- Refactor Canvas from FlightGear and fix lazy rendering with recursive canvases. - New classes PropertyBasedElement and PropertyBasedManager for creating subsystems controlled by the property tree. - New method parseColor to parse CSS 3 conformant color strings (only basic color schemes supported) - New Rect class representing a rectangle.
This commit is contained in:
@@ -1,14 +1,25 @@
|
||||
include (SimGearComponent)
|
||||
|
||||
set(HEADERS
|
||||
ODGauge.hxx
|
||||
VGInitOperation.hxx
|
||||
)
|
||||
canvas_fwd.hxx
|
||||
Canvas.hxx
|
||||
CanvasMgr.hxx
|
||||
CanvasPlacement.hxx
|
||||
CanvasSystemAdapter.hxx
|
||||
MouseEvent.hxx
|
||||
ODGauge.hxx
|
||||
VGInitOperation.hxx
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
ODGauge.cxx
|
||||
)
|
||||
Canvas.cxx
|
||||
CanvasMgr.cxx
|
||||
CanvasPlacement.cxx
|
||||
ODGauge.cxx
|
||||
)
|
||||
|
||||
add_subdirectory(ShivaVG/src)
|
||||
include_directories(ShivaVG/include)
|
||||
|
||||
add_subdirectory(elements)
|
||||
simgear_scene_component(canvas canvas "${SOURCES}" "${HEADERS}")
|
||||
|
||||
502
simgear/canvas/Canvas.cxx
Normal file
502
simgear/canvas/Canvas.cxx
Normal file
@@ -0,0 +1,502 @@
|
||||
// The canvas for rendering with the 2d API
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "Canvas.hxx"
|
||||
#include <simgear/canvas/MouseEvent.hxx>
|
||||
#include <simgear/misc/parse_color.hxx>
|
||||
#include <simgear/scene/util/RenderConstants.hxx>
|
||||
|
||||
#include <osg/Camera>
|
||||
#include <osg/Geode>
|
||||
#include <osgText/Text>
|
||||
#include <osgViewer/Viewer>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <iostream>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Canvas::CullCallback::CullCallback(const CanvasWeakPtr& canvas):
|
||||
_canvas( canvas )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::CullCallback::operator()( osg::Node* node,
|
||||
osg::NodeVisitor* nv )
|
||||
{
|
||||
if( (nv->getTraversalMask() & simgear::MODEL_BIT) && !_canvas.expired() )
|
||||
_canvas.lock()->enableRendering();
|
||||
|
||||
traverse(node, nv);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Canvas::Canvas(SGPropertyNode* node):
|
||||
PropertyBasedElement(node),
|
||||
_canvas_mgr(0),
|
||||
_size_x(-1),
|
||||
_size_y(-1),
|
||||
_view_width(-1),
|
||||
_view_height(-1),
|
||||
_status(node, "status"),
|
||||
_status_msg(node, "status-msg"),
|
||||
_mouse_x(node, "mouse/x"),
|
||||
_mouse_y(node, "mouse/y"),
|
||||
_mouse_dx(node, "mouse/dx"),
|
||||
_mouse_dy(node, "mouse/dy"),
|
||||
_mouse_button(node, "mouse/button"),
|
||||
_mouse_state(node, "mouse/state"),
|
||||
_mouse_mod(node, "mouse/mod"),
|
||||
_mouse_scroll(node, "mouse/scroll"),
|
||||
_mouse_event(node, "mouse/event"),
|
||||
_sampling_dirty(false),
|
||||
_render_dirty(true),
|
||||
_visible(true),
|
||||
_render_always(false)
|
||||
{
|
||||
_status = 0;
|
||||
setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Canvas::~Canvas()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::setSystemAdapter(const SystemAdapterPtr& system_adapter)
|
||||
{
|
||||
_system_adapter = system_adapter;
|
||||
_texture.setSystemAdapter(system_adapter);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
SystemAdapterPtr Canvas::getSystemAdapter() const
|
||||
{
|
||||
return _system_adapter;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::setCanvasMgr(CanvasMgr* canvas_mgr)
|
||||
{
|
||||
_canvas_mgr = canvas_mgr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
CanvasMgr* Canvas::getCanvasMgr() const
|
||||
{
|
||||
return _canvas_mgr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::addDependentCanvas(const CanvasWeakPtr& canvas)
|
||||
{
|
||||
if( canvas.expired() )
|
||||
{
|
||||
SG_LOG
|
||||
(
|
||||
SG_GENERAL,
|
||||
SG_WARN,
|
||||
"Canvas::addDependentCanvas: got an expired Canvas dependent on "
|
||||
<< _node->getPath()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
_dependent_canvases.insert(canvas);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::removeDependentCanvas(const CanvasWeakPtr& canvas)
|
||||
{
|
||||
_dependent_canvases.erase(canvas);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::enableRendering(bool force)
|
||||
{
|
||||
_visible = true;
|
||||
if( force )
|
||||
_render_dirty = true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::update(double delta_time_sec)
|
||||
{
|
||||
if( !_texture.serviceable() )
|
||||
{
|
||||
if( _status != STATUS_OK )
|
||||
return;
|
||||
|
||||
_texture.setSize(_size_x, _size_y);
|
||||
_texture.useImageCoords(true);
|
||||
_texture.useStencil(true);
|
||||
_texture.allocRT(/*_camera_callback*/);
|
||||
|
||||
osg::Camera* camera = _texture.getCamera();
|
||||
|
||||
osg::Vec4 clear_color(0.0f, 0.0f, 0.0f , 1.0f);
|
||||
parseColor(_node->getStringValue("background"), clear_color);
|
||||
camera->setClearColor(clear_color);
|
||||
|
||||
camera->addChild(_root_group->getMatrixTransform());
|
||||
|
||||
// Ensure objects are drawn in order of traversal
|
||||
camera->getOrCreateStateSet()->setBinName("TraversalOrderBin");
|
||||
|
||||
if( _texture.serviceable() )
|
||||
{
|
||||
setStatusFlags(STATUS_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
setStatusFlags(CREATE_FAILED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if( _visible || _render_always )
|
||||
{
|
||||
if( _render_dirty )
|
||||
{
|
||||
// Also mark all dependent (eg. recursively used) canvases as dirty
|
||||
BOOST_FOREACH(CanvasWeakPtr canvas, _dependent_canvases)
|
||||
{
|
||||
if( !canvas.expired() )
|
||||
canvas.lock()->_render_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
_texture.setRender(_render_dirty);
|
||||
|
||||
_render_dirty = false;
|
||||
_visible = false;
|
||||
}
|
||||
else
|
||||
_texture.setRender(false);
|
||||
|
||||
_root_group->update(delta_time_sec);
|
||||
|
||||
if( _sampling_dirty )
|
||||
{
|
||||
_texture.setSampling(
|
||||
_node->getBoolValue("mipmapping"),
|
||||
_node->getIntValue("coverage-samples"),
|
||||
_node->getIntValue("color-samples")
|
||||
);
|
||||
_sampling_dirty = false;
|
||||
_render_dirty = true;
|
||||
}
|
||||
|
||||
while( !_dirty_placements.empty() )
|
||||
{
|
||||
SGPropertyNode *node = _dirty_placements.back();
|
||||
_dirty_placements.pop_back();
|
||||
|
||||
if( node->getIndex() >= static_cast<int>(_placements.size()) )
|
||||
// New placement
|
||||
_placements.resize(node->getIndex() + 1);
|
||||
else
|
||||
// Remove possibly existing placements
|
||||
_placements[ node->getIndex() ].clear();
|
||||
|
||||
// Get new placements
|
||||
PlacementFactoryMap::const_iterator placement_factory =
|
||||
_placement_factories.find( node->getStringValue("type", "object") );
|
||||
if( placement_factory != _placement_factories.end() )
|
||||
{
|
||||
Placements& placements = _placements[ node->getIndex() ] =
|
||||
placement_factory->second
|
||||
(
|
||||
node,
|
||||
boost::static_pointer_cast<Canvas>(_self.lock())
|
||||
);
|
||||
node->setStringValue
|
||||
(
|
||||
"status-msg",
|
||||
placements.empty() ? "No match" : "Ok"
|
||||
);
|
||||
}
|
||||
else
|
||||
node->setStringValue("status-msg", "Unknown placement type");
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::setSizeX(int sx)
|
||||
{
|
||||
if( _size_x == sx )
|
||||
return;
|
||||
_size_x = sx;
|
||||
|
||||
// TODO resize if texture already allocated
|
||||
|
||||
if( _size_x <= 0 )
|
||||
setStatusFlags(MISSING_SIZE_X);
|
||||
else
|
||||
setStatusFlags(MISSING_SIZE_X, false);
|
||||
|
||||
// reset flag to allow creation with new size
|
||||
setStatusFlags(CREATE_FAILED, false);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::setSizeY(int sy)
|
||||
{
|
||||
if( _size_y == sy )
|
||||
return;
|
||||
_size_y = sy;
|
||||
|
||||
// TODO resize if texture already allocated
|
||||
|
||||
if( _size_y <= 0 )
|
||||
setStatusFlags(MISSING_SIZE_Y);
|
||||
else
|
||||
setStatusFlags(MISSING_SIZE_Y, false);
|
||||
|
||||
// reset flag to allow creation with new size
|
||||
setStatusFlags(CREATE_FAILED, false);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int Canvas::getSizeX() const
|
||||
{
|
||||
return _size_x;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int Canvas::getSizeY() const
|
||||
{
|
||||
return _size_y;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::setViewWidth(int w)
|
||||
{
|
||||
if( _view_width == w )
|
||||
return;
|
||||
_view_width = w;
|
||||
|
||||
_texture.setViewSize(_view_width, _view_height);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::setViewHeight(int h)
|
||||
{
|
||||
if( _view_height == h )
|
||||
return;
|
||||
_view_height = h;
|
||||
|
||||
_texture.setViewSize(_view_width, _view_height);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Canvas::handleMouseEvent(const MouseEvent& event)
|
||||
{
|
||||
_mouse_x = event.x;
|
||||
_mouse_y = event.y;
|
||||
_mouse_dx = event.dx;
|
||||
_mouse_dy = event.dy;
|
||||
_mouse_button = event.button;
|
||||
_mouse_state = event.state;
|
||||
_mouse_mod = event.mod;
|
||||
_mouse_scroll = event.scroll;
|
||||
// Always set event type last because all listeners are attached to it
|
||||
_mouse_event = event.type;
|
||||
|
||||
if( _root_group.get() )
|
||||
return _root_group->handleMouseEvent(event);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::childAdded( SGPropertyNode * parent,
|
||||
SGPropertyNode * child )
|
||||
{
|
||||
if( parent != _node )
|
||||
return;
|
||||
|
||||
if( child->getNameString() == "placement" )
|
||||
_dirty_placements.push_back(child);
|
||||
else if( _root_group.get() )
|
||||
static_cast<Element*>(_root_group.get())->childAdded(parent, child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::childRemoved( SGPropertyNode * parent,
|
||||
SGPropertyNode * child )
|
||||
{
|
||||
_render_dirty = true;
|
||||
|
||||
if( parent != _node )
|
||||
return;
|
||||
|
||||
if( child->getNameString() == "placement" )
|
||||
_placements[ child->getIndex() ].clear();
|
||||
else if( _root_group.get() )
|
||||
static_cast<Element*>(_root_group.get())->childRemoved(parent, child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::valueChanged(SGPropertyNode* node)
|
||||
{
|
||||
if( boost::starts_with(node->getNameString(), "status")
|
||||
|| node->getParent()->getNameString() == "bounding-box" )
|
||||
return;
|
||||
_render_dirty = true;
|
||||
|
||||
bool handled = true;
|
||||
if( node->getParent()->getParent() == _node
|
||||
&& node->getParent()->getNameString() == "placement" )
|
||||
{
|
||||
// prevent double updates...
|
||||
for( size_t i = 0; i < _dirty_placements.size(); ++i )
|
||||
{
|
||||
if( node->getParent() == _dirty_placements[i] )
|
||||
return;
|
||||
}
|
||||
|
||||
_dirty_placements.push_back(node->getParent());
|
||||
}
|
||||
else if( node->getParent() == _node )
|
||||
{
|
||||
if( node->getNameString() == "background" )
|
||||
{
|
||||
osg::Vec4 color;
|
||||
if( _texture.getCamera() && parseColor(node->getStringValue(), color) )
|
||||
{
|
||||
_texture.getCamera()->setClearColor(color);
|
||||
_render_dirty = true;
|
||||
}
|
||||
}
|
||||
else if( node->getNameString() == "mipmapping"
|
||||
|| node->getNameString() == "coverage-samples"
|
||||
|| node->getNameString() == "color-samples" )
|
||||
{
|
||||
_sampling_dirty = true;
|
||||
}
|
||||
else if( node->getNameString() == "render-always" )
|
||||
{
|
||||
_render_always = node->getBoolValue();
|
||||
}
|
||||
else if( node->getNameString() == "size" )
|
||||
{
|
||||
if( node->getIndex() == 0 )
|
||||
setSizeX( node->getIntValue() );
|
||||
else if( node->getIndex() == 1 )
|
||||
setSizeY( node->getIntValue() );
|
||||
}
|
||||
else if( node->getNameString() == "view" )
|
||||
{
|
||||
if( node->getIndex() == 0 )
|
||||
setViewWidth( node->getIntValue() );
|
||||
else if( node->getIndex() == 1 )
|
||||
setViewHeight( node->getIntValue() );
|
||||
}
|
||||
else if( node->getNameString() == "freeze" )
|
||||
_texture.setRender( node->getBoolValue() );
|
||||
else
|
||||
handled = false;
|
||||
}
|
||||
else
|
||||
handled = false;
|
||||
|
||||
if( !handled && _root_group.get() )
|
||||
_root_group->valueChanged(node);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::Texture2D* Canvas::getTexture() const
|
||||
{
|
||||
return _texture.getTexture();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Canvas::CullCallbackPtr Canvas::getCullCallback() const
|
||||
{
|
||||
return _cull_callback;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::addPlacementFactory( const std::string& type,
|
||||
PlacementFactory factory )
|
||||
{
|
||||
if( _placement_factories.find(type) != _placement_factories.end() )
|
||||
SG_LOG
|
||||
(
|
||||
SG_GENERAL,
|
||||
SG_WARN,
|
||||
"Canvas::addPlacementFactory: replace existing factor for type " << type
|
||||
);
|
||||
|
||||
_placement_factories[type] = factory;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::setSelf(const PropertyBasedElementPtr& self)
|
||||
{
|
||||
PropertyBasedElement::setSelf(self);
|
||||
|
||||
CanvasPtr canvas = boost::static_pointer_cast<Canvas>(self);
|
||||
|
||||
_root_group.reset( new Group(canvas, _node) );
|
||||
|
||||
// Remove automatically created property listener as we forward them on our
|
||||
// own
|
||||
_root_group->removeListener();
|
||||
|
||||
_cull_callback = new CullCallback(canvas);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::setStatusFlags(unsigned int flags, bool set)
|
||||
{
|
||||
if( set )
|
||||
_status = _status | flags;
|
||||
else
|
||||
_status = _status & ~flags;
|
||||
// TODO maybe extend simgear::PropertyObject to allow |=, &= etc.
|
||||
|
||||
if( (_status & MISSING_SIZE_X) && (_status & MISSING_SIZE_Y) )
|
||||
_status_msg = "Missing size";
|
||||
else if( _status & MISSING_SIZE_X )
|
||||
_status_msg = "Missing size-x";
|
||||
else if( _status & MISSING_SIZE_Y )
|
||||
_status_msg = "Missing size-y";
|
||||
else if( _status & CREATE_FAILED )
|
||||
_status_msg = "Creating render target failed";
|
||||
else if( _status == STATUS_OK && !_texture.serviceable() )
|
||||
_status_msg = "Creation pending...";
|
||||
else
|
||||
_status_msg = "Ok";
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Canvas::PlacementFactoryMap Canvas::_placement_factories;
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
180
simgear/canvas/Canvas.hxx
Normal file
180
simgear/canvas/Canvas.hxx
Normal file
@@ -0,0 +1,180 @@
|
||||
// The canvas for rendering with the 2d API
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef CANVAS_HXX_
|
||||
#define CANVAS_HXX_
|
||||
|
||||
#include "canvas_fwd.hxx"
|
||||
#include "ODGauge.hxx"
|
||||
|
||||
#include <simgear/canvas/elements/CanvasGroup.hxx>
|
||||
#include <simgear/props/PropertyBasedElement.hxx>
|
||||
#include <simgear/props/propertyObject.hxx>
|
||||
#include <osg/NodeCallback>
|
||||
#include <osg/observer_ptr>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
class CanvasMgr;
|
||||
class MouseEvent;
|
||||
|
||||
class Canvas:
|
||||
public PropertyBasedElement
|
||||
{
|
||||
public:
|
||||
|
||||
enum StatusFlags
|
||||
{
|
||||
STATUS_OK,
|
||||
MISSING_SIZE_X = 0x0001,
|
||||
MISSING_SIZE_Y = 0x0002,
|
||||
CREATE_FAILED = 0x0004
|
||||
};
|
||||
|
||||
/**
|
||||
* This callback is installed on every placement of the canvas in the
|
||||
* scene to only render the canvas if at least one placement is visible
|
||||
*/
|
||||
class CullCallback:
|
||||
public osg::NodeCallback
|
||||
{
|
||||
public:
|
||||
CullCallback(const CanvasWeakPtr& canvas);
|
||||
|
||||
private:
|
||||
CanvasWeakPtr _canvas;
|
||||
|
||||
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
|
||||
};
|
||||
typedef osg::ref_ptr<CullCallback> CullCallbackPtr;
|
||||
|
||||
Canvas(SGPropertyNode* node);
|
||||
virtual ~Canvas();
|
||||
|
||||
void setSystemAdapter(const SystemAdapterPtr& system_adapter);
|
||||
SystemAdapterPtr getSystemAdapter() const;
|
||||
|
||||
void setCanvasMgr(CanvasMgr* canvas_mgr);
|
||||
CanvasMgr* getCanvasMgr() const;
|
||||
|
||||
/**
|
||||
* Add a canvas which should be mared as dirty upon any change to this
|
||||
* canvas.
|
||||
*
|
||||
* This mechanism is used to eg. redraw a canvas if it's displaying
|
||||
* another canvas (recursive canvases)
|
||||
*/
|
||||
void addDependentCanvas(const CanvasWeakPtr& canvas);
|
||||
|
||||
/**
|
||||
* Stop notifying the given canvas upon changes
|
||||
*/
|
||||
void removeDependentCanvas(const CanvasWeakPtr& canvas);
|
||||
|
||||
/**
|
||||
* Enable rendering for the next frame
|
||||
*
|
||||
* @param force Force redraw even if nothing has changed (if dirty flag
|
||||
* is not set)
|
||||
*/
|
||||
void enableRendering(bool force = false);
|
||||
|
||||
void update(double delta_time_sec);
|
||||
|
||||
void setSizeX(int sx);
|
||||
void setSizeY(int sy);
|
||||
|
||||
int getSizeX() const;
|
||||
int getSizeY() const;
|
||||
|
||||
void setViewWidth(int w);
|
||||
void setViewHeight(int h);
|
||||
|
||||
bool handleMouseEvent(const MouseEvent& event);
|
||||
|
||||
virtual void childAdded( SGPropertyNode * parent,
|
||||
SGPropertyNode * child );
|
||||
virtual void childRemoved( SGPropertyNode * parent,
|
||||
SGPropertyNode * child );
|
||||
virtual void valueChanged (SGPropertyNode * node);
|
||||
|
||||
osg::Texture2D* getTexture() const;
|
||||
|
||||
CullCallbackPtr getCullCallback() const;
|
||||
|
||||
static void addPlacementFactory( const std::string& type,
|
||||
PlacementFactory factory );
|
||||
|
||||
protected:
|
||||
|
||||
SystemAdapterPtr _system_adapter;
|
||||
CanvasMgr *_canvas_mgr;
|
||||
|
||||
int _size_x,
|
||||
_size_y,
|
||||
_view_width,
|
||||
_view_height;
|
||||
|
||||
PropertyObject<int> _status;
|
||||
PropertyObject<std::string> _status_msg;
|
||||
|
||||
PropertyObject<int> _mouse_x, _mouse_y,
|
||||
_mouse_dx, _mouse_dy,
|
||||
_mouse_button,
|
||||
_mouse_state,
|
||||
_mouse_mod,
|
||||
_mouse_scroll,
|
||||
_mouse_event;
|
||||
|
||||
bool _sampling_dirty,
|
||||
_render_dirty,
|
||||
_visible;
|
||||
|
||||
ODGauge _texture;
|
||||
std::auto_ptr<Group> _root_group;
|
||||
|
||||
CullCallbackPtr _cull_callback;
|
||||
bool _render_always; //<! Used to disable automatic lazy rendering (culling)
|
||||
|
||||
std::vector<SGPropertyNode*> _dirty_placements;
|
||||
std::vector<canvas::Placements> _placements;
|
||||
std::set<CanvasWeakPtr> _dependent_canvases; //<! Canvases which use this
|
||||
// canvas and should be
|
||||
// notified about changes
|
||||
|
||||
typedef std::map<std::string, canvas::PlacementFactory> PlacementFactoryMap;
|
||||
static PlacementFactoryMap _placement_factories;
|
||||
|
||||
virtual void setSelf(const PropertyBasedElementPtr& self);
|
||||
void setStatusFlags(unsigned int flags, bool set = true);
|
||||
|
||||
private:
|
||||
|
||||
Canvas(const Canvas&); // = delete;
|
||||
Canvas& operator=(const Canvas&); // = delete;
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* CANVAS_HXX_ */
|
||||
65
simgear/canvas/CanvasMgr.cxx
Normal file
65
simgear/canvas/CanvasMgr.cxx
Normal file
@@ -0,0 +1,65 @@
|
||||
// Canvas with 2D rendering API
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "CanvasMgr.hxx"
|
||||
#include "Canvas.hxx"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
/**
|
||||
* Canvas factory
|
||||
*/
|
||||
CanvasPtr canvasFactory(SGPropertyNode* node)
|
||||
{
|
||||
return CanvasPtr(new Canvas(node));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
CanvasMgr::CanvasMgr( SGPropertyNode_ptr node,
|
||||
SystemAdapterPtr system_adapter ):
|
||||
PropertyBasedMgr(node, "texture", &canvasFactory),
|
||||
_system_adapter(system_adapter)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
CanvasPtr CanvasMgr::getCanvas(size_t index) const
|
||||
{
|
||||
if( index >= _elements.size()
|
||||
|| !_elements[index] )
|
||||
return CanvasPtr();
|
||||
|
||||
return boost::static_pointer_cast<Canvas>(_elements[index]);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void CanvasMgr::elementCreated(PropertyBasedElementPtr element)
|
||||
{
|
||||
CanvasPtr canvas = boost::static_pointer_cast<Canvas>(element);
|
||||
canvas->setSystemAdapter(_system_adapter);
|
||||
canvas->setCanvasMgr(this);
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
61
simgear/canvas/CanvasMgr.hxx
Normal file
61
simgear/canvas/CanvasMgr.hxx
Normal file
@@ -0,0 +1,61 @@
|
||||
// Canvas with 2D rendering API
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef SG_CANVAS_MGR_H_
|
||||
#define SG_CANVAS_MGR_H_
|
||||
|
||||
#include "canvas_fwd.hxx"
|
||||
#include <simgear/props/PropertyBasedMgr.hxx>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
class CanvasMgr:
|
||||
public PropertyBasedMgr
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @param node Root node of branch used to control canvasses
|
||||
* @param system_adapter Adapter for connecting between canvas and
|
||||
* application framework
|
||||
*
|
||||
*/
|
||||
CanvasMgr( SGPropertyNode_ptr node,
|
||||
SystemAdapterPtr system_adapter );
|
||||
|
||||
/**
|
||||
* Get ::Canvas by index
|
||||
*
|
||||
* @param index Index of texture node in /canvas/by-index/
|
||||
*/
|
||||
CanvasPtr getCanvas(size_t index) const;
|
||||
|
||||
protected:
|
||||
|
||||
SystemAdapterPtr _system_adapter;
|
||||
|
||||
virtual void elementCreated(PropertyBasedElementPtr element);
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* SG_CANVAS_MGR_H_ */
|
||||
39
simgear/canvas/CanvasPlacement.cxx
Normal file
39
simgear/canvas/CanvasPlacement.cxx
Normal file
@@ -0,0 +1,39 @@
|
||||
// Base class for canvas placements
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "CanvasPlacement.hxx"
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Placement::Placement()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Placement::~Placement()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
41
simgear/canvas/CanvasPlacement.hxx
Normal file
41
simgear/canvas/CanvasPlacement.hxx
Normal file
@@ -0,0 +1,41 @@
|
||||
// Base class for canvas placements
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef CANVAS_PLACEMENT_HXX_
|
||||
#define CANVAS_PLACEMENT_HXX_
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
class Placement
|
||||
{
|
||||
public:
|
||||
Placement();
|
||||
virtual ~Placement() = 0;
|
||||
|
||||
private:
|
||||
Placement(const Placement&) /* = delete */;
|
||||
Placement& operator=(const Placement&) /* = delete */;
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* CANVAS_PLACEMENT_HXX_ */
|
||||
43
simgear/canvas/CanvasSystemAdapter.hxx
Normal file
43
simgear/canvas/CanvasSystemAdapter.hxx
Normal file
@@ -0,0 +1,43 @@
|
||||
// Adapter for using the canvas with different applications
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef SG_CANVAS_SYSTEM_ADAPTER_HXX_
|
||||
#define SG_CANVAS_SYSTEM_ADAPTER_HXX_
|
||||
|
||||
#include "canvas_fwd.hxx"
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
class SystemAdapter
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~SystemAdapter() {}
|
||||
virtual FontPtr getFont(const std::string& name) const = 0;
|
||||
virtual void addCamera(osg::Camera* camera) const = 0;
|
||||
virtual void removeCamera(osg::Camera* camera) const = 0;
|
||||
virtual osg::Image* getImage(const std::string& path) const = 0;
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* SG_CANVAS_SYSTEM_ADAPTER_HXX_ */
|
||||
60
simgear/canvas/MouseEvent.hxx
Normal file
60
simgear/canvas/MouseEvent.hxx
Normal file
@@ -0,0 +1,60 @@
|
||||
// Mouse event
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef CANVAS_MOUSE_EVENT_HXX_
|
||||
#define CANVAS_MOUSE_EVENT_HXX_
|
||||
|
||||
#include <osgGA/GUIEventAdapter>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
class MouseEvent
|
||||
{
|
||||
public:
|
||||
typedef osgGA::GUIEventAdapter::EventType EventType;
|
||||
typedef osgGA::GUIEventAdapter::ScrollingMotion Scroll;
|
||||
|
||||
MouseEvent(EventType type):
|
||||
type(type),
|
||||
x(-1), y(-1),
|
||||
dx(0), dy(0),
|
||||
button(-1),
|
||||
state(-1),
|
||||
mod(-1),
|
||||
scroll(osgGA::GUIEventAdapter::SCROLL_NONE)
|
||||
{}
|
||||
|
||||
osg::Vec2f getPos() const { return osg::Vec2f(x, y); }
|
||||
osg::Vec3f getPos3() const { return osg::Vec3f(x, y, 0); }
|
||||
|
||||
EventType type;
|
||||
float x, y,
|
||||
dx, dy;
|
||||
int button, //<! Button for this event
|
||||
state, //<! Current button state
|
||||
mod; //<! Keyboard modifier state
|
||||
Scroll scroll;
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* CANVAS_MOUSE_EVENT_HXX_ */
|
||||
@@ -10,26 +10,30 @@
|
||||
// Supports now multisampling/mipmapping, usage of the stencil buffer and placing
|
||||
// the texture in the scene by certain filter criteria
|
||||
//
|
||||
// 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 library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library 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
|
||||
// This library 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.
|
||||
//
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include "ODGauge.hxx"
|
||||
#include "CanvasSystemAdapter.hxx"
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/scene/util/RenderConstants.hxx>
|
||||
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/AlphaFunc>
|
||||
#include <osg/BlendFunc>
|
||||
@@ -40,237 +44,243 @@
|
||||
#include <osg/StateSet>
|
||||
#include <osg/FrameBufferObject> // for GL_DEPTH_STENCIL_EXT on Windows
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/scene/util/RenderConstants.hxx>
|
||||
#include "ODGauge.hxx"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ODGauge::ODGauge( const CameraRegistrationCallback& cb_camera_add,
|
||||
const CameraRegistrationCallback& cb_camera_remove ):
|
||||
_size_x( -1 ),
|
||||
_size_y( -1 ),
|
||||
_view_width( -1 ),
|
||||
_view_height( -1 ),
|
||||
_use_image_coords( false ),
|
||||
_use_stencil( false ),
|
||||
_use_mipmapping( false ),
|
||||
_coverage_samples( 0 ),
|
||||
_color_samples( 0 ),
|
||||
rtAvailable( false ),
|
||||
_cb_cam_add( cb_camera_add ),
|
||||
_cb_cam_remove( cb_camera_remove )
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
ODGauge::ODGauge():
|
||||
_size_x( -1 ),
|
||||
_size_y( -1 ),
|
||||
_view_width( -1 ),
|
||||
_view_height( -1 ),
|
||||
_use_image_coords( false ),
|
||||
_use_stencil( false ),
|
||||
_use_mipmapping( false ),
|
||||
_coverage_samples( 0 ),
|
||||
_color_samples( 0 ),
|
||||
rtAvailable( false )
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ODGauge::~ODGauge()
|
||||
{
|
||||
if( camera.valid() )
|
||||
_cb_cam_remove(camera.get());
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void ODGauge::setSize(int size_x, int size_y)
|
||||
{
|
||||
_size_x = size_x;
|
||||
_size_y = size_y < 0 ? size_x : size_y;
|
||||
//----------------------------------------------------------------------------
|
||||
ODGauge::~ODGauge()
|
||||
{
|
||||
if( camera.valid() && _system_adapter )
|
||||
_system_adapter->removeCamera(camera.get());
|
||||
}
|
||||
|
||||
if( texture.valid() )
|
||||
texture->setTextureSize(_size_x, _size_x);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void ODGauge::setSystemAdapter(const SystemAdapterPtr& system_adapter)
|
||||
{
|
||||
_system_adapter = system_adapter;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void ODGauge::setViewSize(int width, int height)
|
||||
{
|
||||
_view_width = width;
|
||||
_view_height = height < 0 ? width : height;
|
||||
//----------------------------------------------------------------------------
|
||||
void ODGauge::setSize(int size_x, int size_y)
|
||||
{
|
||||
_size_x = size_x;
|
||||
_size_y = size_y < 0 ? size_x : size_y;
|
||||
|
||||
if( camera )
|
||||
if( texture.valid() )
|
||||
texture->setTextureSize(_size_x, _size_x);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void ODGauge::setViewSize(int width, int height)
|
||||
{
|
||||
_view_width = width;
|
||||
_view_height = height < 0 ? width : height;
|
||||
|
||||
if( camera )
|
||||
updateCoordinateFrame();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void ODGauge::useImageCoords(bool use)
|
||||
{
|
||||
if( use == _use_image_coords )
|
||||
return;
|
||||
|
||||
_use_image_coords = use;
|
||||
|
||||
if( texture )
|
||||
updateCoordinateFrame();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void ODGauge::useStencil(bool use)
|
||||
{
|
||||
if( use == _use_stencil )
|
||||
return;
|
||||
|
||||
_use_stencil = use;
|
||||
|
||||
if( texture )
|
||||
updateStencil();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void ODGauge::setSampling( bool mipmapping,
|
||||
int coverage_samples,
|
||||
int color_samples )
|
||||
{
|
||||
if( _use_mipmapping == mipmapping
|
||||
&& _coverage_samples == coverage_samples
|
||||
&& _color_samples == color_samples )
|
||||
return;
|
||||
|
||||
_use_mipmapping = mipmapping;
|
||||
|
||||
if( color_samples > coverage_samples )
|
||||
{
|
||||
SG_LOG
|
||||
(
|
||||
SG_GL,
|
||||
SG_WARN,
|
||||
"ODGauge::setSampling: color_samples > coverage_samples not allowed!"
|
||||
);
|
||||
color_samples = coverage_samples;
|
||||
}
|
||||
|
||||
_coverage_samples = coverage_samples;
|
||||
_color_samples = color_samples;
|
||||
|
||||
updateSampling();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void ODGauge::setRender(bool render)
|
||||
{
|
||||
// Only the far camera should trigger this texture to be rendered.
|
||||
camera->setNodeMask(render ? simgear::BACKGROUND_BIT : 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool ODGauge::serviceable(void)
|
||||
{
|
||||
return rtAvailable;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void ODGauge::allocRT(osg::NodeCallback* camera_cull_callback)
|
||||
{
|
||||
camera = new osg::Camera;
|
||||
camera->setDataVariance(osg::Object::DYNAMIC);
|
||||
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||
camera->setRenderOrder(osg::Camera::PRE_RENDER);
|
||||
camera->setClearColor(osg::Vec4(0.0f, 0.0f, 0.0f , 0.0f));
|
||||
camera->setClearStencil(0);
|
||||
camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT,
|
||||
osg::Camera::FRAME_BUFFER );
|
||||
|
||||
if( camera_cull_callback )
|
||||
camera->setCullCallback(camera_cull_callback);
|
||||
|
||||
setRender(true);
|
||||
updateCoordinateFrame();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void ODGauge::useImageCoords(bool use)
|
||||
{
|
||||
if( use == _use_image_coords )
|
||||
return;
|
||||
|
||||
_use_image_coords = use;
|
||||
|
||||
if( texture )
|
||||
updateCoordinateFrame();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void ODGauge::useStencil(bool use)
|
||||
{
|
||||
if( use == _use_stencil )
|
||||
return;
|
||||
|
||||
_use_stencil = use;
|
||||
|
||||
if( texture )
|
||||
updateStencil();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void ODGauge::setSampling( bool mipmapping,
|
||||
int coverage_samples,
|
||||
int color_samples )
|
||||
{
|
||||
if( _use_mipmapping == mipmapping
|
||||
&& _coverage_samples == coverage_samples
|
||||
&& _color_samples == color_samples )
|
||||
return;
|
||||
osg::StateSet* stateSet = camera->getOrCreateStateSet();
|
||||
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
||||
stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
|
||||
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||
stateSet->setAttributeAndModes(
|
||||
new osg::PolygonMode( osg::PolygonMode::FRONT_AND_BACK,
|
||||
osg::PolygonMode::FILL ),
|
||||
osg::StateAttribute::ON );
|
||||
stateSet->setAttributeAndModes(
|
||||
new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.0f),
|
||||
osg::StateAttribute::ON );
|
||||
stateSet->setAttribute(new osg::ShadeModel(osg::ShadeModel::FLAT));
|
||||
stateSet->setAttributeAndModes(
|
||||
new osg::BlendFunc( osg::BlendFunc::SRC_ALPHA,
|
||||
osg::BlendFunc::ONE_MINUS_SRC_ALPHA),
|
||||
osg::StateAttribute::ON );
|
||||
if( !texture )
|
||||
{
|
||||
texture = new osg::Texture2D;
|
||||
texture->setTextureSize(_size_x, _size_y);
|
||||
texture->setInternalFormat(GL_RGBA);
|
||||
}
|
||||
|
||||
_use_mipmapping = mipmapping;
|
||||
updateSampling();
|
||||
|
||||
if( color_samples > coverage_samples )
|
||||
if( _system_adapter )
|
||||
_system_adapter->addCamera(camera.get());
|
||||
|
||||
rtAvailable = true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void ODGauge::updateCoordinateFrame()
|
||||
{
|
||||
SG_LOG
|
||||
(
|
||||
SG_GL,
|
||||
SG_WARN,
|
||||
"ODGauge::setSampling: color_samples > coverage_samples not allowed!"
|
||||
assert( camera );
|
||||
|
||||
if( _view_width < 0 )
|
||||
_view_width = _size_x;
|
||||
if( _view_height < 0 )
|
||||
_view_height = _size_y;
|
||||
|
||||
camera->setViewport(0, 0, _size_x, _size_y);
|
||||
|
||||
if( _use_image_coords )
|
||||
camera->setProjectionMatrix(
|
||||
osg::Matrix::ortho2D(0, _view_width, _view_height, 0)
|
||||
);
|
||||
else
|
||||
camera->setProjectionMatrix(
|
||||
osg::Matrix::ortho2D( -_view_width/2., _view_width/2.,
|
||||
-_view_height/2., _view_height/2. )
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void ODGauge::updateStencil()
|
||||
{
|
||||
assert( camera );
|
||||
|
||||
GLbitfield mask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
|
||||
|
||||
if( _use_stencil)
|
||||
{
|
||||
camera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER,
|
||||
GL_DEPTH_STENCIL_EXT );
|
||||
mask |= GL_STENCIL_BUFFER_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
camera->detach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER);
|
||||
}
|
||||
|
||||
camera->setClearMask(mask);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void ODGauge::updateSampling()
|
||||
{
|
||||
assert( camera );
|
||||
assert( texture );
|
||||
|
||||
texture->setFilter(
|
||||
osg::Texture2D::MIN_FILTER,
|
||||
_use_mipmapping ? osg::Texture2D::LINEAR_MIPMAP_LINEAR
|
||||
: osg::Texture2D::LINEAR
|
||||
);
|
||||
color_samples = coverage_samples;
|
||||
}
|
||||
|
||||
_coverage_samples = coverage_samples;
|
||||
_color_samples = color_samples;
|
||||
|
||||
updateSampling();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void ODGauge::setRender(bool render)
|
||||
{
|
||||
// Only the far camera should trigger this texture to be rendered.
|
||||
camera->setNodeMask(render ? simgear::BACKGROUND_BIT : 0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool ODGauge::serviceable(void)
|
||||
{
|
||||
return rtAvailable;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void ODGauge::allocRT(osg::NodeCallback* camera_cull_callback)
|
||||
{
|
||||
camera = new osg::Camera;
|
||||
camera->setDataVariance(osg::Object::DYNAMIC);
|
||||
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||
camera->setRenderOrder(osg::Camera::PRE_RENDER);
|
||||
camera->setClearColor(osg::Vec4(0.0f, 0.0f, 0.0f , 0.0f));
|
||||
camera->setClearStencil(0);
|
||||
camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT,
|
||||
osg::Camera::FRAME_BUFFER );
|
||||
|
||||
if( camera_cull_callback )
|
||||
camera->setCullCallback(camera_cull_callback);
|
||||
|
||||
setRender(true);
|
||||
updateCoordinateFrame();
|
||||
updateStencil();
|
||||
|
||||
osg::StateSet* stateSet = camera->getOrCreateStateSet();
|
||||
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
||||
stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
|
||||
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||
stateSet->setAttributeAndModes(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK,
|
||||
osg::PolygonMode::FILL),
|
||||
osg::StateAttribute::ON);
|
||||
stateSet->setAttributeAndModes(new osg::AlphaFunc(osg::AlphaFunc::GREATER,
|
||||
0.0f),
|
||||
osg::StateAttribute::ON);
|
||||
stateSet->setAttribute(new osg::ShadeModel(osg::ShadeModel::FLAT));
|
||||
stateSet->setAttributeAndModes(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA,
|
||||
osg::BlendFunc::ONE_MINUS_SRC_ALPHA),
|
||||
osg::StateAttribute::ON);
|
||||
if( !texture )
|
||||
{
|
||||
texture = new osg::Texture2D;
|
||||
texture->setTextureSize(_size_x, _size_y);
|
||||
texture->setInternalFormat(GL_RGBA);
|
||||
}
|
||||
|
||||
updateSampling();
|
||||
|
||||
_cb_cam_add(camera.get());
|
||||
rtAvailable = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void ODGauge::updateCoordinateFrame()
|
||||
{
|
||||
assert( camera );
|
||||
|
||||
if( _view_width < 0 )
|
||||
_view_width = _size_x;
|
||||
if( _view_height < 0 )
|
||||
_view_height = _size_y;
|
||||
|
||||
camera->setViewport(0, 0, _size_x, _size_y);
|
||||
|
||||
if( _use_image_coords )
|
||||
camera->setProjectionMatrix(
|
||||
osg::Matrix::ortho2D(0, _view_width, _view_height, 0)
|
||||
camera->attach(
|
||||
osg::Camera::COLOR_BUFFER,
|
||||
texture.get(),
|
||||
0, 0,
|
||||
_use_mipmapping,
|
||||
_coverage_samples,
|
||||
_color_samples
|
||||
);
|
||||
else
|
||||
camera->setProjectionMatrix(
|
||||
osg::Matrix::ortho2D( -_view_width/2., _view_width/2.,
|
||||
-_view_height/2., _view_height/2. )
|
||||
);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void ODGauge::updateStencil()
|
||||
{
|
||||
assert( camera );
|
||||
|
||||
GLbitfield mask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
|
||||
|
||||
if( _use_stencil)
|
||||
{
|
||||
camera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER,
|
||||
GL_DEPTH_STENCIL_EXT );
|
||||
mask |= GL_STENCIL_BUFFER_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
camera->detach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER);
|
||||
}
|
||||
|
||||
camera->setClearMask(mask);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void ODGauge::updateSampling()
|
||||
{
|
||||
assert( camera );
|
||||
assert( texture );
|
||||
|
||||
texture->setFilter(
|
||||
osg::Texture2D::MIN_FILTER,
|
||||
_use_mipmapping ? osg::Texture2D::LINEAR_MIPMAP_LINEAR
|
||||
: osg::Texture2D::LINEAR
|
||||
);
|
||||
camera->attach(
|
||||
osg::Camera::COLOR_BUFFER,
|
||||
texture.get(),
|
||||
0, 0,
|
||||
_use_mipmapping,
|
||||
_coverage_samples,
|
||||
_color_samples
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
@@ -10,30 +10,28 @@
|
||||
// Supports now multisampling/mipmapping, usage of the stencil buffer and placing
|
||||
// the texture in the scene by certain filter criteria
|
||||
//
|
||||
// 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 library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library 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
|
||||
// This library 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.
|
||||
//
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef _SG_OD_GAUGE_HXX
|
||||
#define _SG_OD_GAUGE_HXX
|
||||
|
||||
#include "canvas_fwd.hxx"
|
||||
|
||||
#include <osg/NodeCallback>
|
||||
#include <osg/Group>
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Camera;
|
||||
@@ -42,6 +40,9 @@ namespace osg
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
/**
|
||||
* Owner Drawn Gauge (aka render-to-texture) helper class
|
||||
*/
|
||||
@@ -49,12 +50,11 @@ namespace simgear
|
||||
{
|
||||
public:
|
||||
|
||||
typedef boost::function<void(osg::Camera*)> CameraRegistrationCallback;
|
||||
|
||||
ODGauge( const CameraRegistrationCallback& cb_camera_add,
|
||||
const CameraRegistrationCallback& cb_camera_remove );
|
||||
ODGauge();
|
||||
virtual ~ODGauge();
|
||||
|
||||
void setSystemAdapter(const SystemAdapterPtr& system_adapter);
|
||||
|
||||
/**
|
||||
* Set the size of the render target.
|
||||
*
|
||||
@@ -124,7 +124,9 @@ namespace simgear
|
||||
// Real initialization function. Bad name.
|
||||
void allocRT(osg::NodeCallback* camera_cull_callback = 0);
|
||||
|
||||
private:
|
||||
protected:
|
||||
|
||||
SystemAdapterPtr _system_adapter;
|
||||
|
||||
int _size_x,
|
||||
_size_y,
|
||||
@@ -142,15 +144,13 @@ namespace simgear
|
||||
osg::ref_ptr<osg::Camera> camera;
|
||||
osg::ref_ptr<osg::Texture2D> texture;
|
||||
|
||||
CameraRegistrationCallback _cb_cam_add,
|
||||
_cb_cam_remove;
|
||||
|
||||
void updateCoordinateFrame();
|
||||
void updateStencil();
|
||||
void updateSampling();
|
||||
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif // _SG_OD_GAUGE_HXX
|
||||
|
||||
@@ -45,4 +45,8 @@ TARGET_LINK_LIBRARIES(
|
||||
ShivaVG
|
||||
${OPENGL_gl_LIBRARY}
|
||||
${OPENGL_glu_LIBRARY}
|
||||
)
|
||||
)
|
||||
|
||||
if(NOT SIMGEAR_HEADLESS)
|
||||
install(TARGETS ShivaVG ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
@@ -12,9 +12,9 @@
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Library 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.
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef CANVAS_VG_INITOPERATION_HXX_
|
||||
#define CANVAS_VG_INITOPERATION_HXX_
|
||||
|
||||
58
simgear/canvas/canvas_fwd.hxx
Normal file
58
simgear/canvas/canvas_fwd.hxx
Normal file
@@ -0,0 +1,58 @@
|
||||
// Canvas forward declarations
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef SG_CANVAS_FWD_HXX_
|
||||
#define SG_CANVAS_FWD_HXX_
|
||||
|
||||
#include <simgear/props/propsfwd.hxx>
|
||||
#include <simgear/structure/SGWeakPtr.hxx>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osgText/Font>
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/weak_ptr.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
class Canvas;
|
||||
typedef boost::shared_ptr<Canvas> CanvasPtr;
|
||||
typedef boost::weak_ptr<Canvas> CanvasWeakPtr;
|
||||
|
||||
typedef osg::ref_ptr<osgText::Font> FontPtr;
|
||||
|
||||
class Placement;
|
||||
typedef boost::shared_ptr<Placement> PlacementPtr;
|
||||
typedef std::vector<PlacementPtr> Placements;
|
||||
typedef boost::function<Placements( const SGPropertyNode*,
|
||||
CanvasPtr )> PlacementFactory;
|
||||
|
||||
class SystemAdapter;
|
||||
typedef boost::shared_ptr<SystemAdapter> SystemAdapterPtr;
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
|
||||
#endif /* SG_CANVAS_FWD_HXX_ */
|
||||
21
simgear/canvas/elements/CMakeLists.txt
Normal file
21
simgear/canvas/elements/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
include (SimGearComponent)
|
||||
|
||||
set(HEADERS
|
||||
CanvasElement.hxx
|
||||
CanvasGroup.hxx
|
||||
CanvasImage.hxx
|
||||
CanvasMap.hxx
|
||||
CanvasPath.hxx
|
||||
CanvasText.hxx
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
CanvasElement.cxx
|
||||
CanvasGroup.cxx
|
||||
CanvasImage.cxx
|
||||
CanvasMap.cxx
|
||||
CanvasPath.cxx
|
||||
CanvasText.cxx
|
||||
)
|
||||
|
||||
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
|
||||
304
simgear/canvas/elements/CanvasElement.cxx
Normal file
304
simgear/canvas/elements/CanvasElement.cxx
Normal file
@@ -0,0 +1,304 @@
|
||||
// Interface for 2D Canvas element
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "CanvasElement.hxx"
|
||||
#include <simgear/canvas/MouseEvent.hxx>
|
||||
|
||||
#include <osg/Drawable>
|
||||
#include <osg/Geode>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
const std::string NAME_TRANSFORM = "tf";
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::removeListener()
|
||||
{
|
||||
_node->removeChangeListener(this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Element::~Element()
|
||||
{
|
||||
removeListener();
|
||||
|
||||
BOOST_FOREACH(osg::Group* parent, _transform->getParents())
|
||||
{
|
||||
parent->removeChild(_transform);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::update(double dt)
|
||||
{
|
||||
if( !_transform->getNodeMask() )
|
||||
// Don't do anything if element is hidden
|
||||
return;
|
||||
|
||||
if( _transform_dirty )
|
||||
{
|
||||
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);
|
||||
|
||||
// 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, 0,
|
||||
|
||||
tf_node->getDoubleValue("m[2]", 0),
|
||||
tf_node->getDoubleValue("m[3]", 1), 0, 0,
|
||||
|
||||
0, 0, 1, 0,
|
||||
tf_node->getDoubleValue("m[4]", 0),
|
||||
tf_node->getDoubleValue("m[5]", 0), 0, 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);
|
||||
_transform_dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Element::handleMouseEvent(const MouseEvent& event)
|
||||
{
|
||||
// Transform event to local coordinates
|
||||
const osg::Matrixd& m = _transform->getInverseMatrix();
|
||||
MouseEvent local_event = event;
|
||||
local_event.x = m(0, 0) * event.x + m(1, 0) * event.y + m(3, 0);
|
||||
local_event.y = m(0, 1) * event.x + m(1, 1) * event.y + m(3, 1);
|
||||
|
||||
// Drawables have a bounding box...
|
||||
if( _drawable )
|
||||
{
|
||||
if( !_drawable->getBound().contains(local_event.getPos3()) )
|
||||
return false;
|
||||
}
|
||||
// ... for other elements, i.e. groups only a bounding sphere is available
|
||||
else if( !_transform->getBound().contains(local_event.getPos3()) )
|
||||
return false;
|
||||
|
||||
local_event.dx = m(0, 0) * event.dx + m(1, 0) * event.dy;
|
||||
local_event.dy = m(0, 1) * event.dx + m(1, 1) * event.dy;
|
||||
|
||||
return handleLocalMouseEvent(local_event);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::ref_ptr<osg::MatrixTransform> Element::getMatrixTransform()
|
||||
{
|
||||
return _transform;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
|
||||
{
|
||||
if( parent == _node
|
||||
&& child->getNameString() == NAME_TRANSFORM )
|
||||
{
|
||||
if( child->getIndex() >= static_cast<int>(_transform_types.size()) )
|
||||
_transform_types.resize( child->getIndex() + 1 );
|
||||
|
||||
_transform_types[ child->getIndex() ] = TT_NONE;
|
||||
_transform_dirty = true;
|
||||
return;
|
||||
}
|
||||
else if( parent->getParent() == _node
|
||||
&& parent->getNameString() == NAME_TRANSFORM )
|
||||
{
|
||||
assert(parent->getIndex() < static_cast<int>(_transform_types.size()));
|
||||
|
||||
const std::string& name = child->getNameString();
|
||||
|
||||
TransformType& type = _transform_types[parent->getIndex()];
|
||||
|
||||
if( name == "m" )
|
||||
type = TT_MATRIX;
|
||||
else if( name == "t" )
|
||||
type = TT_TRANSLATE;
|
||||
else if( name == "rot" )
|
||||
type = TT_ROTATE;
|
||||
else if( name == "s" )
|
||||
type = TT_SCALE;
|
||||
|
||||
_transform_dirty = true;
|
||||
return;
|
||||
}
|
||||
|
||||
childAdded(child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
|
||||
{
|
||||
if( parent == _node && child->getNameString() == NAME_TRANSFORM )
|
||||
{
|
||||
assert(child->getIndex() < static_cast<int>(_transform_types.size()));
|
||||
_transform_types[ child->getIndex() ] = TT_NONE;
|
||||
|
||||
while( !_transform_types.empty() && _transform_types.back() == TT_NONE )
|
||||
_transform_types.pop_back();
|
||||
|
||||
_transform_dirty = true;
|
||||
return;
|
||||
}
|
||||
|
||||
childRemoved(child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::valueChanged(SGPropertyNode* child)
|
||||
{
|
||||
SGPropertyNode *parent = child->getParent();
|
||||
if( parent == _node )
|
||||
{
|
||||
if( setStyle(child) )
|
||||
return;
|
||||
else if( child->getNameString() == "update" )
|
||||
return update(0);
|
||||
else if( child->getNameString() == "visible" )
|
||||
// TODO check if we need another nodemask
|
||||
return _transform->setNodeMask( child->getBoolValue() ? 0xffffffff : 0 );
|
||||
}
|
||||
else if( parent->getParent() == _node
|
||||
&& parent->getNameString() == NAME_TRANSFORM )
|
||||
{
|
||||
_transform_dirty = true;
|
||||
return;
|
||||
}
|
||||
|
||||
childChanged(child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::setBoundingBox(const osg::BoundingBox& bb)
|
||||
{
|
||||
if( _bounding_box.empty() )
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
_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());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Element::Element( const CanvasWeakPtr& canvas,
|
||||
SGPropertyNode_ptr node,
|
||||
const Style& parent_style ):
|
||||
_canvas( canvas ),
|
||||
_transform_dirty( false ),
|
||||
_transform( new osg::MatrixTransform ),
|
||||
_node( node ),
|
||||
_style( parent_style ),
|
||||
_drawable( 0 )
|
||||
{
|
||||
assert( _node );
|
||||
_node->addChangeListener(this);
|
||||
|
||||
SG_LOG
|
||||
(
|
||||
SG_GL,
|
||||
SG_DEBUG,
|
||||
"New canvas element " << node->getPath()
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Element::handleLocalMouseEvent(const MouseEvent& event)
|
||||
{
|
||||
// std::cout << _node->getPath()
|
||||
// << " local: pos=(" << event.x << "|" << event.y << ") "
|
||||
// << "d=(" << event.dx << "|" << event.dx << ")"
|
||||
// << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::setDrawable( osg::Drawable* drawable )
|
||||
{
|
||||
_drawable = drawable;
|
||||
assert( _drawable );
|
||||
|
||||
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
|
||||
geode->addDrawable(_drawable);
|
||||
_transform->addChild(geode);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::setupStyle()
|
||||
{
|
||||
BOOST_FOREACH( Style::value_type style, _style )
|
||||
setStyle(style.second);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Element::setStyle(const SGPropertyNode* child)
|
||||
{
|
||||
StyleSetters::const_iterator setter =
|
||||
_style_setters.find(child->getNameString());
|
||||
if( setter == _style_setters.end() )
|
||||
return false;
|
||||
|
||||
setter->second(child);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
178
simgear/canvas/elements/CanvasElement.hxx
Normal file
178
simgear/canvas/elements/CanvasElement.hxx
Normal file
@@ -0,0 +1,178 @@
|
||||
// Interface for 2D Canvas elements
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef CANVAS_ELEMENT_HXX_
|
||||
#define CANVAS_ELEMENT_HXX_
|
||||
|
||||
#include <simgear/canvas/canvas_fwd.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/misc/stdint.hxx> // for uint32_t
|
||||
#include <osg/BoundingBox>
|
||||
#include <osg/MatrixTransform>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Drawable;
|
||||
}
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
class MouseEvent;
|
||||
class Element:
|
||||
public SGPropertyChangeListener
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::string, const SGPropertyNode*> Style;
|
||||
typedef boost::function<void(const SGPropertyNode*)> StyleSetter;
|
||||
typedef std::map<std::string, StyleSetter> StyleSetters;
|
||||
|
||||
/**
|
||||
* Remove the property listener of the element.
|
||||
*
|
||||
* You will need to call the appropriate methods (#childAdded,
|
||||
* #childRemoved, #valueChanged) yourself to ensure the element still
|
||||
* receives the needed events.
|
||||
*/
|
||||
void removeListener();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
virtual ~Element() = 0;
|
||||
|
||||
/**
|
||||
* Called every frame to update internal state
|
||||
*
|
||||
* @param dt Frame time in seconds
|
||||
*/
|
||||
virtual void update(double dt);
|
||||
|
||||
/**
|
||||
* Handle mouse event (transforms coordinates to local coordinate frame
|
||||
* and forwards event to #handleLocalMouseEvent)
|
||||
*/
|
||||
virtual bool handleMouseEvent(const canvas::MouseEvent& event);
|
||||
|
||||
osg::ref_ptr<osg::MatrixTransform> getMatrixTransform();
|
||||
|
||||
virtual void childAdded( SGPropertyNode * parent,
|
||||
SGPropertyNode * child );
|
||||
virtual void childRemoved( SGPropertyNode * parent,
|
||||
SGPropertyNode * child );
|
||||
virtual void valueChanged(SGPropertyNode * child);
|
||||
|
||||
/**
|
||||
* Write the given bounding box to the property tree
|
||||
*/
|
||||
void setBoundingBox(const osg::BoundingBox& bb);
|
||||
|
||||
protected:
|
||||
|
||||
enum Attributes
|
||||
{
|
||||
LAST_ATTRIBUTE = 0x0001
|
||||
};
|
||||
|
||||
enum TransformType
|
||||
{
|
||||
TT_NONE,
|
||||
TT_MATRIX,
|
||||
TT_TRANSLATE,
|
||||
TT_ROTATE,
|
||||
TT_SCALE
|
||||
};
|
||||
|
||||
CanvasWeakPtr _canvas;
|
||||
uint32_t _attributes_dirty;
|
||||
|
||||
bool _transform_dirty;
|
||||
osg::ref_ptr<osg::MatrixTransform> _transform;
|
||||
std::vector<TransformType> _transform_types;
|
||||
|
||||
SGPropertyNode_ptr _node;
|
||||
Style _style;
|
||||
StyleSetters _style_setters;
|
||||
std::vector<SGPropertyNode_ptr> _bounding_box;
|
||||
|
||||
Element( const CanvasWeakPtr& canvas,
|
||||
SGPropertyNode_ptr node,
|
||||
const Style& parent_style );
|
||||
|
||||
template<typename T, class C1, class C2>
|
||||
Element::StyleSetter
|
||||
addStyle(const std::string& name, void (C1::*setter)(T), C2 instance)
|
||||
{
|
||||
return _style_setters[ name ] =
|
||||
bindStyleSetter<T>(name, setter, instance);
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, class C1, class C2>
|
||||
Element::StyleSetter
|
||||
addStyle(const std::string& name, void (C1::*setter)(T2), C2 instance)
|
||||
{
|
||||
return _style_setters[ name ] =
|
||||
bindStyleSetter<T1>(name, setter, instance);
|
||||
}
|
||||
|
||||
template<class C1, class C2>
|
||||
Element::StyleSetter
|
||||
addStyle( const std::string& name,
|
||||
void (C1::*setter)(const std::string&),
|
||||
C2 instance )
|
||||
{
|
||||
return _style_setters[ name ] =
|
||||
bindStyleSetter<const char*>(name, setter, instance);
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, class C1, class C2>
|
||||
Element::StyleSetter
|
||||
bindStyleSetter( const std::string& name,
|
||||
void (C1::*setter)(T2),
|
||||
C2 instance )
|
||||
{
|
||||
return boost::bind(setter, instance, boost::bind(&getValue<T1>, _1));
|
||||
}
|
||||
|
||||
virtual bool handleLocalMouseEvent(const canvas::MouseEvent& event);
|
||||
|
||||
virtual void childAdded(SGPropertyNode * child) {}
|
||||
virtual void childRemoved(SGPropertyNode * child){}
|
||||
virtual void childChanged(SGPropertyNode * child){}
|
||||
|
||||
void setDrawable(osg::Drawable* drawable);
|
||||
|
||||
void setupStyle();
|
||||
bool setStyle(const SGPropertyNode* child);
|
||||
|
||||
private:
|
||||
|
||||
osg::ref_ptr<osg::Drawable> _drawable;
|
||||
|
||||
Element(const Element&);// = delete
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* CANVAS_ELEMENT_HXX_ */
|
||||
219
simgear/canvas/elements/CanvasGroup.cxx
Normal file
219
simgear/canvas/elements/CanvasGroup.cxx
Normal file
@@ -0,0 +1,219 @@
|
||||
// A group of 2D Canvas elements
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "CanvasGroup.hxx"
|
||||
#include "CanvasImage.hxx"
|
||||
#include "CanvasMap.hxx"
|
||||
#include "CanvasPath.hxx"
|
||||
#include "CanvasText.hxx"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Group::Group( const CanvasWeakPtr& canvas,
|
||||
SGPropertyNode_ptr node,
|
||||
const Style& parent_style ):
|
||||
Element(canvas, node, parent_style)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Group::~Group()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Group::update(double dt)
|
||||
{
|
||||
BOOST_FOREACH( ChildList::value_type child, _children )
|
||||
child.second->update(dt);
|
||||
|
||||
Element::update(dt);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Group::handleLocalMouseEvent(const canvas::MouseEvent& event)
|
||||
{
|
||||
// Iterate in reverse order as last child is displayed on top
|
||||
BOOST_REVERSE_FOREACH( ChildList::value_type child, _children )
|
||||
{
|
||||
if( child.second->handleMouseEvent(event) )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Group::childAdded(SGPropertyNode* child)
|
||||
{
|
||||
if( child->getParent() != _node )
|
||||
return;
|
||||
|
||||
boost::shared_ptr<Element> element;
|
||||
|
||||
// TODO create map of child factories and use also to check for element
|
||||
// on deletion in ::childRemoved
|
||||
if( child->getNameString() == "text" )
|
||||
element.reset( new Text(_canvas, child, _style) );
|
||||
else if( child->getNameString() == "group" )
|
||||
element.reset( new Group(_canvas, child, _style) );
|
||||
else if( child->getNameString() == "map" )
|
||||
element.reset( new Map(_canvas, child, _style) );
|
||||
else if( child->getNameString() == "path" )
|
||||
element.reset( new Path(_canvas, child, _style) );
|
||||
else if( child->getNameString() == "image" )
|
||||
element.reset( new Image(_canvas, child, _style) );
|
||||
|
||||
if( element )
|
||||
{
|
||||
// Add to osg scene graph...
|
||||
_transform->addChild( element->getMatrixTransform() );
|
||||
_children.push_back( ChildList::value_type(child, element) );
|
||||
return;
|
||||
}
|
||||
|
||||
_style[ child->getNameString() ] = child;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct ChildFinder
|
||||
{
|
||||
public:
|
||||
ChildFinder(SGPropertyNode *node):
|
||||
_node(node)
|
||||
{}
|
||||
|
||||
bool operator()(const Group::ChildList::value_type& el) const
|
||||
{
|
||||
return el.first == _node;
|
||||
}
|
||||
|
||||
private:
|
||||
SGPropertyNode *_node;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Group::childRemoved(SGPropertyNode* node)
|
||||
{
|
||||
if( node->getParent() != _node )
|
||||
return;
|
||||
|
||||
if( node->getNameString() == "text"
|
||||
|| node->getNameString() == "group"
|
||||
|| node->getNameString() == "map"
|
||||
|| node->getNameString() == "path"
|
||||
|| node->getNameString() == "image" )
|
||||
{
|
||||
ChildFinder pred(node);
|
||||
ChildList::iterator child =
|
||||
std::find_if(_children.begin(), _children.end(), pred);
|
||||
|
||||
if( child == _children.end() )
|
||||
SG_LOG
|
||||
(
|
||||
SG_GL,
|
||||
SG_WARN,
|
||||
"can't removed unknown child " << node->getDisplayName()
|
||||
);
|
||||
else
|
||||
{
|
||||
_transform->removeChild( child->second->getMatrixTransform() );
|
||||
_children.erase(child);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Style::iterator style = _style.find(node->getNameString());
|
||||
if( style != _style.end() )
|
||||
_style.erase(style);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Group::childChanged(SGPropertyNode* node)
|
||||
{
|
||||
if( node->getParent()->getParent() == _node
|
||||
&& node->getNameString() == "z-index" )
|
||||
return handleZIndexChanged(node->getParent(), node->getIntValue());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Group::handleZIndexChanged(SGPropertyNode* node, int z_index)
|
||||
{
|
||||
ChildFinder pred(node);
|
||||
ChildList::iterator child =
|
||||
std::find_if(_children.begin(), _children.end(), pred);
|
||||
|
||||
if( child == _children.end() )
|
||||
return;
|
||||
|
||||
osg::Node* tf = child->second->getMatrixTransform();
|
||||
int index = _transform->getChildIndex(tf),
|
||||
index_new = index;
|
||||
|
||||
ChildList::iterator next = child;
|
||||
++next;
|
||||
|
||||
while( next != _children.end()
|
||||
&& next->first->getIntValue("z-index", 0) <= z_index )
|
||||
{
|
||||
++index_new;
|
||||
++next;
|
||||
}
|
||||
|
||||
if( index_new != index )
|
||||
{
|
||||
_children.insert(next, *child);
|
||||
}
|
||||
else
|
||||
{
|
||||
ChildList::iterator prev = child;
|
||||
while( prev != _children.begin()
|
||||
&& (--prev)->first->getIntValue("z-index", 0) > z_index)
|
||||
{
|
||||
--index_new;
|
||||
}
|
||||
|
||||
if( index == index_new )
|
||||
return;
|
||||
|
||||
_children.insert(prev, *child);
|
||||
}
|
||||
|
||||
_transform->removeChild(index);
|
||||
_transform->insertChild(index_new, tf);
|
||||
|
||||
_children.erase(child);
|
||||
|
||||
SG_LOG
|
||||
(
|
||||
SG_GENERAL,
|
||||
SG_INFO,
|
||||
"canvas::Group: Moved element " << index << " to position " << index_new
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
67
simgear/canvas/elements/CanvasGroup.hxx
Normal file
67
simgear/canvas/elements/CanvasGroup.hxx
Normal file
@@ -0,0 +1,67 @@
|
||||
// A group of 2D Canvas elements
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef CANVAS_GROUP_HXX_
|
||||
#define CANVAS_GROUP_HXX_
|
||||
|
||||
#include "CanvasElement.hxx"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
typedef boost::shared_ptr<Element> ElementPtr;
|
||||
|
||||
class Group:
|
||||
public Element
|
||||
{
|
||||
public:
|
||||
typedef std::list< std::pair< const SGPropertyNode*,
|
||||
ElementPtr
|
||||
>
|
||||
> ChildList;
|
||||
|
||||
Group( const CanvasWeakPtr& canvas,
|
||||
SGPropertyNode_ptr node,
|
||||
const Style& parent_style = Style() );
|
||||
virtual ~Group();
|
||||
|
||||
virtual void update(double dt);
|
||||
|
||||
protected:
|
||||
|
||||
ChildList _children;
|
||||
|
||||
virtual bool handleLocalMouseEvent(const canvas::MouseEvent& event);
|
||||
|
||||
virtual void childAdded(SGPropertyNode * child);
|
||||
virtual void childRemoved(SGPropertyNode * child);
|
||||
virtual void childChanged(SGPropertyNode * child);
|
||||
|
||||
void handleZIndexChanged(SGPropertyNode* node, int z_index);
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* CANVAS_GROUP_HXX_ */
|
||||
352
simgear/canvas/elements/CanvasImage.cxx
Normal file
352
simgear/canvas/elements/CanvasImage.cxx
Normal file
@@ -0,0 +1,352 @@
|
||||
// An image on the Canvas
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "CanvasImage.hxx"
|
||||
|
||||
#include <simgear/canvas/Canvas.hxx>
|
||||
#include <simgear/canvas/CanvasMgr.hxx>
|
||||
#include <simgear/canvas/CanvasSystemAdapter.hxx>
|
||||
#include <simgear/misc/parse_color.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#include <osg/Array>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/PrimitiveSet>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
/**
|
||||
* Callback to enable/disable rendering of canvas displayed inside windows or
|
||||
* other canvases.
|
||||
*/
|
||||
class CullCallback:
|
||||
public osg::Drawable::CullCallback
|
||||
{
|
||||
public:
|
||||
CullCallback(const CanvasWeakPtr& canvas);
|
||||
|
||||
private:
|
||||
CanvasWeakPtr _canvas;
|
||||
|
||||
virtual bool cull( osg::NodeVisitor* nv,
|
||||
osg::Drawable* drawable,
|
||||
osg::RenderInfo* renderInfo ) const;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
CullCallback::CullCallback(const CanvasWeakPtr& canvas):
|
||||
_canvas( canvas )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool CullCallback::cull( osg::NodeVisitor* nv,
|
||||
osg::Drawable* drawable,
|
||||
osg::RenderInfo* renderInfo ) const
|
||||
{
|
||||
if( !_canvas.expired() )
|
||||
_canvas.lock()->enableRendering();
|
||||
|
||||
// TODO check if window/image should be culled
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Image::Image( const CanvasWeakPtr& canvas,
|
||||
SGPropertyNode_ptr node,
|
||||
const Style& parent_style ):
|
||||
Element(canvas, node, parent_style),
|
||||
_texture(new osg::Texture2D),
|
||||
_node_src_rect( node->getNode("source", 0, true) )
|
||||
{
|
||||
_geom = new osg::Geometry;
|
||||
_geom->setUseDisplayList(false);
|
||||
|
||||
osg::StateSet *stateSet = _geom->getOrCreateStateSet();
|
||||
stateSet->setTextureAttributeAndModes(0, _texture.get());
|
||||
stateSet->setDataVariance(osg::Object::STATIC);
|
||||
|
||||
// allocate arrays for the image
|
||||
_vertices = new osg::Vec3Array(4);
|
||||
_vertices->setDataVariance(osg::Object::STATIC);
|
||||
_geom->setVertexArray(_vertices);
|
||||
|
||||
_texCoords = new osg::Vec2Array(4);
|
||||
_texCoords->setDataVariance(osg::Object::STATIC);
|
||||
_geom->setTexCoordArray(0, _texCoords);
|
||||
|
||||
_colors = new osg::Vec4Array(4);
|
||||
_colors->setDataVariance(osg::Object::STATIC);
|
||||
_geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
|
||||
_geom->setColorArray(_colors);
|
||||
|
||||
osg::DrawArrays* prim = new osg::DrawArrays(osg::PrimitiveSet::QUADS);
|
||||
prim->set(osg::PrimitiveSet::QUADS, 0, 4);
|
||||
prim->setDataVariance(osg::Object::STATIC);
|
||||
_geom->addPrimitiveSet(prim);
|
||||
|
||||
setDrawable(_geom);
|
||||
|
||||
addStyle("fill", &Image::setFill, this);
|
||||
setFill("#ffffff"); // TODO how should we handle default values?
|
||||
|
||||
setupStyle();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Image::~Image()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Image::update(double dt)
|
||||
{
|
||||
Element::update(dt);
|
||||
|
||||
if( _attributes_dirty & DEST_SIZE )
|
||||
{
|
||||
(*_vertices)[0].set(_region.l(), _region.t(), 0);
|
||||
(*_vertices)[1].set(_region.r(), _region.t(), 0);
|
||||
(*_vertices)[2].set(_region.r(), _region.b(), 0);
|
||||
(*_vertices)[3].set(_region.l(), _region.b(), 0);
|
||||
_vertices->dirty();
|
||||
|
||||
_attributes_dirty &= ~DEST_SIZE;
|
||||
_geom->dirtyBound();
|
||||
setBoundingBox(_geom->getBound());
|
||||
}
|
||||
|
||||
if( _attributes_dirty & SRC_RECT )
|
||||
{
|
||||
double u0 = _src_rect.l(),
|
||||
u1 = _src_rect.r(),
|
||||
v0 = _src_rect.b(),
|
||||
v1 = _src_rect.t();
|
||||
|
||||
if( !_node_src_rect->getBoolValue("normalized", true) )
|
||||
{
|
||||
const Rect<int>& tex_dim = getTextureDimensions();
|
||||
|
||||
u0 /= tex_dim.width();
|
||||
u1 /= tex_dim.width();
|
||||
v0 /= tex_dim.height();
|
||||
v1 /= tex_dim.height();
|
||||
}
|
||||
|
||||
(*_texCoords)[0].set(u0, v0);
|
||||
(*_texCoords)[1].set(u1, v0);
|
||||
(*_texCoords)[2].set(u1, v1);
|
||||
(*_texCoords)[3].set(u0, v1);
|
||||
_texCoords->dirty();
|
||||
|
||||
_attributes_dirty &= ~SRC_RECT;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Image::setSrcCanvas(CanvasPtr canvas)
|
||||
{
|
||||
if( !_src_canvas.expired() )
|
||||
_src_canvas.lock()->removeDependentCanvas(_canvas);
|
||||
|
||||
_src_canvas = canvas;
|
||||
_geom->getOrCreateStateSet()
|
||||
->setTextureAttribute(0, canvas ? canvas->getTexture() : 0);
|
||||
_geom->setCullCallback(canvas ? new CullCallback(canvas) : 0);
|
||||
|
||||
if( !_src_canvas.expired() )
|
||||
{
|
||||
setupDefaultDimensions();
|
||||
_src_canvas.lock()->addDependentCanvas(_canvas);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
CanvasWeakPtr Image::getSrcCanvas() const
|
||||
{
|
||||
return _src_canvas;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Image::setImage(osg::Image *img)
|
||||
{
|
||||
// remove canvas...
|
||||
setSrcCanvas( CanvasPtr() );
|
||||
|
||||
_texture->setImage(img);
|
||||
_geom->getOrCreateStateSet()
|
||||
->setTextureAttributeAndModes(0, _texture);
|
||||
|
||||
if( img )
|
||||
setupDefaultDimensions();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Image::setFill(const std::string& fill)
|
||||
{
|
||||
osg::Vec4 color;
|
||||
if( !parseColor(fill, color) )
|
||||
return;
|
||||
|
||||
for( int i = 0; i < 4; ++i )
|
||||
(*_colors)[i] = color;
|
||||
_colors->dirty();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const Rect<float>& Image::getRegion() const
|
||||
{
|
||||
return _region;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Image::childChanged(SGPropertyNode* child)
|
||||
{
|
||||
const std::string& name = child->getNameString();
|
||||
|
||||
if( child->getParent() == _node_src_rect )
|
||||
{
|
||||
_attributes_dirty |= SRC_RECT;
|
||||
|
||||
if( name == "left" )
|
||||
_src_rect.setLeft( child->getFloatValue() );
|
||||
else if( name == "right" )
|
||||
_src_rect.setRight( child->getFloatValue() );
|
||||
else if( name == "top" )
|
||||
_src_rect.setTop( child->getFloatValue() );
|
||||
else if( name == "bottom" )
|
||||
_src_rect.setBottom( child->getFloatValue() );
|
||||
|
||||
return;
|
||||
}
|
||||
else if( child->getParent() != _node )
|
||||
return;
|
||||
|
||||
if( name == "x" )
|
||||
{
|
||||
_region.setX( child->getFloatValue() );
|
||||
_attributes_dirty |= DEST_SIZE;
|
||||
}
|
||||
else if( name == "y" )
|
||||
{
|
||||
_region.setY( child->getFloatValue() );
|
||||
_attributes_dirty |= DEST_SIZE;
|
||||
}
|
||||
else if( name == "size" )
|
||||
{
|
||||
if( child->getIndex() == 0 )
|
||||
_region.setWidth( child->getFloatValue() );
|
||||
else
|
||||
_region.setHeight( child->getFloatValue() );
|
||||
|
||||
_attributes_dirty |= DEST_SIZE;
|
||||
}
|
||||
else if( name == "file" )
|
||||
{
|
||||
static const std::string CANVAS_PROTOCOL = "canvas://";
|
||||
const std::string& path = child->getStringValue();
|
||||
|
||||
CanvasPtr canvas = _canvas.lock();
|
||||
if( !canvas )
|
||||
{
|
||||
SG_LOG(SG_GL, SG_ALERT, "canvas::Image: No canvas available");
|
||||
return;
|
||||
}
|
||||
|
||||
if( boost::starts_with(path, CANVAS_PROTOCOL) )
|
||||
{
|
||||
CanvasMgr* canvas_mgr = canvas->getCanvasMgr();
|
||||
if( !canvas_mgr )
|
||||
{
|
||||
SG_LOG(SG_GL, SG_ALERT, "canvas::Image: Failed to get CanvasMgr");
|
||||
return;
|
||||
}
|
||||
|
||||
const SGPropertyNode* canvas_node =
|
||||
canvas_mgr->getPropertyRoot()
|
||||
->getParent()
|
||||
->getNode( path.substr(CANVAS_PROTOCOL.size()) );
|
||||
if( !canvas_node )
|
||||
{
|
||||
SG_LOG(SG_GL, SG_ALERT, "canvas::Image: No such canvas: " << path);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO add support for other means of addressing canvases (eg. by
|
||||
// name)
|
||||
CanvasPtr src_canvas = canvas_mgr->getCanvas( canvas_node->getIndex() );
|
||||
if( !src_canvas )
|
||||
{
|
||||
SG_LOG(SG_GL, SG_ALERT, "canvas::Image: Invalid canvas: " << path);
|
||||
return;
|
||||
}
|
||||
|
||||
setSrcCanvas(src_canvas);
|
||||
}
|
||||
else
|
||||
{
|
||||
setImage( canvas->getSystemAdapter()->getImage(path) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Image::setupDefaultDimensions()
|
||||
{
|
||||
if( !_src_rect.width() || !_src_rect.height() )
|
||||
{
|
||||
const Rect<int>& tex_dim = getTextureDimensions();
|
||||
|
||||
_node_src_rect->setBoolValue("normalized", false);
|
||||
_node_src_rect->setFloatValue("right", tex_dim.width());
|
||||
_node_src_rect->setFloatValue("bottom", tex_dim.height());
|
||||
}
|
||||
|
||||
if( !_region.width() || !_region.height() )
|
||||
{
|
||||
_node->setFloatValue("size[0]", _src_rect.width());
|
||||
_node->setFloatValue("size[1]", _src_rect.height());
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Rect<int> Image::getTextureDimensions() const
|
||||
{
|
||||
osg::Texture2D *texture = !_src_canvas.expired()
|
||||
? _src_canvas.lock()->getTexture()
|
||||
: _texture.get();
|
||||
|
||||
if( !texture )
|
||||
return Rect<int>();
|
||||
|
||||
return Rect<int>
|
||||
(
|
||||
0,0,
|
||||
texture->getTextureWidth(),
|
||||
texture->getTextureHeight()
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
89
simgear/canvas/elements/CanvasImage.hxx
Normal file
89
simgear/canvas/elements/CanvasImage.hxx
Normal file
@@ -0,0 +1,89 @@
|
||||
// An image on the Canvas
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef CANVAS_IMAGE_HXX_
|
||||
#define CANVAS_IMAGE_HXX_
|
||||
|
||||
#include "CanvasElement.hxx"
|
||||
|
||||
#include <simgear/canvas/canvas_fwd.hxx>
|
||||
#include <simgear/math/Rect.hxx>
|
||||
#include <osg/Texture2D>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
class Image:
|
||||
public Element
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @param node Property node containing settings for this image:
|
||||
* rect/[left/right/top/bottom] Dimensions of source
|
||||
* rect
|
||||
* size[0-1] Dimensions of rectangle
|
||||
* [x,y] Position of rectangle
|
||||
*/
|
||||
Image( const CanvasWeakPtr& canvas,
|
||||
SGPropertyNode_ptr node,
|
||||
const Style& parent_style );
|
||||
virtual ~Image();
|
||||
|
||||
virtual void update(double dt);
|
||||
|
||||
void setSrcCanvas(CanvasPtr canvas);
|
||||
CanvasWeakPtr getSrcCanvas() const;
|
||||
|
||||
void setImage(osg::Image *img);
|
||||
void setFill(const std::string& fill);
|
||||
|
||||
const Rect<float>& getRegion() const;
|
||||
|
||||
protected:
|
||||
|
||||
enum ImageAttributes
|
||||
{
|
||||
SRC_RECT = LAST_ATTRIBUTE << 1, // Source image rectangle
|
||||
DEST_SIZE = SRC_RECT << 1 // Element size
|
||||
};
|
||||
|
||||
virtual void childChanged(SGPropertyNode * child);
|
||||
|
||||
void setupDefaultDimensions();
|
||||
Rect<int> getTextureDimensions() const;
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> _texture;
|
||||
// TODO optionally forward events to canvas
|
||||
CanvasWeakPtr _src_canvas;
|
||||
|
||||
osg::ref_ptr<osg::Geometry> _geom;
|
||||
osg::ref_ptr<osg::Vec3Array> _vertices;
|
||||
osg::ref_ptr<osg::Vec2Array> _texCoords;
|
||||
osg::ref_ptr<osg::Vec4Array> _colors;
|
||||
|
||||
SGPropertyNode *_node_src_rect;
|
||||
Rect<float> _src_rect,
|
||||
_region;
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace canvas
|
||||
|
||||
#endif /* CANVAS_IMAGE_HXX_ */
|
||||
230
simgear/canvas/elements/CanvasMap.cxx
Normal file
230
simgear/canvas/elements/CanvasMap.cxx
Normal file
@@ -0,0 +1,230 @@
|
||||
// A group of 2D Canvas elements which get automatically transformed according
|
||||
// to the map parameters.
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "CanvasMap.hxx"
|
||||
#include "map/geo_node_pair.hxx"
|
||||
#include "map/projection.hxx"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
#define LOG_GEO_RET(msg) \
|
||||
{\
|
||||
SG_LOG\
|
||||
(\
|
||||
SG_GENERAL,\
|
||||
SG_WARN,\
|
||||
msg << " (" << child->getStringValue()\
|
||||
<< ", " << child->getPath() << ")"\
|
||||
);\
|
||||
return;\
|
||||
}
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
const std::string GEO = "-geo";
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Map::Map( const CanvasWeakPtr& canvas,
|
||||
SGPropertyNode_ptr node,
|
||||
const Style& parent_style ):
|
||||
Group(canvas, node, parent_style),
|
||||
// TODO make projection configurable
|
||||
_projection(new SansonFlamsteedProjection),
|
||||
_projection_dirty(true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Map::~Map()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::update(double dt)
|
||||
{
|
||||
for( GeoNodes::iterator it = _geo_nodes.begin();
|
||||
it != _geo_nodes.end();
|
||||
++it )
|
||||
{
|
||||
GeoNodePair* geo_node = it->second.get();
|
||||
if( !geo_node->isComplete()
|
||||
|| (!geo_node->isDirty() && !_projection_dirty) )
|
||||
continue;
|
||||
|
||||
GeoCoord lat = parseGeoCoord(geo_node->getLat());
|
||||
if( lat.type != GeoCoord::LATITUDE )
|
||||
continue;
|
||||
|
||||
GeoCoord lon = parseGeoCoord(geo_node->getLon());
|
||||
if( lon.type != GeoCoord::LONGITUDE )
|
||||
continue;
|
||||
|
||||
Projection::ScreenPosition pos =
|
||||
_projection->worldToScreen(lat.value, lon.value);
|
||||
|
||||
geo_node->setScreenPos(pos.x, pos.y);
|
||||
|
||||
// geo_node->print();
|
||||
geo_node->setDirty(false);
|
||||
}
|
||||
_projection_dirty = false;
|
||||
|
||||
Group::update(dt);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
|
||||
{
|
||||
if( !boost::ends_with(child->getNameString(), GEO) )
|
||||
return Element::childAdded(parent, child);
|
||||
|
||||
_geo_nodes[child].reset(new GeoNodePair());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
|
||||
{
|
||||
if( !boost::ends_with(child->getNameString(), GEO) )
|
||||
return Element::childRemoved(parent, child);
|
||||
|
||||
// TODO remove from other node
|
||||
_geo_nodes.erase(child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::valueChanged(SGPropertyNode * child)
|
||||
{
|
||||
const std::string& name = child->getNameString();
|
||||
|
||||
if( !boost::ends_with(name, GEO) )
|
||||
return Group::valueChanged(child);
|
||||
|
||||
GeoNodes::iterator it_geo_node = _geo_nodes.find(child);
|
||||
if( it_geo_node == _geo_nodes.end() )
|
||||
LOG_GEO_RET("geo node not found!")
|
||||
GeoNodePair* geo_node = it_geo_node->second.get();
|
||||
|
||||
geo_node->setDirty();
|
||||
|
||||
if( geo_node->getStatus() & GeoNodePair::INCOMPLETE )
|
||||
{
|
||||
// Detect lat, lon tuples...
|
||||
GeoCoord coord = parseGeoCoord(child->getStringValue());
|
||||
int index_other = -1;
|
||||
|
||||
switch( coord.type )
|
||||
{
|
||||
case GeoCoord::LATITUDE:
|
||||
index_other = child->getIndex() + 1;
|
||||
geo_node->setNodeLat(child);
|
||||
break;
|
||||
case GeoCoord::LONGITUDE:
|
||||
index_other = child->getIndex() - 1;
|
||||
geo_node->setNodeLon(child);
|
||||
break;
|
||||
default:
|
||||
LOG_GEO_RET("Invalid geo coord")
|
||||
}
|
||||
|
||||
SGPropertyNode *other = child->getParent()->getChild(name, index_other);
|
||||
if( !other )
|
||||
return;
|
||||
|
||||
GeoCoord coord_other = parseGeoCoord(other->getStringValue());
|
||||
if( coord_other.type == GeoCoord::INVALID
|
||||
|| coord_other.type == coord.type )
|
||||
return;
|
||||
|
||||
GeoNodes::iterator it_geo_node_other = _geo_nodes.find(other);
|
||||
if( it_geo_node_other == _geo_nodes.end() )
|
||||
LOG_GEO_RET("other geo node not found!")
|
||||
GeoNodePair* geo_node_other = it_geo_node_other->second.get();
|
||||
|
||||
// Let use both nodes use the same GeoNodePair instance
|
||||
if( geo_node_other != geo_node )
|
||||
it_geo_node_other->second = it_geo_node->second;
|
||||
|
||||
if( coord_other.type == GeoCoord::LATITUDE )
|
||||
geo_node->setNodeLat(other);
|
||||
else
|
||||
geo_node->setNodeLon(other);
|
||||
|
||||
// Set name for resulting screen coordinate nodes
|
||||
geo_node->setTargetName( name.substr(0, name.length() - GEO.length()) );
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::childChanged(SGPropertyNode * child)
|
||||
{
|
||||
if( child->getParent() != _node )
|
||||
return Group::childChanged(child);
|
||||
|
||||
if( child->getNameString() == "ref-lat"
|
||||
|| child->getNameString() == "ref-lon" )
|
||||
_projection->setWorldPosition( _node->getDoubleValue("ref-lat"),
|
||||
_node->getDoubleValue("ref-lon") );
|
||||
else if( child->getNameString() == "hdg" )
|
||||
_projection->setOrientation(child->getFloatValue());
|
||||
else if( child->getNameString() == "range" )
|
||||
_projection->setRange(child->getDoubleValue());
|
||||
else
|
||||
return Group::childChanged(child);
|
||||
|
||||
_projection_dirty = true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Map::GeoCoord Map::parseGeoCoord(const std::string& val) const
|
||||
{
|
||||
GeoCoord coord;
|
||||
if( val.length() < 2 )
|
||||
return coord;
|
||||
|
||||
if( val[0] == 'N' || val[0] == 'S' )
|
||||
coord.type = GeoCoord::LATITUDE;
|
||||
else if( val[0] == 'E' || val[0] == 'W' )
|
||||
coord.type = GeoCoord::LONGITUDE;
|
||||
else
|
||||
return coord;
|
||||
|
||||
char* end;
|
||||
coord.value = strtod(&val[1], &end);
|
||||
|
||||
if( end != &val[val.length()] )
|
||||
{
|
||||
coord.type = GeoCoord::INVALID;
|
||||
return coord;
|
||||
}
|
||||
|
||||
if( val[0] == 'S' || val[0] == 'W' )
|
||||
coord.value *= -1;
|
||||
|
||||
return coord;
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
82
simgear/canvas/elements/CanvasMap.hxx
Normal file
82
simgear/canvas/elements/CanvasMap.hxx
Normal file
@@ -0,0 +1,82 @@
|
||||
// A group of 2D Canvas elements which get automatically transformed according
|
||||
// to the map parameters.
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef CANVAS_MAP_HXX_
|
||||
#define CANVAS_MAP_HXX_
|
||||
|
||||
#include "CanvasGroup.hxx"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
class GeoNodePair;
|
||||
class HorizontalProjection;
|
||||
class Map:
|
||||
public Group
|
||||
{
|
||||
public:
|
||||
Map( const CanvasWeakPtr& canvas,
|
||||
SGPropertyNode_ptr node,
|
||||
const Style& parent_style );
|
||||
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 childChanged(SGPropertyNode * child);
|
||||
|
||||
typedef boost::unordered_map< SGPropertyNode*,
|
||||
boost::shared_ptr<GeoNodePair>
|
||||
> GeoNodes;
|
||||
GeoNodes _geo_nodes;
|
||||
boost::shared_ptr<HorizontalProjection> _projection;
|
||||
bool _projection_dirty;
|
||||
|
||||
struct GeoCoord
|
||||
{
|
||||
GeoCoord():
|
||||
type(INVALID)
|
||||
{}
|
||||
enum
|
||||
{
|
||||
INVALID,
|
||||
LATITUDE,
|
||||
LONGITUDE
|
||||
} type;
|
||||
double value;
|
||||
};
|
||||
|
||||
GeoCoord parseGeoCoord(const std::string& val) const;
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* CANVAS_MAP_HXX_ */
|
||||
439
simgear/canvas/elements/CanvasPath.cxx
Normal file
439
simgear/canvas/elements/CanvasPath.cxx
Normal file
@@ -0,0 +1,439 @@
|
||||
// An OpenVG path on the Canvas
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "CanvasPath.hxx"
|
||||
#include <simgear/misc/parse_color.hxx>
|
||||
|
||||
#include <osg/Drawable>
|
||||
#include <osg/BlendFunc>
|
||||
|
||||
#include <vg/openvg.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
typedef std::vector<VGubyte> CmdList;
|
||||
typedef std::vector<VGfloat> CoordList;
|
||||
|
||||
/**
|
||||
* Helper to split and convert comma/whitespace separated floating point
|
||||
* values
|
||||
*/
|
||||
std::vector<float> splitAndConvert(const char del[], const std::string& str);
|
||||
|
||||
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)
|
||||
{
|
||||
setSupportsDisplayList(false);
|
||||
setDataVariance(Object::DYNAMIC);
|
||||
|
||||
setUpdateCallback(new PathUpdateCallback());
|
||||
}
|
||||
|
||||
virtual ~PathDrawable()
|
||||
{
|
||||
if( _path != VG_INVALID_HANDLE )
|
||||
vgDestroyPath(_path);
|
||||
if( _paint != VG_INVALID_HANDLE )
|
||||
vgDestroyPaint(_paint);
|
||||
if( _paint_fill != VG_INVALID_HANDLE )
|
||||
vgDestroyPaint(_paint_fill);
|
||||
}
|
||||
|
||||
virtual const char* className() const { return "PathDrawable"; }
|
||||
virtual osg::Object* cloneType() const { return new PathDrawable(_path_element); }
|
||||
virtual osg::Object* clone(const osg::CopyOp&) const { return new PathDrawable(_path_element); }
|
||||
|
||||
/**
|
||||
* Replace the current path segments with the new ones
|
||||
*
|
||||
* @param cmds List of OpenVG path commands
|
||||
* @param coords List of coordinates/parameters used by #cmds
|
||||
*/
|
||||
void setSegments(const CmdList& cmds, const CoordList& coords)
|
||||
{
|
||||
_cmds = cmds;
|
||||
_coords = coords;
|
||||
|
||||
_attributes_dirty |= (PATH | BOUNDING_BOX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set path fill paint ("none" if not filled)
|
||||
*/
|
||||
void setFill(const std::string& fill)
|
||||
{
|
||||
if( fill == "none" )
|
||||
{
|
||||
_mode &= ~VG_FILL_PATH;
|
||||
}
|
||||
else if( parseColor(fill, _fill_color) )
|
||||
{
|
||||
_mode |= VG_FILL_PATH;
|
||||
_attributes_dirty |= FILL_COLOR;
|
||||
}
|
||||
else
|
||||
{
|
||||
SG_LOG
|
||||
(
|
||||
SG_GENERAL,
|
||||
SG_WARN,
|
||||
"canvas::Path Unknown fill: " << fill
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set path fill rule ("pseudo-nonzero" or "evenodd")
|
||||
*
|
||||
* @warning As the current nonzero implementation causes sever artifacts
|
||||
* for every concave path we call it pseudo-nonzero, so that
|
||||
* everyone is warned that it won't work as expected :)
|
||||
*/
|
||||
void setFillRule(const std::string& fill_rule)
|
||||
{
|
||||
if( fill_rule == "pseudo-nonzero" )
|
||||
_fill_rule = VG_NON_ZERO;
|
||||
else // if( fill_rule == "evenodd" )
|
||||
_fill_rule = VG_EVEN_ODD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set path stroke paint ("none" if no stroke)
|
||||
*/
|
||||
void setStroke(const std::string& stroke)
|
||||
{
|
||||
if( stroke == "none" )
|
||||
{
|
||||
_mode &= ~VG_STROKE_PATH;
|
||||
}
|
||||
else if( parseColor(stroke, _stroke_color) )
|
||||
{
|
||||
_mode |= VG_STROKE_PATH;
|
||||
_attributes_dirty |= STROKE_COLOR;
|
||||
}
|
||||
else
|
||||
{
|
||||
SG_LOG
|
||||
(
|
||||
SG_GENERAL,
|
||||
SG_WARN,
|
||||
"canvas::Path Unknown stroke: " << stroke
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set stroke width
|
||||
*/
|
||||
void setStrokeWidth(float width)
|
||||
{
|
||||
_stroke_width = width;
|
||||
_attributes_dirty |= BOUNDING_BOX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set stroke dash (line stipple)
|
||||
*/
|
||||
void setStrokeDashArray(const std::string& dash)
|
||||
{
|
||||
_stroke_dash = splitAndConvert(",\t\n ", dash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set stroke-linecap
|
||||
*
|
||||
* @see http://www.w3.org/TR/SVG/painting.html#StrokeLinecapProperty
|
||||
*/
|
||||
void setStrokeLinecap(const std::string& linecap)
|
||||
{
|
||||
if( linecap == "round" )
|
||||
_stroke_linecap = VG_CAP_ROUND;
|
||||
else if( linecap == "square" )
|
||||
_stroke_linecap = VG_CAP_SQUARE;
|
||||
else
|
||||
_stroke_linecap = VG_CAP_BUTT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw callback
|
||||
*/
|
||||
virtual void drawImplementation(osg::RenderInfo& renderInfo) const
|
||||
{
|
||||
if( _attributes_dirty & PATH )
|
||||
return;
|
||||
|
||||
osg::State* state = renderInfo.getState();
|
||||
assert(state);
|
||||
|
||||
state->setActiveTextureUnit(0);
|
||||
state->setClientActiveTextureUnit(0);
|
||||
state->disableAllVertexArrays();
|
||||
|
||||
glPushAttrib(~0u); // Don't use GL_ALL_ATTRIB_BITS as on my machine it
|
||||
// eg. doesn't include GL_MULTISAMPLE_BIT
|
||||
glPushClientAttrib(~0u);
|
||||
|
||||
// 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 )
|
||||
{
|
||||
vgSetPaint(_paint, VG_STROKE_PATH);
|
||||
|
||||
vgSetf(VG_STROKE_LINE_WIDTH, _stroke_width);
|
||||
vgSeti(VG_STROKE_CAP_STYLE, _stroke_linecap);
|
||||
vgSetfv( VG_STROKE_DASH_PATTERN,
|
||||
_stroke_dash.size(),
|
||||
_stroke_dash.empty() ? 0 : &_stroke_dash[0] );
|
||||
}
|
||||
if( _mode & VG_FILL_PATH )
|
||||
{
|
||||
vgSetPaint(_paint_fill, VG_FILL_PATH);
|
||||
|
||||
vgSeti(VG_FILL_RULE, _fill_rule);
|
||||
}
|
||||
|
||||
// And finally draw the path
|
||||
if( _mode )
|
||||
vgDrawPath(_path, _mode);
|
||||
|
||||
VGErrorCode err = vgGetError();
|
||||
if( err != VG_NO_ERROR )
|
||||
SG_LOG(SG_GL, SG_ALERT, "vgError: " << err);
|
||||
|
||||
glPopAttrib();
|
||||
glPopClientAttrib();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the bounding box
|
||||
*/
|
||||
virtual osg::BoundingBox computeBound() const
|
||||
{
|
||||
if( _path == VG_INVALID_HANDLE || (_attributes_dirty & PATH) )
|
||||
return osg::BoundingBox();
|
||||
|
||||
VGfloat min[2], size[2];
|
||||
vgPathBounds(_path, &min[0], &min[1], &size[0], &size[1]);
|
||||
|
||||
_attributes_dirty &= ~BOUNDING_BOX;
|
||||
|
||||
// vgPathBounds doesn't take stroke width into account
|
||||
float ext = 0.5 * _stroke_width;
|
||||
|
||||
osg::BoundingBox bb
|
||||
(
|
||||
min[0] - ext, min[1] - ext, -0.1,
|
||||
min[0] + size[0] + ext, min[1] + size[1] + ext, 0.1
|
||||
);
|
||||
_path_element->setBoundingBox(bb);
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
enum Attributes
|
||||
{
|
||||
PATH = 0x0001,
|
||||
STROKE_COLOR = PATH << 1,
|
||||
FILL_COLOR = STROKE_COLOR << 1,
|
||||
BOUNDING_BOX = FILL_COLOR << 1
|
||||
};
|
||||
|
||||
Path *_path_element;
|
||||
|
||||
mutable VGPath _path;
|
||||
mutable VGPaint _paint;
|
||||
mutable VGPaint _paint_fill;
|
||||
mutable uint32_t _attributes_dirty;
|
||||
|
||||
CmdList _cmds;
|
||||
CoordList _coords;
|
||||
|
||||
VGbitfield _mode;
|
||||
osg::Vec4f _fill_color;
|
||||
VGFillRule _fill_rule;
|
||||
osg::Vec4f _stroke_color;
|
||||
VGfloat _stroke_width;
|
||||
std::vector<VGfloat> _stroke_dash;
|
||||
VGCapStyle _stroke_linecap;
|
||||
|
||||
/**
|
||||
* Initialize/Update the OpenVG path
|
||||
*/
|
||||
void update()
|
||||
{
|
||||
if( _attributes_dirty & PATH )
|
||||
{
|
||||
const VGbitfield caps = VG_PATH_CAPABILITY_APPEND_TO
|
||||
| VG_PATH_CAPABILITY_MODIFY
|
||||
| VG_PATH_CAPABILITY_PATH_BOUNDS;
|
||||
|
||||
if( _path == VG_INVALID_HANDLE )
|
||||
_path = vgCreatePath(
|
||||
VG_PATH_FORMAT_STANDARD,
|
||||
VG_PATH_DATATYPE_F,
|
||||
1.f, 0.f, // scale,bias
|
||||
_cmds.size(), _coords.size(),
|
||||
caps
|
||||
);
|
||||
else
|
||||
vgClearPath(_path, caps);
|
||||
|
||||
if( !_cmds.empty() && !_coords.empty() )
|
||||
vgAppendPathData(_path, _cmds.size(), &_cmds[0], &_coords[0]);
|
||||
|
||||
_attributes_dirty &= ~PATH;
|
||||
_attributes_dirty |= BOUNDING_BOX;
|
||||
}
|
||||
|
||||
if( _attributes_dirty & BOUNDING_BOX )
|
||||
dirtyBound();
|
||||
}
|
||||
|
||||
struct PathUpdateCallback:
|
||||
public osg::Drawable::UpdateCallback
|
||||
{
|
||||
virtual void update(osg::NodeVisitor*, osg::Drawable* drawable)
|
||||
{
|
||||
static_cast<PathDrawable*>(drawable)->update();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Path::Path( const CanvasWeakPtr& canvas,
|
||||
SGPropertyNode_ptr node,
|
||||
const Style& parent_style ):
|
||||
Element(canvas, node, parent_style),
|
||||
_path( new PathDrawable(this) )
|
||||
{
|
||||
setDrawable(_path);
|
||||
PathDrawable *path = _path.get();
|
||||
|
||||
addStyle("fill", &PathDrawable::setFill, path);
|
||||
addStyle("fill-rule", &PathDrawable::setFillRule, path);
|
||||
addStyle("stroke", &PathDrawable::setStroke, path);
|
||||
addStyle("stroke-width", &PathDrawable::setStrokeWidth, path);
|
||||
addStyle("stroke-dasharray", &PathDrawable::setStrokeDashArray, path);
|
||||
addStyle("stroke-linecap", &PathDrawable::setStrokeLinecap, path);
|
||||
|
||||
setupStyle();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Path::~Path()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
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);
|
||||
}
|
||||
|
||||
Element::update(dt);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Path::childRemoved(SGPropertyNode* child)
|
||||
{
|
||||
childChanged(child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Path::childChanged(SGPropertyNode* child)
|
||||
{
|
||||
if( child->getParent() != _node )
|
||||
return;
|
||||
|
||||
if( child->getNameString() == "cmd" )
|
||||
_attributes_dirty |= CMDS;
|
||||
else if( child->getNameString() == "coord" )
|
||||
_attributes_dirty |= COORDS;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::vector<float> splitAndConvert(const char del[], const std::string& str)
|
||||
{
|
||||
std::vector<float> values;
|
||||
size_t pos = 0;
|
||||
for(;;)
|
||||
{
|
||||
pos = str.find_first_not_of(del, pos);
|
||||
if( pos == std::string::npos )
|
||||
break;
|
||||
|
||||
char *end = 0;
|
||||
float val = strtod(&str[pos], &end);
|
||||
if( end == &str[pos] || !end )
|
||||
break;
|
||||
|
||||
values.push_back(val);
|
||||
pos = end - &str[0];
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
57
simgear/canvas/elements/CanvasPath.hxx
Normal file
57
simgear/canvas/elements/CanvasPath.hxx
Normal file
@@ -0,0 +1,57 @@
|
||||
// An OpenVG path on the Canvas
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef CANVAS_PATH_HXX_
|
||||
#define CANVAS_PATH_HXX_
|
||||
|
||||
#include "CanvasElement.hxx"
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
class Path:
|
||||
public Element
|
||||
{
|
||||
public:
|
||||
Path( const CanvasWeakPtr& canvas,
|
||||
SGPropertyNode_ptr node,
|
||||
const Style& parent_style );
|
||||
virtual ~Path();
|
||||
|
||||
virtual void update(double dt);
|
||||
|
||||
protected:
|
||||
|
||||
enum PathAttributes
|
||||
{
|
||||
CMDS = LAST_ATTRIBUTE << 1,
|
||||
COORDS = CMDS << 1
|
||||
};
|
||||
|
||||
class PathDrawable;
|
||||
osg::ref_ptr<PathDrawable> _path;
|
||||
|
||||
virtual void childRemoved(SGPropertyNode * child);
|
||||
virtual void childChanged(SGPropertyNode * child);
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* CANVAS_PATH_HXX_ */
|
||||
291
simgear/canvas/elements/CanvasText.cxx
Normal file
291
simgear/canvas/elements/CanvasText.cxx
Normal file
@@ -0,0 +1,291 @@
|
||||
// A text on the Canvas
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "CanvasText.hxx"
|
||||
#include <simgear/canvas/Canvas.hxx>
|
||||
#include <simgear/canvas/CanvasSystemAdapter.hxx>
|
||||
#include <simgear/misc/parse_color.hxx>
|
||||
#include <osgText/Text>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
class Text::TextOSG:
|
||||
public osgText::Text
|
||||
{
|
||||
public:
|
||||
|
||||
TextOSG(canvas::Text* text);
|
||||
|
||||
void setCharacterAspect(float aspect);
|
||||
void setFill(const std::string& fill);
|
||||
void setBackgroundColor(const std::string& fill);
|
||||
|
||||
osg::Vec2 handleHit(float x, float y);
|
||||
|
||||
virtual osg::BoundingBox computeBound() const;
|
||||
|
||||
protected:
|
||||
|
||||
canvas::Text *_text_element;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Text::TextOSG::TextOSG(canvas::Text* text):
|
||||
_text_element(text)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::TextOSG::setCharacterAspect(float aspect)
|
||||
{
|
||||
setCharacterSize(getCharacterHeight(), aspect);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::TextOSG::setFill(const std::string& fill)
|
||||
{
|
||||
// if( fill == "none" )
|
||||
// TODO No text
|
||||
// else
|
||||
osg::Vec4 color;
|
||||
if( parseColor(fill, color) )
|
||||
setColor( color );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::TextOSG::setBackgroundColor(const std::string& fill)
|
||||
{
|
||||
osg::Vec4 color;
|
||||
if( parseColor(fill, color) )
|
||||
setBoundingBoxColor( color );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::Vec2 Text::TextOSG::handleHit(float x, float y)
|
||||
{
|
||||
float line_height = _characterHeight + _lineSpacing;
|
||||
|
||||
// TODO check with align other than TOP
|
||||
float first_line_y = -0.5 * _lineSpacing;//_offset.y() - _characterHeight;
|
||||
size_t line = std::max<int>(0, (y - first_line_y) / line_height);
|
||||
|
||||
if( _textureGlyphQuadMap.empty() )
|
||||
return osg::Vec2(-1, -1);
|
||||
|
||||
// TODO check when it can be larger
|
||||
assert( _textureGlyphQuadMap.size() == 1 );
|
||||
|
||||
const GlyphQuads& glyphquad = _textureGlyphQuadMap.begin()->second;
|
||||
const GlyphQuads::Glyphs& glyphs = glyphquad._glyphs;
|
||||
const GlyphQuads::Coords2& coords = glyphquad._coords;
|
||||
const GlyphQuads::LineNumbers& line_numbers = glyphquad._lineNumbers;
|
||||
|
||||
const float HIT_FRACTION = 0.6;
|
||||
const float character_width = getCharacterHeight()
|
||||
* getCharacterAspectRatio();
|
||||
|
||||
y = (line + 0.5) * line_height;
|
||||
|
||||
bool line_found = false;
|
||||
for(size_t i = 0; i < line_numbers.size(); ++i)
|
||||
{
|
||||
if( line_numbers[i] != line )
|
||||
{
|
||||
if( !line_found )
|
||||
{
|
||||
if( line_numbers[i] < line )
|
||||
// Wait for the correct line...
|
||||
continue;
|
||||
|
||||
// We have already passed the correct line -> It's empty...
|
||||
return osg::Vec2(0, y);
|
||||
}
|
||||
|
||||
// Next line and not returned -> not before any character
|
||||
// -> return position after last character of line
|
||||
return osg::Vec2(coords[(i - 1) * 4 + 2].x(), y);
|
||||
}
|
||||
|
||||
line_found = true;
|
||||
|
||||
// Get threshold for mouse x position for setting cursor before or after
|
||||
// current character
|
||||
float threshold = coords[i * 4].x()
|
||||
+ HIT_FRACTION * glyphs[i]->getHorizontalAdvance()
|
||||
* character_width;
|
||||
|
||||
if( x <= threshold )
|
||||
{
|
||||
if( i == 0 || line_numbers[i - 1] != line )
|
||||
// first character of line
|
||||
x = coords[i * 4].x();
|
||||
else if( coords[(i - 1) * 4].x() == coords[(i - 1) * 4 + 2].x() )
|
||||
// If previous character width is zero set to begin of next character
|
||||
// (Happens eg. with spaces)
|
||||
x = coords[i * 4].x();
|
||||
else
|
||||
// position at center between characters
|
||||
x = 0.5 * (coords[(i - 1) * 4 + 2].x() + coords[i * 4].x());
|
||||
|
||||
return osg::Vec2(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing found -> return position after last character
|
||||
return osg::Vec2
|
||||
(
|
||||
coords.back().x(),
|
||||
(_lineCount - 0.5) * line_height
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::BoundingBox Text::TextOSG::computeBound() const
|
||||
{
|
||||
osg::BoundingBox bb = osgText::Text::computeBound();
|
||||
if( !bb.valid() )
|
||||
return bb;
|
||||
|
||||
// TODO bounding box still doesn't seem always right (eg. with center
|
||||
// horizontal alignment not completely accurate)
|
||||
bb._min.y() += _offset.y();
|
||||
bb._max.y() += _offset.y();
|
||||
|
||||
_text_element->setBoundingBox(bb);
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Text::Text( const CanvasWeakPtr& canvas,
|
||||
SGPropertyNode_ptr node,
|
||||
const Style& parent_style ):
|
||||
Element(canvas, node, parent_style),
|
||||
_text( new Text::TextOSG(this) )
|
||||
{
|
||||
setDrawable(_text);
|
||||
_text->setCharacterSizeMode(osgText::Text::OBJECT_COORDS);
|
||||
_text->setAxisAlignment(osgText::Text::USER_DEFINED_ROTATION);
|
||||
_text->setRotation(osg::Quat(osg::PI, osg::X_AXIS));
|
||||
|
||||
addStyle("fill", &TextOSG::setFill, _text);
|
||||
addStyle("background", &TextOSG::setBackgroundColor, _text);
|
||||
addStyle("character-size",
|
||||
static_cast<void (TextOSG::*)(float)>(&TextOSG::setCharacterSize),
|
||||
_text);
|
||||
addStyle("character-aspect-ratio", &TextOSG::setCharacterAspect, _text);
|
||||
addStyle("padding", &TextOSG::setBoundingBoxMargin, _text);
|
||||
// TEXT = 1 default
|
||||
// BOUNDINGBOX = 2
|
||||
// FILLEDBOUNDINGBOX = 4
|
||||
// ALIGNMENT = 8
|
||||
addStyle<int>("draw-mode", &TextOSG::setDrawMode, _text);
|
||||
addStyle("max-width", &TextOSG::setMaximumWidth, _text);
|
||||
addStyle("font", &Text::setFont, this);
|
||||
addStyle("alignment", &Text::setAlignment, this);
|
||||
addStyle("text", &Text::setText, this);
|
||||
|
||||
setupStyle();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Text::~Text()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::setText(const char* text)
|
||||
{
|
||||
_text->setText(text, osgText::String::ENCODING_UTF8);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::setFont(const char* name)
|
||||
{
|
||||
_text->setFont( _canvas.lock()->getSystemAdapter()->getFont(name) );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::setAlignment(const char* align)
|
||||
{
|
||||
const std::string align_string(align);
|
||||
if( 0 ) return;
|
||||
#define ENUM_MAPPING(enum_val, string_val) \
|
||||
else if( align_string == string_val )\
|
||||
_text->setAlignment( osgText::Text::enum_val );
|
||||
#include "text-alignment.hxx"
|
||||
#undef ENUM_MAPPING
|
||||
else
|
||||
{
|
||||
if( !align_string.empty() )
|
||||
SG_LOG
|
||||
(
|
||||
SG_GENERAL,
|
||||
SG_WARN,
|
||||
"canvas::Text: unknown alignment '" << align_string << "'"
|
||||
);
|
||||
_text->setAlignment(osgText::Text::LEFT_BASE_LINE);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#if 0
|
||||
const char* Text::getAlignment() const
|
||||
{
|
||||
switch( _text->getAlignment() )
|
||||
{
|
||||
#define ENUM_MAPPING(enum_val, string_val) \
|
||||
case osgText::Text::enum_val:\
|
||||
return string_val;
|
||||
#include "text-alignment.hxx"
|
||||
#undef ENUM_MAPPING
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::childChanged(SGPropertyNode* child)
|
||||
{
|
||||
if( child->getParent() != _node )
|
||||
return;
|
||||
|
||||
const std::string& name = child->getNameString();
|
||||
if( name == "hit-y" )
|
||||
handleHit
|
||||
(
|
||||
_node->getFloatValue("hit-x"),
|
||||
_node->getFloatValue("hit-y")
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::handleHit(float x, float y)
|
||||
{
|
||||
const osg::Vec2& pos = _text->handleHit(x, y);
|
||||
_node->setFloatValue("cursor-x", pos.x());
|
||||
_node->setFloatValue("cursor-y", pos.y());
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
59
simgear/canvas/elements/CanvasText.hxx
Normal file
59
simgear/canvas/elements/CanvasText.hxx
Normal file
@@ -0,0 +1,59 @@
|
||||
// A text on the Canvas
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef CANVAS_TEXT_HXX_
|
||||
#define CANVAS_TEXT_HXX_
|
||||
|
||||
#include "CanvasElement.hxx"
|
||||
#include <osgText/Text>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
class Text:
|
||||
public Element
|
||||
{
|
||||
public:
|
||||
Text( const CanvasWeakPtr& canvas,
|
||||
SGPropertyNode_ptr node,
|
||||
const Style& parent_style );
|
||||
~Text();
|
||||
|
||||
void setText(const char* text);
|
||||
void setFont(const char* name);
|
||||
void setAlignment(const char* align);
|
||||
|
||||
protected:
|
||||
|
||||
class TextOSG;
|
||||
osg::ref_ptr<TextOSG> _text;
|
||||
|
||||
virtual void childChanged(SGPropertyNode * child);
|
||||
|
||||
void handleHit(float x, float y);
|
||||
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* CANVAS_TEXT_HXX_ */
|
||||
134
simgear/canvas/elements/map/geo_node_pair.hxx
Normal file
134
simgear/canvas/elements/map/geo_node_pair.hxx
Normal file
@@ -0,0 +1,134 @@
|
||||
// Groups together two nodes representing a geographic position (lat + lon)
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef CANVAS_GEO_NODE_PAIR_HXX_
|
||||
#define CANVAS_GEO_NODE_PAIR_HXX_
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
class GeoNodePair
|
||||
{
|
||||
public:
|
||||
enum StatusFlags
|
||||
{
|
||||
LAT_MISSING = 1,
|
||||
LON_MISSING = LAT_MISSING << 1,
|
||||
INCOMPLETE = LAT_MISSING | LON_MISSING,
|
||||
DIRTY = LON_MISSING << 1
|
||||
};
|
||||
|
||||
GeoNodePair():
|
||||
_status(INCOMPLETE),
|
||||
_node_lat(0),
|
||||
_node_lon(0)
|
||||
{}
|
||||
|
||||
uint8_t getStatus() const
|
||||
{
|
||||
return _status;
|
||||
}
|
||||
|
||||
void setDirty(bool flag = true)
|
||||
{
|
||||
if( flag )
|
||||
_status |= DIRTY;
|
||||
else
|
||||
_status &= ~DIRTY;
|
||||
}
|
||||
|
||||
bool isDirty() const
|
||||
{
|
||||
return (_status & DIRTY)!=0;
|
||||
}
|
||||
|
||||
bool isComplete() const
|
||||
{
|
||||
return !(_status & INCOMPLETE);
|
||||
}
|
||||
|
||||
void setNodeLat(SGPropertyNode* node)
|
||||
{
|
||||
_node_lat = node;
|
||||
_status &= ~LAT_MISSING;
|
||||
|
||||
if( node == _node_lon )
|
||||
{
|
||||
_node_lon = 0;
|
||||
_status |= LON_MISSING;
|
||||
}
|
||||
}
|
||||
|
||||
void setNodeLon(SGPropertyNode* node)
|
||||
{
|
||||
_node_lon = node;
|
||||
_status &= ~LON_MISSING;
|
||||
|
||||
if( node == _node_lat )
|
||||
{
|
||||
_node_lat = 0;
|
||||
_status |= LAT_MISSING;
|
||||
}
|
||||
}
|
||||
|
||||
const char* getLat() const
|
||||
{
|
||||
return _node_lat ? _node_lat->getStringValue() : "";
|
||||
}
|
||||
|
||||
const char* getLon() const
|
||||
{
|
||||
return _node_lon ? _node_lon->getStringValue() : "";
|
||||
}
|
||||
|
||||
void setTargetName(const std::string& name)
|
||||
{
|
||||
_target_name = name;
|
||||
}
|
||||
|
||||
void setScreenPos(float x, float y)
|
||||
{
|
||||
assert( isComplete() );
|
||||
SGPropertyNode *parent = _node_lat->getParent();
|
||||
parent->getChild(_target_name, _node_lat->getIndex(), true)
|
||||
->setDoubleValue(x);
|
||||
parent->getChild(_target_name, _node_lon->getIndex(), true)
|
||||
->setDoubleValue(y);
|
||||
}
|
||||
|
||||
void print()
|
||||
{
|
||||
std::cout << "lat=" << (_node_lat ? _node_lat->getPath() : "")
|
||||
<< ", lon=" << (_node_lon ? _node_lon->getPath() : "")
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint8_t _status;
|
||||
SGPropertyNode *_node_lat,
|
||||
*_node_lon;
|
||||
std::string _target_name;
|
||||
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* CANVAS_GEO_NODE_PAIR_HXX_ */
|
||||
179
simgear/canvas/elements/map/projection.hxx
Normal file
179
simgear/canvas/elements/map/projection.hxx
Normal file
@@ -0,0 +1,179 @@
|
||||
// Geographic projections for Canvas map element
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef CANVAS_MAP_PROJECTION_HXX_
|
||||
#define CANVAS_MAP_PROJECTION_HXX_
|
||||
|
||||
#include <simgear/math/SGMisc.hxx>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
/**
|
||||
* Base class for all projections
|
||||
*/
|
||||
class Projection
|
||||
{
|
||||
public:
|
||||
struct ScreenPosition
|
||||
{
|
||||
ScreenPosition() {}
|
||||
|
||||
ScreenPosition(double x, double y):
|
||||
x(x),
|
||||
y(y)
|
||||
{}
|
||||
|
||||
double x, y;
|
||||
};
|
||||
|
||||
virtual ~Projection() {}
|
||||
|
||||
void setScreenRange(double range)
|
||||
{
|
||||
_screen_range = range;
|
||||
}
|
||||
|
||||
virtual ScreenPosition worldToScreen(double x, double y) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
double _screen_range;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for horizontal projections
|
||||
*/
|
||||
class HorizontalProjection:
|
||||
public Projection
|
||||
{
|
||||
public:
|
||||
|
||||
HorizontalProjection():
|
||||
_cos_rot(1),
|
||||
_sin_rot(0),
|
||||
_range(5)
|
||||
{
|
||||
setScreenRange(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set world position of center point used for the projection
|
||||
*/
|
||||
void setWorldPosition(double lat, double lon)
|
||||
{
|
||||
_ref_lat = SGMiscd::deg2rad(lat);
|
||||
_ref_lon = SGMiscd::deg2rad(lon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up heading
|
||||
*/
|
||||
void setOrientation(float hdg)
|
||||
{
|
||||
hdg = SGMiscf::deg2rad(hdg);
|
||||
_sin_rot = sin(hdg);
|
||||
_cos_rot = cos(hdg);
|
||||
}
|
||||
|
||||
void setRange(double range)
|
||||
{
|
||||
_range = range;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform given world position to screen position
|
||||
*
|
||||
* @param lat Latitude in degrees
|
||||
* @param lon Longitude in degrees
|
||||
*/
|
||||
ScreenPosition worldToScreen(double lat, double lon)
|
||||
{
|
||||
lat = SGMiscd::deg2rad(lat);
|
||||
lon = SGMiscd::deg2rad(lon);
|
||||
ScreenPosition pos = project(lat, lon);
|
||||
double scale = _screen_range / _range;
|
||||
pos.x *= scale;
|
||||
pos.y *= scale;
|
||||
return ScreenPosition
|
||||
(
|
||||
_cos_rot * pos.x - _sin_rot * pos.y,
|
||||
-_sin_rot * pos.x - _cos_rot * pos.y
|
||||
);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Project given geographic world position to screen space
|
||||
*
|
||||
* @param lat Latitude in radians
|
||||
* @param lon Longitude in radians
|
||||
*/
|
||||
virtual ScreenPosition project(double lat, double lon) const = 0;
|
||||
|
||||
double _ref_lat,
|
||||
_ref_lon,
|
||||
_cos_rot,
|
||||
_sin_rot,
|
||||
_range;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sanson-Flamsteed projection, relative to the projection center
|
||||
*/
|
||||
class SansonFlamsteedProjection:
|
||||
public HorizontalProjection
|
||||
{
|
||||
protected:
|
||||
|
||||
virtual ScreenPosition project(double lat, double lon) const
|
||||
{
|
||||
double d_lat = lat - _ref_lat,
|
||||
d_lon = lon - _ref_lon;
|
||||
double r = getEarthRadius(lat);
|
||||
|
||||
ScreenPosition pos;
|
||||
|
||||
pos.x = r * cos(lat) * d_lon;
|
||||
pos.y = r * d_lat;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Earth radius at a given latitude (Ellipsoide equation with two
|
||||
* equal axis)
|
||||
*/
|
||||
float getEarthRadius(float lat) const
|
||||
{
|
||||
const float rec = 6378137.f / 1852; // earth radius, equator (?)
|
||||
const float rpol = 6356752.314f / 1852; // earth radius, polar (?)
|
||||
|
||||
double a = cos(lat) / rec;
|
||||
double b = sin(lat) / rpol;
|
||||
return 1.0f / sqrt( a * a + b * b );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* CANVAS_MAP_PROJECTION_HXX_ */
|
||||
41
simgear/canvas/elements/text-alignment.hxx
Normal file
41
simgear/canvas/elements/text-alignment.hxx
Normal file
@@ -0,0 +1,41 @@
|
||||
// Mapping between strings and osg text alignment flags
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef ENUM_MAPPING
|
||||
# error "Only include with ENUM_MAPPING defined!"
|
||||
#endif
|
||||
|
||||
ENUM_MAPPING(LEFT_TOP, "left-top")
|
||||
ENUM_MAPPING(LEFT_CENTER, "left-center")
|
||||
ENUM_MAPPING(LEFT_BOTTOM, "left-bottom")
|
||||
|
||||
ENUM_MAPPING(CENTER_TOP, "center-top")
|
||||
ENUM_MAPPING(CENTER_CENTER, "center-center")
|
||||
ENUM_MAPPING(CENTER_BOTTOM, "center-bottom")
|
||||
|
||||
ENUM_MAPPING(RIGHT_TOP, "right-top")
|
||||
ENUM_MAPPING(RIGHT_CENTER, "right-center")
|
||||
ENUM_MAPPING(RIGHT_BOTTOM, "right-bottom")
|
||||
|
||||
ENUM_MAPPING(LEFT_BASE_LINE, "left-baseline")
|
||||
ENUM_MAPPING(CENTER_BASE_LINE, "center-baseline")
|
||||
ENUM_MAPPING(RIGHT_BASE_LINE, "right-baseline")
|
||||
|
||||
ENUM_MAPPING(LEFT_BOTTOM_BASE_LINE, "left-bottom-baseline")
|
||||
ENUM_MAPPING(CENTER_BOTTOM_BASE_LINE, "center-bottom-baseline")
|
||||
ENUM_MAPPING(RIGHT_BOTTOM_BASE_LINE, "right-bottom-baseline")
|
||||
@@ -1,7 +1,8 @@
|
||||
include (SimGearComponent)
|
||||
|
||||
|
||||
set(HEADERS
|
||||
set(HEADERS
|
||||
Rect.hxx
|
||||
SGBox.hxx
|
||||
SGCMath.hxx
|
||||
SGGeoc.hxx
|
||||
|
||||
85
simgear/math/Rect.hxx
Normal file
85
simgear/math/Rect.hxx
Normal file
@@ -0,0 +1,85 @@
|
||||
// Class representing a rectangular region
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef SG_RECT_HXX_
|
||||
#define SG_RECT_HXX_
|
||||
|
||||
#include <osg/Vec2>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class Rect
|
||||
{
|
||||
public:
|
||||
Rect():
|
||||
_x1(0),
|
||||
_x2(0),
|
||||
_y1(0),
|
||||
_y2(0)
|
||||
{}
|
||||
|
||||
Rect(T x, T y, T w, T h):
|
||||
_x1(x),
|
||||
_x2(x + w),
|
||||
_y1(y),
|
||||
_y2(y + h)
|
||||
{}
|
||||
|
||||
void set(T x, T y, T w, T h)
|
||||
{
|
||||
_x1 = x;
|
||||
_x2 = x + w;
|
||||
_y1 = y;
|
||||
_y2 = y + h;
|
||||
}
|
||||
|
||||
T x() const { return _x1; }
|
||||
T y() const { return _y1; }
|
||||
T width() const { return _x2 - _x1; }
|
||||
T height() const { return _y2 - _y1; }
|
||||
|
||||
void setX(T x) { T w = width(); _x1 = x; _x2 = x + w; }
|
||||
void setY(T y) { T h = height(); _y1 = y; _y2 = y + h; }
|
||||
void setWidth(T w) { _x2 = _x1 + w; }
|
||||
void setHeight(T h) { _y2 = _y1 + h; }
|
||||
|
||||
T l() const { return _x1; }
|
||||
T r() const { return _x2; }
|
||||
T t() const { return _y1; }
|
||||
T b() const { return _y2; }
|
||||
|
||||
void setLeft(T l) { _x1 = l; }
|
||||
void setRight(T r) { _x2 = r; }
|
||||
void setTop(T t) { _y1 = t; }
|
||||
void setBottom(T b) { _y2 = b; }
|
||||
|
||||
bool contains(T x, T y) const
|
||||
{
|
||||
return _x1 <= x && x <= _x2
|
||||
&& _y1 <= y && y <= _y2;
|
||||
}
|
||||
|
||||
private:
|
||||
T _x1, _x2, _y1, _y2;
|
||||
};
|
||||
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* SG_RECT_HXX_ */
|
||||
@@ -4,6 +4,7 @@ include (SimGearComponent)
|
||||
set(HEADERS
|
||||
ResourceManager.hxx
|
||||
interpolator.hxx
|
||||
parse_color.hxx
|
||||
sg_dir.hxx
|
||||
sg_path.hxx
|
||||
sgstream.hxx
|
||||
@@ -19,6 +20,7 @@ set(HEADERS
|
||||
set(SOURCES
|
||||
ResourceManager.cxx
|
||||
interpolator.cxx
|
||||
parse_color.cxx
|
||||
sg_dir.cxx
|
||||
sg_path.cxx
|
||||
sgstream.cxx
|
||||
@@ -39,6 +41,10 @@ add_executable(test_strings strutils_test.cxx )
|
||||
add_test(test_strings ${EXECUTABLE_OUTPUT_PATH}/test_strings)
|
||||
target_link_libraries(test_strings SimGearCore)
|
||||
|
||||
add_executable(test_parse_color parse_color_test.cxx )
|
||||
add_test(test_parse_color ${EXECUTABLE_OUTPUT_PATH}/test_parse_color)
|
||||
target_link_libraries(test_parse_color SimGearCore)
|
||||
|
||||
add_executable(test_path path_test.cxx )
|
||||
add_test(test_path ${EXECUTABLE_OUTPUT_PATH}/test_path)
|
||||
target_link_libraries(test_path SimGearCore)
|
||||
|
||||
90
simgear/misc/parse_color.cxx
Normal file
90
simgear/misc/parse_color.cxx
Normal file
@@ -0,0 +1,90 @@
|
||||
// Parse CSS colors
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "parse_color.hxx"
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool parseColor(std::string str, osg::Vec4& result)
|
||||
{
|
||||
boost::trim(str);
|
||||
osg::Vec4 color(0,0,0,1);
|
||||
|
||||
if( str.empty() )
|
||||
return false;
|
||||
|
||||
// #rrggbb
|
||||
if( str[0] == '#' )
|
||||
{
|
||||
const int offsets[] = {2,2,2};
|
||||
const boost::offset_separator hex_separator( boost::begin(offsets),
|
||||
boost::end(offsets) );
|
||||
typedef boost::tokenizer<boost::offset_separator> offset_tokenizer;
|
||||
offset_tokenizer tokens(str.begin() + 1, str.end(), hex_separator);
|
||||
|
||||
int comp = 0;
|
||||
for( offset_tokenizer::const_iterator tok = tokens.begin();
|
||||
tok != tokens.end() && comp < 4;
|
||||
++tok, ++comp )
|
||||
{
|
||||
color._v[comp] = strtol(std::string(*tok).c_str(), 0, 16) / 255.f;
|
||||
}
|
||||
}
|
||||
// rgb(r,g,b)
|
||||
// rgba(r,g,b,a)
|
||||
else if( boost::ends_with(str, ")") )
|
||||
{
|
||||
const std::string RGB = "rgb(",
|
||||
RGBA = "rgba(";
|
||||
size_t pos;
|
||||
if( boost::starts_with(str, RGB) )
|
||||
pos = RGB.length();
|
||||
else if( boost::starts_with(str, RGBA) )
|
||||
pos = RGBA.length();
|
||||
else
|
||||
return false;
|
||||
|
||||
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
|
||||
const boost::char_separator<char> del(", \t\n");
|
||||
|
||||
tokenizer tokens(str.begin() + pos, str.end() - 1, del);
|
||||
int comp = 0;
|
||||
for( tokenizer::const_iterator tok = tokens.begin();
|
||||
tok != tokens.end() && comp < 4;
|
||||
++tok, ++comp )
|
||||
{
|
||||
color._v[comp] = boost::lexical_cast<float>(*tok)
|
||||
// rgb = [0,255], a = [0,1]
|
||||
/ (comp < 3 ? 255 : 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
result = color;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace simgear
|
||||
40
simgear/misc/parse_color.hxx
Normal file
40
simgear/misc/parse_color.hxx
Normal file
@@ -0,0 +1,40 @@
|
||||
// Parse CSS colors
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef PARSE_COLOR_HXX_
|
||||
#define PARSE_COLOR_HXX_
|
||||
|
||||
#include <osg/Vec4>
|
||||
#include <string>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
/**
|
||||
* Parse a (CSS) color
|
||||
*
|
||||
* @param str Text to parse
|
||||
* @param result Output for parse color
|
||||
*
|
||||
* @return Whether str contained a valid color (and result has been modified)
|
||||
*/
|
||||
bool parseColor(std::string str, osg::Vec4& result);
|
||||
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* PARSE_COLOR_HXX_ */
|
||||
35
simgear/misc/parse_color_test.cxx
Normal file
35
simgear/misc/parse_color_test.cxx
Normal file
@@ -0,0 +1,35 @@
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include "parse_color.hxx"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#define COMPARE(a, b) \
|
||||
if( (a) != (b) ) \
|
||||
{ \
|
||||
std::cerr << "failed:" << #a << " != " << #b << std::endl; \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
#define VERIFY(a) \
|
||||
if( !(a) ) \
|
||||
{ \
|
||||
std::cerr << "failed:" << #a << std::endl; \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
#define VERIFY_COLOR(str, r, g, b, a) \
|
||||
VERIFY(simgear::parseColor(str, color)) \
|
||||
COMPARE(color, osg::Vec4(r, g, b, a))
|
||||
|
||||
int main (int ac, char ** av)
|
||||
{
|
||||
osg::Vec4 color;
|
||||
VERIFY_COLOR("#ff0000", 1,0,0,1);
|
||||
VERIFY_COLOR("#00ff00", 0,1,0,1);
|
||||
VERIFY_COLOR("#0000ff", 0,0,1,1);
|
||||
VERIFY_COLOR("rgb( 255,\t127.5,0)", 1, 0.5, 0, 1);
|
||||
VERIFY_COLOR("rgba(255, 127.5,0, 0.5)", 1, 0.5, 0, 0.5);
|
||||
std::cout << "all tests passed successfully!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -12,9 +12,9 @@
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Library 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.
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "PropertyBasedElement.hxx"
|
||||
|
||||
@@ -46,4 +46,10 @@ namespace simgear
|
||||
return _node;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void PropertyBasedElement::setSelf(const PropertyBasedElementPtr& self)
|
||||
{
|
||||
_self = self;
|
||||
}
|
||||
|
||||
} // namespace simgear
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Library 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.
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef SG_PROPERTY_BASED_ELEMENT_HXX_
|
||||
#define SG_PROPERTY_BASED_ELEMENT_HXX_
|
||||
@@ -47,9 +47,9 @@ namespace simgear
|
||||
SGConstPropertyNode_ptr getProps() const;
|
||||
SGPropertyNode_ptr getProps();
|
||||
|
||||
protected:
|
||||
virtual void setSelf(const PropertyBasedElementPtr& self);
|
||||
|
||||
friend class PropertyBasedMgr;
|
||||
protected:
|
||||
|
||||
SGPropertyNode_ptr _node;
|
||||
PropertyBasedElementWeakPtr _self;
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Library 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.
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "PropertyBasedMgr.hxx"
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace simgear
|
||||
);
|
||||
|
||||
PropertyBasedElementPtr el = _element_factory(child);
|
||||
el->_self = el;
|
||||
el->setSelf( el );
|
||||
_elements[index] = el;
|
||||
elementCreated( el );
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Library 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.
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef SG_PROPERTY_BASED_MGR_HXX_
|
||||
#define SG_PROPERTY_BASED_MGR_HXX_
|
||||
|
||||
@@ -1162,6 +1162,18 @@ public:
|
||||
T getValue(typename boost::disable_if_c<simgear::props::PropertyTraits<T>::Internal>
|
||||
::type* dummy = 0) const;
|
||||
|
||||
/**
|
||||
* Get a list of values from all children with the given name
|
||||
*/
|
||||
template<typename T, typename T_get /* = T */> // TODO use C++11 or traits
|
||||
std::vector<T> getChildValues(const std::string& name) const;
|
||||
|
||||
/**
|
||||
* Get a list of values from all children with the given name
|
||||
*/
|
||||
template<typename T>
|
||||
std::vector<T> getChildValues(const std::string& name) const;
|
||||
|
||||
/**
|
||||
* Set a bool value for this node.
|
||||
*/
|
||||
@@ -1846,6 +1858,25 @@ inline T SGPropertyNode::getValue(typename boost::enable_if_c<simgear::props
|
||||
return ::getValue<T>(this);
|
||||
}
|
||||
|
||||
template<typename T, typename T_get /* = T */> // TODO use C++11 or traits
|
||||
std::vector<T> SGPropertyNode::getChildValues(const std::string& name) const
|
||||
{
|
||||
const simgear::PropertyList& props = getChildren(name);
|
||||
std::vector<T> values( props.size() );
|
||||
|
||||
for( size_t i = 0; i < props.size(); ++i )
|
||||
values[i] = props[i]->getValue<T_get>();
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
std::vector<T> SGPropertyNode::getChildValues(const std::string& name) const
|
||||
{
|
||||
return getChildValues<T, T>(name);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool SGPropertyNode::setValue(const T& val,
|
||||
typename boost::disable_if_c<simgear::props
|
||||
|
||||
Reference in New Issue
Block a user