openscenegraph / OpenSceneGraph

OpenSceneGraph git repository
http://www.openscenegraph.org
Other
3.21k stars 1.42k forks source link

osgText::Text::AlignmentType::LEFT_TOP makes text jump #1269

Open rubenlg opened 11 months ago

rubenlg commented 11 months ago

osgText::Text::AlignmentType::LEFT_TOP should align the text to the tallest possible glyph, but in practice it's aligning to the tallest glyph currently present in the input text. This is a problem when the text changes dynamically, because it will jump around as glyphs of different sizes appear. Here's a small repro case with text appearing letter by letter to illustrate the bug. Sorry for the hardcoded Linux font.

#include <osgDB/ReadFile>
#include <osgText/Text>
#include <osgViewer/Viewer>
#include <string>

const std::string TEXT = "aeiAg!";

class TextAnimationCallback : public osg::NodeCallback {
public:
  explicit TextAnimationCallback(osgText::Text *textNode)
      : textNode_(textNode) {}

  virtual void operator()(osg::Node *node, osg::NodeVisitor *nv) {
    double currentTime = nv->getFrameStamp()->getSimulationTime();
    if (currentTime - startTime_ >= 0.3) {
      textNode_->setText(TEXT.substr(0, letterIndex_ + 1),
                         osgText::String::Encoding::ENCODING_UTF8);
      letterIndex_ = (letterIndex_ + 1) % TEXT.size();
      startTime_ = currentTime;
    }
    traverse(node, nv);
  }
private:
  osg::ref_ptr<osgText::Text> textNode_;
  unsigned int letterIndex_ = 0;
  double startTime_ = 0.0;
};

int main() {
  osg::ref_ptr<osgText::Text> textNode = new osgText::Text;

  textNode->setText("____________"); // placeholder for osgViewer
  textNode->setFont(osgText::readFontFile(
      "/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf"));
  textNode->setRotation(
      osg::Quat(osg::inDegrees(90.0f), osg::Vec3(1.0f, 0.0f, 0.0f)));
  textNode->setAlignment(osgText::Text::AlignmentType::LEFT_TOP);
  textNode->setUpdateCallback(new TextAnimationCallback(textNode));

  osgViewer::Viewer viewer;
  viewer.setSceneData(textNode);
  return viewer.run();
}

I suppose a possible workaround, to achieve top alignment while this isn't fixed, would be to align to the baseline and then correct the position by using the ascender property from osgText::Font::getVerticalSize. But I haven't tried it yet.

Note that a proper fix for this would be a breaking change, since there might be code out there relying on its current behavior. Maybe fixing it properly would require introducing new enum values, such as LEFT_TOP_STABLE?