1 // An image on the Canvas
3 // Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Library General Public
7 // License as published by the Free Software Foundation; either
8 // version 2 of the License, or (at your option) any later version.
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Library General Public License for more details.
15 // You should have received a copy of the GNU Library General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "CanvasImage.hxx"
21 #include <simgear/canvas/Canvas.hxx>
22 #include <simgear/canvas/CanvasMgr.hxx>
23 #include <simgear/canvas/CanvasSystemAdapter.hxx>
24 #include <simgear/scene/util/parse_color.hxx>
25 #include <simgear/misc/sg_path.hxx>
28 #include <osg/Geometry>
29 #include <osg/PrimitiveSet>
31 #include <boost/algorithm/string/predicate.hpp>
38 * Callback to enable/disable rendering of canvas displayed inside windows or
42 public osg::Drawable::CullCallback
45 CullCallback(const CanvasWeakPtr& canvas);
48 CanvasWeakPtr _canvas;
50 virtual bool cull( osg::NodeVisitor* nv,
51 osg::Drawable* drawable,
52 osg::RenderInfo* renderInfo ) const;
55 //----------------------------------------------------------------------------
56 CullCallback::CullCallback(const CanvasWeakPtr& canvas):
62 //----------------------------------------------------------------------------
63 bool CullCallback::cull( osg::NodeVisitor* nv,
64 osg::Drawable* drawable,
65 osg::RenderInfo* renderInfo ) const
67 if( !_canvas.expired() )
68 _canvas.lock()->enableRendering();
70 // TODO check if window/image should be culled
74 //----------------------------------------------------------------------------
75 Image::Image( const CanvasWeakPtr& canvas,
76 const SGPropertyNode_ptr& node,
77 const Style& parent_style,
79 Element(canvas, node, parent_style, parent),
80 _texture(new osg::Texture2D),
81 _node_src_rect( node->getNode("source", 0, true) ),
85 _geom = new osg::Geometry;
86 _geom->setUseDisplayList(false);
88 osg::StateSet *stateSet = _geom->getOrCreateStateSet();
89 stateSet->setTextureAttributeAndModes(0, _texture.get());
90 stateSet->setDataVariance(osg::Object::STATIC);
92 // allocate arrays for the image
93 _vertices = new osg::Vec3Array(4);
94 _vertices->setDataVariance(osg::Object::STATIC);
95 _geom->setVertexArray(_vertices);
97 _texCoords = new osg::Vec2Array(4);
98 _texCoords->setDataVariance(osg::Object::STATIC);
99 _geom->setTexCoordArray(0, _texCoords);
101 _colors = new osg::Vec4Array(4);
102 _colors->setDataVariance(osg::Object::STATIC);
103 _geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
104 _geom->setColorArray(_colors);
106 osg::DrawArrays* prim = new osg::DrawArrays(osg::PrimitiveSet::QUADS);
107 prim->set(osg::PrimitiveSet::QUADS, 0, 4);
108 prim->setDataVariance(osg::Object::STATIC);
109 _geom->addPrimitiveSet(prim);
113 addStyle("fill", &Image::setFill, this);
114 setFill("#ffffff"); // TODO how should we handle default values?
119 //----------------------------------------------------------------------------
125 //----------------------------------------------------------------------------
126 void Image::update(double dt)
130 if( _attributes_dirty & DEST_SIZE )
132 (*_vertices)[0].set(_region.l(), _region.t(), 0);
133 (*_vertices)[1].set(_region.r(), _region.t(), 0);
134 (*_vertices)[2].set(_region.r(), _region.b(), 0);
135 (*_vertices)[3].set(_region.l(), _region.b(), 0);
138 _attributes_dirty &= ~DEST_SIZE;
140 setBoundingBox(_geom->getBound());
143 if( _attributes_dirty & SRC_RECT )
145 double u0 = _src_rect.l(),
150 if( !_node_src_rect->getBoolValue("normalized", true) )
152 const SGRect<int>& tex_dim = getTextureDimensions();
154 u0 /= tex_dim.width();
155 u1 /= tex_dim.width();
156 v0 /= tex_dim.height();
157 v1 /= tex_dim.height();
160 (*_texCoords)[0].set(u0, v0);
161 (*_texCoords)[1].set(u1, v0);
162 (*_texCoords)[2].set(u1, v1);
163 (*_texCoords)[3].set(u0, v1);
166 _attributes_dirty &= ~SRC_RECT;
170 //----------------------------------------------------------------------------
171 void Image::setSrcCanvas(CanvasPtr canvas)
173 if( !_src_canvas.expired() )
174 _src_canvas.lock()->removeDependentCanvas(_canvas);
176 _src_canvas = canvas;
177 _geom->getOrCreateStateSet()
178 ->setTextureAttribute(0, canvas ? canvas->getTexture() : 0);
179 _geom->setCullCallback(canvas ? new CullCallback(canvas) : 0);
181 if( !_src_canvas.expired() )
183 setupDefaultDimensions();
184 _src_canvas.lock()->addDependentCanvas(_canvas);
188 //----------------------------------------------------------------------------
189 CanvasWeakPtr Image::getSrcCanvas() const
194 //----------------------------------------------------------------------------
195 void Image::setImage(osg::Image *img)
198 setSrcCanvas( CanvasPtr() );
200 _texture->setImage(img);
201 _geom->getOrCreateStateSet()
202 ->setTextureAttributeAndModes(0, _texture);
205 setupDefaultDimensions();
208 //----------------------------------------------------------------------------
209 void Image::setFill(const std::string& fill)
212 if( !parseColor(fill, color) )
215 for( int i = 0; i < 4; ++i )
216 (*_colors)[i] = color;
220 //----------------------------------------------------------------------------
221 const SGRect<float>& Image::getRegion() const
226 //----------------------------------------------------------------------------
227 void Image::childChanged(SGPropertyNode* child)
229 const std::string& name = child->getNameString();
231 if( child->getParent() == _node_src_rect )
233 _attributes_dirty |= SRC_RECT;
236 _src_rect.setLeft( child->getFloatValue() );
237 else if( name == "right" )
238 _src_rect.setRight( child->getFloatValue() );
239 else if( name == "top" )
240 _src_rect.setTop( child->getFloatValue() );
241 else if( name == "bottom" )
242 _src_rect.setBottom( child->getFloatValue() );
246 else if( child->getParent() != _node )
251 _region.setX( child->getFloatValue() );
252 _attributes_dirty |= DEST_SIZE;
254 else if( name == "y" )
256 _region.setY( child->getFloatValue() );
257 _attributes_dirty |= DEST_SIZE;
259 else if( name == "size" )
261 if( child->getIndex() == 0 )
262 _region.setWidth( child->getFloatValue() );
264 _region.setHeight( child->getFloatValue() );
266 _attributes_dirty |= DEST_SIZE;
268 else if( name == "file" )
270 static const std::string CANVAS_PROTOCOL = "canvas://";
271 const std::string& path = child->getStringValue();
273 CanvasPtr canvas = _canvas.lock();
276 SG_LOG(SG_GL, SG_ALERT, "canvas::Image: No canvas available");
280 if( boost::starts_with(path, CANVAS_PROTOCOL) )
282 CanvasMgr* canvas_mgr = canvas->getCanvasMgr();
285 SG_LOG(SG_GL, SG_ALERT, "canvas::Image: Failed to get CanvasMgr");
289 const SGPropertyNode* canvas_node =
290 canvas_mgr->getPropertyRoot()
292 ->getNode( path.substr(CANVAS_PROTOCOL.size()) );
295 SG_LOG(SG_GL, SG_ALERT, "canvas::Image: No such canvas: " << path);
299 // TODO add support for other means of addressing canvases (eg. by
301 CanvasPtr src_canvas = canvas_mgr->getCanvas( canvas_node->getIndex() );
304 SG_LOG(SG_GL, SG_ALERT, "canvas::Image: Invalid canvas: " << path);
308 setSrcCanvas(src_canvas);
312 setImage( canvas->getSystemAdapter()->getImage(path) );
317 //----------------------------------------------------------------------------
318 void Image::setupDefaultDimensions()
320 if( !_src_rect.width() || !_src_rect.height() )
322 const SGRect<int>& tex_dim = getTextureDimensions();
324 _node_src_rect->setBoolValue("normalized", false);
325 _node_src_rect->setFloatValue("right", tex_dim.width());
326 _node_src_rect->setFloatValue("bottom", tex_dim.height());
329 if( !_region.width() || !_region.height() )
331 _node->setFloatValue("size[0]", _src_rect.width());
332 _node->setFloatValue("size[1]", _src_rect.height());
336 //----------------------------------------------------------------------------
337 SGRect<int> Image::getTextureDimensions() const
339 osg::Texture2D *texture = !_src_canvas.expired()
340 ? _src_canvas.lock()->getTexture()
344 return SGRect<int>();
349 texture->getTextureWidth(),
350 texture->getTextureHeight()
354 } // namespace canvas
355 } // namespace simgear