#include <Canvas/property_helper.hxx>
#include <Main/globals.hxx>
+#include <Viewer/CameraGroup.hxx>
#include <Viewer/renderer.hxx>
+#include <simgear/scene/util/RenderConstants.hxx>
+
#include <osg/Camera>
#include <osg/Geode>
#include <osgText/Text>
public:
CameraCullCallback():
- _render( true )
+ _render( true ),
+ _render_frame( 0 )
{}
/**
private:
bool _render;
+ unsigned int _render_frame;
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
- if( _render )
- {
- traverse(node, nv);
- _render = false;
- }
+ if( !_render && nv->getTraversalNumber() != _render_frame )
+ return;
+
+ traverse(node, nv);
+
+ _render = false;
+ _render_frame = nv->getTraversalNumber();
}
};
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
- _camera_cull->enableRendering();
+ if( nv->getTraversalMask() & simgear::MODEL_BIT )
+ _camera_cull->enableRendering();
+
traverse(node, nv);
}
};
if( !tex )
return 0;
- osgViewer::Viewer::Contexts contexts;
- globals->get_renderer()->getViewer()->getContexts(contexts);
+// osgViewer::Viewer::Contexts contexts;
+// globals->get_renderer()->getViewer()->getContexts(contexts);
+//
+// if( contexts.empty() )
+// return 0;
- if( contexts.empty() )
- return 0;
+ osg::Camera* guiCamera =
+ flightgear::getGUICamera(flightgear::CameraGroup::getDefault());
- osg::State* state = contexts[0]->getState();
+ osg::State* state = guiCamera->getGraphicsContext()->getState(); //contexts[0]->getState();
if( !state )
return 0;
namespace canvas
{
+ class Text::TextOSG:
+ public osgText::Text
+ {
+ public:
+ osg::Vec2 handleHit(float x, float y);
+ };
+
+ //----------------------------------------------------------------------------
+ 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
+ );
+ }
//----------------------------------------------------------------------------
Text::Text(SGPropertyNode_ptr node):
Element(node, COLOR | COLOR_FILL | BOUNDING_BOX),
- _text( new osgText::Text ),
+ _text( new Text::TextOSG() ),
_font_size( 0 ),
_font_aspect( 0 )
{
//----------------------------------------------------------------------------
void Text::childChanged(SGPropertyNode* child)
{
- if( _font_size == child || _font_aspect == child )
+ const std::string& name = child->getNameString();
+
+ if( name == "hit-y" )
+ handleHit
+ (
+ _node->getFloatValue("hit-x"),
+ _node->getFloatValue("hit-y")
+ );
+ else if( _font_size == child || _font_aspect == child )
_attributes_dirty |= FONT_SIZE;
- else if( child->getNameString() == "text" )
+ else if( name == "text" )
_text->setText
(
osgText::String( child->getStringValue(),
osgText::String::ENCODING_UTF8 )
);
- else if( child->getNameString() == "max-width" )
+ else if( name == "max-width" )
_text->setMaximumWidth( child->getFloatValue() );
- else if( child->getNameString() == "font" )
+ else if( name == "font" )
setFont( child->getStringValue() );
}
_text->setBoundingBoxColor(color);
}
+ //----------------------------------------------------------------------------
+ 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());
+ }
+
//----------------------------------------------------------------------------
Text::font_ptr Text::getFont(const std::string& name)
{