1
0
Fork 0

Canvas: Image/Window unifying and allow using canvas inside canvas.

- Refactor and unify common functionality of canvas::Window and
   canvas::Image
 - Make canvas::Image actually work
 - Allow using canvases inside canvas::Image
   * Use new canvas:// "protocol" to allow using canvases in
     place of images
 - Prepare for categorizing canvases:
   * Move canvases to /canvas/by-index
   * Later support linking to other nodes in subbranches of
     /canvas
This commit is contained in:
Thomas Geymayer 2012-08-09 14:50:20 +02:00
parent 350d508324
commit 83bbd9e45c
14 changed files with 352 additions and 219 deletions

View file

@ -37,6 +37,7 @@ typedef boost::weak_ptr<PropertyBasedElement> PropertyBasedElementWeakPtr;
namespace canvas namespace canvas
{ {
class Group; class Group;
class Image;
class MouseEvent; class MouseEvent;
class Placement; class Placement;

View file

@ -30,7 +30,7 @@ CanvasPtr canvasFactory(SGPropertyNode* node)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
CanvasMgr::CanvasMgr(): CanvasMgr::CanvasMgr():
PropertyBasedMgr("/canvas", "texture", &canvasFactory) PropertyBasedMgr("/canvas/by-index", "texture", &canvasFactory)
{ {
Canvas::addPlacementFactory Canvas::addPlacementFactory
( (
@ -46,11 +46,21 @@ CanvasMgr::CanvasMgr():
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
unsigned int CanvasMgr::getCanvasTexId(size_t index) const CanvasPtr CanvasMgr::getCanvas(size_t index) const
{ {
if( index >= _elements.size() if( index >= _elements.size()
|| !_elements[index] ) || !_elements[index] )
return 0; return CanvasPtr();
return static_cast<Canvas*>(_elements[index].get())->getTexId(); return boost::static_pointer_cast<Canvas>(_elements[index]);
}
//------------------------------------------------------------------------------
unsigned int CanvasMgr::getCanvasTexId(size_t index) const
{
CanvasPtr canvas = getCanvas(index);
if( canvas )
return canvas->getTexId();
else
return 0;
} }

View file

@ -19,6 +19,7 @@
#ifndef CANVAS_MGR_H_ #ifndef CANVAS_MGR_H_
#define CANVAS_MGR_H_ #define CANVAS_MGR_H_
#include "canvas_fwd.hpp"
#include "property_based_mgr.hxx" #include "property_based_mgr.hxx"
class CanvasMgr: class CanvasMgr:
@ -27,9 +28,20 @@ class CanvasMgr:
public: public:
CanvasMgr(); CanvasMgr();
/**
* Get ::Canvas by index
*
* @param index Index of texture node in /canvas/by-index/
*/
CanvasPtr getCanvas(size_t index) const;
/** /**
* Get OpenGL texture name for given canvas * Get OpenGL texture name for given canvas
* *
* @deprecated This was only meant to be used by the PUI CanvasWidget
* implementation as PUI can't handle osg::Texture objects.
* Use getCanvas(index)->getTexture() instead.
*
* @param Index of canvas * @param Index of canvas
* @return OpenGL texture name * @return OpenGL texture name
*/ */

View file

@ -20,6 +20,8 @@
#include <osgDB/ReadFile> #include <osgDB/ReadFile>
#include <Canvas/canvas.hxx>
#include <Canvas/canvas_mgr.hxx>
#include <Canvas/property_helper.hxx> #include <Canvas/property_helper.hxx>
#include <osg/Array> #include <osg/Array>
#include <osg/Geometry> #include <osg/Geometry>
@ -28,43 +30,80 @@
#include <Main/globals.hxx> #include <Main/globals.hxx>
#include <Main/fg_props.hxx> #include <Main/fg_props.hxx>
#include <boost/algorithm/string/predicate.hpp>
/**
* Callback to enable/disable rendering of canvas displayed inside windows or
* other canvases.
*/
class CullCallback:
public osg::Drawable::CullCallback
{
public:
CullCallback(Canvas::CameraCullCallback* camera_cull);
private:
Canvas::CameraCullCallback *_camera_cull;
virtual bool cull( osg::NodeVisitor* nv,
osg::Drawable* drawable,
osg::RenderInfo* renderInfo ) const;
};
//------------------------------------------------------------------------------
CullCallback::CullCallback(Canvas::CameraCullCallback* camera_cull):
_camera_cull( camera_cull )
{
}
//------------------------------------------------------------------------------
bool CullCallback::cull( osg::NodeVisitor* nv,
osg::Drawable* drawable,
osg::RenderInfo* renderInfo ) const
{
_camera_cull->enableRendering();
// TODO check if window/image should be culled
return false;
}
namespace canvas namespace canvas
{ {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
Image::Image(SGPropertyNode_ptr node): Image::Image(SGPropertyNode_ptr node):
Element(node, COLOR | COLOR_FILL | BOUNDING_BOX), Element(node, COLOR_FILL | BOUNDING_BOX),
_texture(new osg::Texture2D) _texture(new osg::Texture2D),
_node_src_rect( node->getNode("source", 0, true) ),
_src_rect(0,0,0,0),
_region(0,0,0,0)
{ {
_source_rect = node->getChild("source");
_geom = new osg::Geometry; _geom = new osg::Geometry;
_geom->setUseDisplayList(false); _geom->setUseDisplayList(false);
osg::StateSet *stateSet = _geom->getOrCreateStateSet(); osg::StateSet *stateSet = _geom->getOrCreateStateSet();
stateSet->setTextureAttributeAndModes(0, _texture.get()); stateSet->setTextureAttributeAndModes(0, _texture.get());
stateSet->setDataVariance(osg::Object::STATIC); stateSet->setDataVariance(osg::Object::STATIC);
// allocate arrays for the image // allocate arrays for the image
_vertices = new osg::Vec2Array; _vertices = new osg::Vec3Array(4);
_vertices->setDataVariance(osg::Object::STATIC); _vertices->setDataVariance(osg::Object::STATIC);
_vertices->reserve(4);
_geom->setVertexArray(_vertices); _geom->setVertexArray(_vertices);
_texCoords = new osg::Vec2Array; _texCoords = new osg::Vec2Array(4);
_texCoords->setDataVariance(osg::Object::STATIC); _texCoords->setDataVariance(osg::Object::STATIC);
_texCoords->reserve(4);
_geom->setTexCoordArray(0, _texCoords); _geom->setTexCoordArray(0, _texCoords);
_colors = new osg::Vec4Array; _colors = new osg::Vec4Array(4);
_colors->setDataVariance(osg::Object::STATIC); _colors->setDataVariance(osg::Object::STATIC);
_geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX); _geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
_geom->setColorArray(_colors); _geom->setColorArray(_colors);
osg::DrawArrays* prim = new osg::DrawArrays(osg::PrimitiveSet::QUADS); osg::DrawArrays* prim = new osg::DrawArrays(osg::PrimitiveSet::QUADS);
prim->set(osg::PrimitiveSet::QUADS, 0, 1); prim->set(osg::PrimitiveSet::QUADS, 0, 4);
prim->setDataVariance(osg::Object::STATIC); prim->setDataVariance(osg::Object::STATIC);
_geom->addPrimitiveSet(prim); _geom->addPrimitiveSet(prim);
setDrawable(_geom); setDrawable(_geom);
} }
@ -79,69 +118,184 @@ namespace canvas
{ {
Element::update(dt); Element::update(dt);
if( _attributes_dirty & SRC_RECT ) { if( _attributes_dirty & DEST_SIZE )
_attributes_dirty &= ~SRC_RECT; {
int texWidth = _texture->getTextureWidth(); (*_vertices)[0].set(_region.l(), _region.t(), 0);
int texHeight = _texture->getTextureHeight(); (*_vertices)[1].set(_region.r(), _region.t(), 0);
(*_vertices)[2].set(_region.r(), _region.b(), 0);
double x0 = _source_rect->getDoubleValue("left"), (*_vertices)[3].set(_region.l(), _region.b(), 0);
x1 = _source_rect->getDoubleValue("right"),
y0 = _source_rect->getDoubleValue("top"),
y1 = _source_rect->getDoubleValue("bottom");
double width = x1 - x0, height = y1 - y0;
_vertices->clear();
_vertices->push_back(osg::Vec2(0, 0));
_vertices->push_back(osg::Vec2(width, 0));
_vertices->push_back(osg::Vec2(width, height));
_vertices->push_back(osg::Vec2(0, height));
_vertices->dirty(); _vertices->dirty();
double u0 = x0 / texWidth, _attributes_dirty &= ~DEST_SIZE;
u1 = x1 / texWidth, _geom->dirtyBound();
v0 = y0 / texHeight,
v1 = y1 / texHeight;
_texCoords->clear();
_texCoords->push_back(osg::Vec2(u0, v0));
_texCoords->push_back(osg::Vec2(u1, v0));
_texCoords->push_back(osg::Vec2(u1, v1));
_texCoords->push_back(osg::Vec2(u0, v1));
_texCoords->dirty();
} }
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) )
{
osg::Texture2D *texture = !_canvas.expired()
? _canvas.lock()->getTexture()
: _texture.get();
int texWidth = texture->getTextureWidth();
int texHeight = texture->getTextureHeight();
u0 /= texWidth;
u1 /= texWidth;
v0 /= texHeight;
v1 /= texHeight;
}
(*_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::setCanvas(CanvasPtr canvas)
{
_canvas = canvas;
_geom->getOrCreateStateSet()
->setTextureAttribute(0, canvas ? canvas->getTexture() : 0);
_geom->setCullCallback(
canvas ? new CullCallback(canvas->getCameraCullCallback()) : 0
);
}
//----------------------------------------------------------------------------
CanvasWeakPtr Image::getCanvas() const
{
return _canvas;
}
//----------------------------------------------------------------------------
void Image::setImage(osg::Image *img)
{
// remove canvas...
setCanvas( CanvasPtr() );
_texture->setImage(img);
_geom->getOrCreateStateSet()
->setTextureAttributeAndModes(0, _texture);
}
//----------------------------------------------------------------------------
const Rect<float>& Image::getRegion() const
{
return _region;
}
//----------------------------------------------------------------------------
void Image::valueChanged(SGPropertyNode *node)
{
if( node->getParent() == _node_src_rect )
{
_attributes_dirty |= SRC_RECT;
if( node->getNameString() == "left" )
_src_rect.setLeft( node->getFloatValue() );
else if( node->getNameString() == "right" )
_src_rect.setRight( node->getFloatValue() );
else if( node->getNameString() == "top" )
_src_rect.setTop( node->getFloatValue() );
else if( node->getNameString() == "bottom" )
_src_rect.setBottom( node->getFloatValue() );
}
else
Element::valueChanged(node);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Image::childChanged(SGPropertyNode* child) void Image::childChanged(SGPropertyNode* child)
{ {
const std::string& name = child->getNameString(); const std::string& name = child->getNameString();
if (_source_rect == child) if( name == "x" )
_attributes_dirty |= SRC_RECT; {
else if (name == "file") { _region.setX( child->getFloatValue() );
SGPath tpath = globals->resolve_ressource_path(child->getStringValue()); _attributes_dirty |= DEST_SIZE;
if (tpath.isNull() || !tpath.exists()) { }
SG_LOG(SG_GL, SG_ALERT, "canvas::Image: No such image: " << child->getStringValue()); else if( name == "y" )
} else { {
_texture->setImage(osgDB::readImageFile(tpath.c_str())); _region.setY( child->getFloatValue() );
_attributes_dirty |= SRC_RECT; _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();
if( boost::starts_with(path, CANVAS_PROTOCOL) )
{
CanvasMgr* canvas_mgr =
dynamic_cast<CanvasMgr*>(globals->get_subsystem("Canvas"));
if( !canvas_mgr )
{
SG_LOG(SG_GL, SG_ALERT, "canvas::Image: Failed to get CanvasMgr");
return;
} }
}
}
//---------------------------------------------------------------------------- const SGPropertyNode* canvas_node =
void Image::colorChanged(const osg::Vec4& color) canvas_mgr->getPropertyRoot()
{ ->getParent()
_colors->clear(); ->getNode( path.substr(CANVAS_PROTOCOL.size()) );
for (int i=0; i<4; ++i) { if( !canvas_node )
_colors->push_back(color); {
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 canvas = canvas_mgr->getCanvas( canvas_node->getIndex() );
if( !canvas )
{
SG_LOG(SG_GL, SG_ALERT, "canvas::Image: Invalid canvas: " << path);
return;
}
setCanvas(canvas);
} }
_colors->dirty(); else
{
SGPath tpath = globals->resolve_ressource_path(path);
if( tpath.isNull() || !tpath.exists() )
{
SG_LOG(SG_GL, SG_ALERT, "canvas::Image: No such image: " << path);
return;
}
setImage( osgDB::readImageFile(tpath.c_str()) );
}
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Image::colorFillChanged(const osg::Vec4& /*color*/) void Image::colorFillChanged(const osg::Vec4& color)
{ {
for( int i = 0; i < 4; ++i )
(*_colors)[i] = color;
_colors->dirty();
} }
} // namespace canvas } // namespace canvas

View file

@ -20,11 +20,8 @@
#define CANVAS_IMAGE_HXX_ #define CANVAS_IMAGE_HXX_
#include "element.hxx" #include "element.hxx"
#include <Canvas/canvas_fwd.hpp>
#include <boost/shared_ptr.hpp> #include <Canvas/rect.hxx>
#include <map>
#include <vector>
#include <osg/Texture2D> #include <osg/Texture2D>
@ -35,33 +32,58 @@ namespace canvas
public Element public Element
{ {
public: 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(SGPropertyNode_ptr node); Image(SGPropertyNode_ptr node);
~Image(); ~Image();
virtual void update(double dt); virtual void update(double dt);
void setCanvas(CanvasPtr canvas);
CanvasWeakPtr getCanvas() const;
void setImage(osg::Image *img);
const Rect<float>& getRegion() const;
/**
* Callback for every changed child node
*/
virtual void valueChanged(SGPropertyNode *node);
protected: protected:
enum TextAttributes enum ImageAttributes
{ {
SRC_RECT = LAST_ATTRIBUTE << 1, // Source image rectangle SRC_RECT = LAST_ATTRIBUTE << 1, // Source image rectangle
DEST_SIZE = SRC_RECT << 1 // Element size
}; };
SGPropertyNode_ptr _source_rect, /**
_dest_rect; * Callback for changed direct child nodes
*/
virtual void childChanged(SGPropertyNode * child); virtual void childChanged(SGPropertyNode * child);
virtual void colorChanged(const osg::Vec4& color);
virtual void colorFillChanged(const osg::Vec4& color); virtual void colorFillChanged(const osg::Vec4& color);
void handleHit(float x, float y); void handleHit(float x, float y);
osg::ref_ptr<osg::Texture2D> _texture; osg::ref_ptr<osg::Texture2D> _texture;
// TODO optionally forward events to canvas
CanvasWeakPtr _canvas;
osg::Geometry *_geom; osg::Geometry *_geom;
osg::Vec2Array *_vertices; osg::Vec3Array *_vertices;
osg::Vec2Array *_texCoords; osg::Vec2Array *_texCoords;
osg::Vec4Array* _colors; osg::Vec4Array* _colors;
SGPropertyNode *_node_src_rect;
Rect<float> _src_rect,
_region;
}; };
} // namespace canvas } // namespace canvas

View file

@ -226,10 +226,10 @@ namespace canvas
_node->addChangeListener(this); _node->addChangeListener(this);
if( _attributes_used & COLOR ) if( _attributes_used & COLOR )
linkColorNodes("color", _node, _color, osg::Vec4f(0,1,0,1)); linkColorNodes("color", _node, _color, osg::Vec4f(0,0,0,1));
if( _attributes_used & COLOR_FILL ) if( _attributes_used & COLOR_FILL )
linkColorNodes("color-fill", _node, _color_fill, osg::Vec4f(1,0,1,1)); linkColorNodes("color-fill", _node, _color_fill, osg::Vec4f(1,1,1,1));
SG_LOG SG_LOG
( (

View file

@ -24,6 +24,7 @@
#include <Viewer/CameraGroup.hxx> #include <Viewer/CameraGroup.hxx>
#include <Viewer/renderer.hxx> #include <Viewer/renderer.hxx>
#include <osg/BlendFunc>
#include <osgViewer/Viewer> #include <osgViewer/Viewer>
#include <osgGA/GUIEventHandler> #include <osgGA/GUIEventHandler>
@ -94,7 +95,6 @@ GUIMgr::GUIMgr():
PropertyBasedMgr("/sim/gui/canvas", "window", &windowFactory), PropertyBasedMgr("/sim/gui/canvas", "window", &windowFactory),
_event_handler( new GUIEventHandler(this) ), _event_handler( new GUIEventHandler(this) ),
_transform( new osg::MatrixTransform ), _transform( new osg::MatrixTransform ),
_geode_windows( new osg::Geode ),
_width(_props, "size[0]"), _width(_props, "size[0]"),
_height(_props, "size[1]"), _height(_props, "size[1]"),
_last_push(-1) _last_push(-1)
@ -104,18 +104,31 @@ GUIMgr::GUIMgr():
osg::Camera* camera = osg::Camera* camera =
flightgear::getGUICamera( flightgear::CameraGroup::getDefault() ); flightgear::getGUICamera( flightgear::CameraGroup::getDefault() );
assert(camera); assert(camera);
camera->addChild(_transform);
osg::Viewport* vp = camera->getViewport(); osg::Viewport* vp = camera->getViewport();
handleResize(vp->x(), vp->y(), vp->width(), vp->height()); handleResize(vp->x(), vp->y(), vp->width(), vp->height());
_transform->addChild(_geode_windows);
camera->addChild(_transform);
Canvas::addPlacementFactory Canvas::addPlacementFactory
( (
"window", "window",
boost::bind(&GUIMgr::addPlacement, this, _1, _2) boost::bind(&GUIMgr::addPlacement, this, _1, _2)
); );
osg::StateSet* stateSet = _transform->getOrCreateStateSet();
stateSet->setDataVariance(osg::Object::STATIC);
stateSet->setRenderBinDetails(1000, "RenderBin");
// speed optimization?
stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
stateSet->setAttribute(new osg::BlendFunc(
osg::BlendFunc::SRC_ALPHA,
osg::BlendFunc::ONE_MINUS_SRC_ALPHA)
);
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -141,9 +154,9 @@ void GUIMgr::shutdown()
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void GUIMgr::elementCreated(PropertyBasedElementPtr element) void GUIMgr::elementCreated(PropertyBasedElementPtr element)
{ {
_geode_windows->addDrawable _transform->addChild
( (
static_cast<canvas::Window*>(element.get())->getDrawable() static_cast<canvas::Window*>(element.get())->getGroup()
); );
} }

View file

@ -51,7 +51,6 @@ class GUIMgr:
protected: protected:
osg::ref_ptr<GUIEventHandler> _event_handler; osg::ref_ptr<GUIEventHandler> _event_handler;
osg::ref_ptr<osg::MatrixTransform> _transform; osg::ref_ptr<osg::MatrixTransform> _transform;
osg::ref_ptr<osg::Geode> _geode_windows;
simgear::PropertyObject<int> _width, simgear::PropertyObject<int> _width,
_height; _height;

View file

@ -100,6 +100,12 @@ void PropertyBasedMgr::childRemoved( SGPropertyNode * parent,
_elements[index].reset(); _elements[index].reset();
} }
//------------------------------------------------------------------------------
const SGPropertyNode* PropertyBasedMgr::getPropertyRoot() const
{
return _props;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
PropertyBasedMgr::PropertyBasedMgr( const std::string& path_root, PropertyBasedMgr::PropertyBasedMgr( const std::string& path_root,
const std::string& name_elements, const std::string& name_elements,

View file

@ -43,6 +43,8 @@ class PropertyBasedMgr:
virtual void elementCreated(PropertyBasedElementPtr element) {} virtual void elementCreated(PropertyBasedElementPtr element) {}
virtual const SGPropertyNode* getPropertyRoot() const;
protected: protected:
typedef boost::function<PropertyBasedElementPtr(SGPropertyNode*)> typedef boost::function<PropertyBasedElementPtr(SGPropertyNode*)>

View file

@ -49,11 +49,21 @@ namespace canvas
T width() const { return _x2 - _x1; } T width() const { return _x2 - _x1; }
T height() const { return _y2 - _y1; } 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 l() const { return _x1; }
T r() const { return _x2; } T r() const { return _x2; }
T t() const { return _y1; } T t() const { return _y1; }
T b() const { return _y2; } 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 bool contains(T x, T y) const
{ {
return _x1 <= x && x <= _x2 return _x1 <= x && x <= _x2

View file

@ -19,164 +19,78 @@
#include "window.hxx" #include "window.hxx"
#include <Canvas/canvas.hxx> #include <Canvas/canvas.hxx>
#include <osg/BlendFunc>
#include <osg/Geometry>
#include <osg/Texture2D>
#include <osgGA/GUIEventHandler> #include <osgGA/GUIEventHandler>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
/**
* Callback to enable/disable rendering of canvas displayed inside windows
*/
class CullCallback:
public osg::Drawable::CullCallback
{
public:
CullCallback(Canvas::CameraCullCallback* camera_cull);
private:
Canvas::CameraCullCallback *_camera_cull;
virtual bool cull( osg::NodeVisitor* nv,
osg::Drawable* drawable,
osg::RenderInfo* renderInfo ) const;
};
//------------------------------------------------------------------------------
CullCallback::CullCallback(Canvas::CameraCullCallback* camera_cull):
_camera_cull( camera_cull )
{
}
//------------------------------------------------------------------------------
bool CullCallback::cull( osg::NodeVisitor* nv,
osg::Drawable* drawable,
osg::RenderInfo* renderInfo ) const
{
_camera_cull->enableRendering();
return false;
}
namespace canvas namespace canvas
{ {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
Window::Window(SGPropertyNode* node): Window::Window(SGPropertyNode* node):
PropertyBasedElement(node), PropertyBasedElement(node),
_dirty(true), _image(node)
_geometry( new osg::Geometry ),
_vertices( new osg::Vec3Array(4) ),
_tex_coords( new osg::Vec2Array(4) ),
_x(node, "x"),
_y(node, "y"),
_width(node, "size[0]"),
_height(node, "size[1]")
{ {
_x = 50; // TODO probably better remove default position and size
_y = 100; node->setFloatValue("x", 50);
_width = 400; node->setFloatValue("y", 100);
_height = 300; node->setFloatValue("size[0]", 400);
node->setFloatValue("size[1]", 300);
_geometry->setVertexArray(_vertices); node->setFloatValue("source/right", 1);
_geometry->setTexCoordArray(0,_tex_coords); node->setFloatValue("source/bottom", 1);
node->setBoolValue("source/normalized", true);
osg::Vec4Array* colors = new osg::Vec4Array(1);
(*colors)[0].set(1.0f,1.0f,1.0,1.0f);
_geometry->setColorArray(colors);
_geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
_geometry->addPrimitiveSet(
new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)
);
_geometry->setDataVariance(osg::Object::DYNAMIC);
osg::StateSet* stateSet = _geometry->getOrCreateStateSet();
stateSet->setRenderBinDetails(1000, "RenderBin");
// speed optimization?
stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
stateSet->setAttribute(new osg::BlendFunc(
osg::BlendFunc::SRC_ALPHA,
osg::BlendFunc::ONE_MINUS_SRC_ALPHA)
);
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
Window::~Window() Window::~Window()
{ {
BOOST_FOREACH(osg::Node* parent, _geometry->getParents()) BOOST_FOREACH(osg::Group* parent, getGroup()->getParents())
{ {
osg::Geode* geode = dynamic_cast<osg::Geode*>(parent); parent->removeChild(getGroup());
if( geode )
geode->removeDrawable(_geometry);
} }
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Window::update(double delta_time_sec) void Window::update(double delta_time_sec)
{ {
if( !_dirty ) _image.update(delta_time_sec);
return;
_dirty = false;
_region.set(_x, _y, _width, _height);
int z = 0; // TODO do we need to use z for depth ordering?
(*_vertices)[0].set(_region.l(), _region.t(), z);
(*_vertices)[1].set(_region.r(), _region.t(), z);
(*_vertices)[2].set(_region.r(), _region.b(), z);
(*_vertices)[3].set(_region.l(), _region.b(), z);
float l = 0, t = 1, b = 0, r = 1;
(*_tex_coords)[0].set(l,t);
(*_tex_coords)[1].set(r,t);
(*_tex_coords)[2].set(r,b);
(*_tex_coords)[3].set(l,b);
_geometry->dirtyDisplayList();
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Window::valueChanged (SGPropertyNode * node) void Window::valueChanged(SGPropertyNode * node)
{ {
if( node->getParent() != _node ) _image.valueChanged(node);
return; }
const std::string& name = node->getNameString(); //----------------------------------------------------------------------------
if( name == "x" || name == "y" || name == "size" ) osg::Group* Window::getGroup()
_dirty = true; {
return _image.getMatrixTransform();
}
//----------------------------------------------------------------------------
const Rect<float>& Window::getRegion() const
{
return _image.getRegion();
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Window::setCanvas(CanvasPtr canvas) void Window::setCanvas(CanvasPtr canvas)
{ {
_canvas = canvas; _image.setCanvas(canvas);
_geometry->getOrCreateStateSet()
->setTextureAttribute(0, canvas ? canvas->getTexture() : 0);
_geometry->dirtyDisplayList();
_geometry->setCullCallback(
canvas ? new CullCallback(canvas->getCameraCullCallback()) : 0
);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
CanvasWeakPtr Window::getCanvas() const CanvasWeakPtr Window::getCanvas() const
{ {
return _canvas; return _image.getCanvas();
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool Window::handleMouseEvent(const MouseEvent& event) bool Window::handleMouseEvent(const MouseEvent& event)
{ {
if( !_canvas.expired() ) if( !getCanvas().expired() )
return _canvas.lock()->handleMouseEvent(event); return getCanvas().lock()->handleMouseEvent(event);
else else
return false; return false;
} }

View file

@ -20,7 +20,7 @@
#define CANVAS_WINDOW_HXX_ #define CANVAS_WINDOW_HXX_
#include "property_based_element.hxx" #include "property_based_element.hxx"
#include "rect.hxx" #include <Canvas/elements/CanvasImage.hxx>
#include <Canvas/MouseEvent.hxx> #include <Canvas/MouseEvent.hxx>
#include <simgear/props/propertyObject.hxx> #include <simgear/props/propertyObject.hxx>
@ -40,8 +40,8 @@ namespace canvas
virtual void update(double delta_time_sec); virtual void update(double delta_time_sec);
virtual void valueChanged (SGPropertyNode * node); virtual void valueChanged (SGPropertyNode * node);
osg::Drawable* getDrawable() { return _geometry; } osg::Group* getGroup();
const Rect<int>& getRegion() const { return _region; } const Rect<float>& getRegion() const;
void setCanvas(CanvasPtr canvas); void setCanvas(CanvasPtr canvas);
CanvasWeakPtr getCanvas() const; CanvasWeakPtr getCanvas() const;
@ -50,17 +50,7 @@ namespace canvas
protected: protected:
bool _dirty; Image _image;
osg::ref_ptr<osg::Geometry> _geometry;
osg::ref_ptr<osg::Vec3Array> _vertices;
osg::ref_ptr<osg::Vec2Array> _tex_coords;
simgear::PropertyObject<int> _x, _y,
_width, _height;
Rect<int> _region;
CanvasWeakPtr _canvas;
}; };
} // namespace canvas } // namespace canvas

View file

@ -32,7 +32,7 @@ CanvasWidget::CanvasWidget( int x, int y,
} }
// Get the first unused canvas slot // Get the first unused canvas slot
SGPropertyNode* canvas_root = fgGetNode("/canvas", true); SGPropertyNode* canvas_root = fgGetNode("/canvas/by-index", true);
for(int index = 0;; ++index) for(int index = 0;; ++index)
{ {
if( !canvas_root->getChild("texture", index) ) if( !canvas_root->getChild("texture", index) )