OpenSceneGraph/include/osgText/Text

615 lines
25 KiB
Plaintext
Raw Normal View History

2006-07-18 23:21:48 +08:00
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* 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
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGTEXT_TEXT
#define OSGTEXT_TEXT 1
#include <osg/Drawable>
#include <osg/Quat>
#include <osgText/Font>
#include <osgText/String>
namespace osgText {
class OSGTEXT_EXPORT Text : public osg::Drawable
{
public:
Text();
Text(const Text& text,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
virtual osg::Object* cloneType() const { return new Text(); }
virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new Text(*this,copyop); }
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const Text*>(obj)!=NULL; }
virtual const char* className() const { return "Text"; }
virtual const char* libraryName() const { return "osgText"; }
/** Set the Font to use to render the text.
* setFont(0) sets the use of the default font.*/
void setFont(Font* font=0);
/** Set the font, loaded from the specified front file, to use to render the text,
* setFont("") sets the use of the default font.
* See the osgText::readFontFile function for how the font file will be located. */
void setFont(const std::string& fontfile);
/** Get the font. Return 0 if default is being used.*/
const Font* getFont() const { return _font.get(); }
/** Set the Font reference width and height resolution in texels.
* Note, the size may not be supported by current font,
* the closest supported font size will be selected.*/
void setFontResolution(unsigned int width, unsigned int height);
unsigned int getFontWidth() const { return _fontWidth; }
unsigned int getFontHeight() const { return _fontHeight; }
/** Set the text using a osgText::String.*/
void setText(const String& text);
/** Set the text using a std::string,
* which is converted to an internal TextString.*/
void setText(const std::string& text);
/** Set the text using a Unicode encoded std::string, which is converted to an internal TextString.
* The encoding parameter specificies which Unicode encodeding is used in the std::string. */
void setText(const std::string& text,String::Encoding encoding);
/** Set the text using a wchar_t string,
* which is converted to an internal TextString.*/
void setText(const wchar_t* text);
/** Get the text string.
* Note, if you modify the string you must call Text::update() for
* the internal glyph reprentation to be updated.*/
String& getText() { return _text; }
/** Get the const text string.*/
const String& getText() const { return _text; }
/** update internal glyph respresnetation used for rendering,
* and bounding volume.*/
void update() { computeGlyphRepresentation(); }
/** Set the rendered character size in object coordinates.*/
2003-03-04 04:24:49 +08:00
void setCharacterSize(float height,float aspectRatio=1.0f);
float getCharacterHeight() const { return _characterHeight; }
float getCharacterAspectRatio() const { return _characterAspectRatio; }
2003-06-24 23:40:09 +08:00
enum CharacterSizeMode
{
OBJECT_COORDS, /// default
SCREEN_COORDS, /// internally scale the characters to be constant screen size.
OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT /// text that behavaves like OBJECT_COORDS sized text when a long distance way, but has its screen sized capped automatically when the viewer gets near.
};
/** Set how the CharacterSize value relates to the final rendered character.*/
void setCharacterSizeMode(CharacterSizeMode mode) { _characterSizeMode = mode; }
/** Get the CharacterSizeMode.*/
CharacterSizeMode getCharacterSizeMode() const { return _characterSizeMode; }
/** Set the maximum width of the text box.
* With horizontal layouts any characters which do not fit are wrapped around.
* 0 or negative values indicate that no maximum width is set, lines can be as long as
* they need be to fit thre required text*/
void setMaximumWidth(float maximumWidth);
/** Get the maximim width of the text box.*/
float getMaximumWidth() const { return _maximumWidth; }
/** Set the maximum height of the text box.
* With horizontal layouts any characters which do not fit are wrapped around.
* 0 or negative values indicate that no maximum height is set, lines can be as long as
* they need be to fit the required text*/
void setMaximumHeight(float maximumHeight);
/** Get the maximum height of the text box.*/
float getMaximumHeight() const { return _maximumHeight; }
/** Set the line spacing of the text box, given as a percentage of
* the character height. The default value is 0 for backward
* compatibility. For longer paragraphs of text, a value of at
* least 25% (i.e. set line spacing to 0.25) is recommended. */
void setLineSpacing(float lineSpacing);
/** Get the line spacing of the text box. */
float getLineSpacing() const { return _lineSpacing; }
/** Set the position of text.*/
void setPosition(const osg::Vec3& pos);
/** Get the position of text.*/
const osg::Vec3& getPosition() const { return _position; }
enum AlignmentType
{
LEFT_TOP,
LEFT_CENTER,
LEFT_BOTTOM,
CENTER_TOP,
CENTER_CENTER,
CENTER_BOTTOM,
RIGHT_TOP,
RIGHT_CENTER,
RIGHT_BOTTOM,
LEFT_BASE_LINE,
CENTER_BASE_LINE,
RIGHT_BASE_LINE,
2005-11-18 01:44:48 +08:00
LEFT_BOTTOM_BASE_LINE,
CENTER_BOTTOM_BASE_LINE,
RIGHT_BOTTOM_BASE_LINE,
2005-11-18 01:44:48 +08:00
BASE_LINE = LEFT_BASE_LINE /// default.
};
void setAlignment(AlignmentType alignment);
AlignmentType getAlignment() const { return _alignment; }
enum AxisAlignment
{
XY_PLANE,
2003-12-20 22:20:48 +08:00
REVERSED_XY_PLANE,
XZ_PLANE,
2003-12-20 22:20:48 +08:00
REVERSED_XZ_PLANE,
YZ_PLANE,
2003-12-20 22:20:48 +08:00
REVERSED_YZ_PLANE,
SCREEN
};
void setAxisAlignment(AxisAlignment axis);
void setRotation(const osg::Quat& quat);
2003-06-24 23:40:09 +08:00
const osg::Quat& getRotation() const { return _rotation; }
void setAutoRotateToScreen(bool autoRotateToScreen);
bool getAutoRotateToScreen() const { return _autoRotateToScreen; }
enum Layout
{
LEFT_TO_RIGHT, /// default
RIGHT_TO_LEFT,
VERTICAL
};
void setLayout(Layout layout);
Layout getLayout() const { return _layout; }
void setColor(const osg::Vec4& color);
const osg::Vec4& getColor() const { return _color; }
enum DrawModeMask
{
TEXT = 1, /// default
BOUNDINGBOX = 2,
ALIGNMENT = 4
};
void setDrawMode(unsigned int mode);
unsigned int getDrawMode() const { return _drawMode; }
enum BackdropType
{
DROP_SHADOW_BOTTOM_RIGHT = 0, // usually the type of shadow you see
DROP_SHADOW_CENTER_RIGHT,
DROP_SHADOW_TOP_RIGHT,
DROP_SHADOW_BOTTOM_CENTER,
DROP_SHADOW_TOP_CENTER,
DROP_SHADOW_BOTTOM_LEFT,
DROP_SHADOW_CENTER_LEFT,
DROP_SHADOW_TOP_LEFT,
OUTLINE,
NONE
};
enum BackdropImplementation
{
/* POLYGON_OFFSET:
* This uses glPolygonOffset to draw the text multiple times to
* create the drop-shadow and outline effects. glPolygonOffset
* is used to prevent z-fighting of the overlapping text.
* This probably should have been the best option, but all the ATI
* cards we have encountered so far have serious problems with this.
* We see little white holes/artifacts in the rendered glyph textures
* which move around depending on the viewing angle. For moving text,
* the moving holes give an extremely unpleasant flickering effect.
* Pumping up the "units" parameter in glPolygonOffset can minimize
* this problem, but two other bad side-effects occur if you do this.
* First, high values will cause problems with clipping, particularly
* when there are objects behind the text. The drop-shadows or outline
* may be culled because their computed offset is behind the object or
* z-far plane. Second, there is an additional problem associated with
* the Z-slope. High values can make large chunks of the backdrop
* suddenly disappear. This can be reduced by the "factor" parameter.
* Making the "factor" value small, can help, but experimentally, we've
* found that it creates a new, different kind of z-fighting problem.
* So there is no perfect solution. With units, you trade off the 'holes'
* for the large-section clipping.
* Experimentally, we have found units values from 150-512 to be tolerable
* to acceptable with respect to the 'holes'. A factor of .1 seems to
* bring down the large clipping problem without creating a new z-fighting
* problem.
* (You can experiment with these numbers by playing with the
* osg:PolygonOffset multipliers which this backend tries to respect.)
*
* If ATI ever fixes their cards/drivers, then this might become the
* best option.*/
POLYGON_OFFSET = 0,
/* NO_DEPTH_BUFFER
* Instead of using glPolygonOffset to prevent z-fighting, this mode
* just disables the depth buffer when rendering the text. This allows
* the text to be rendered without any z-fighting. The downside to this
* mode is that render order begins to matter and the text will not
* necessarily correctly appear above or behind other objects in the
* scene based on depth values.
* This mode is best for text that only needs to be ontop and
* not obscured by any objects.*/
NO_DEPTH_BUFFER,
/* DEPTH_RANGE
* This mode is inspired by Paul Martz's OpenGL FAQ, item 13.050.
* This uses glDepthRange as a substitute for glPolygonOffset.
* Strangely, experiments on ATI cards seem to produce cleaner results
* than when using glPolygonOffset. The trade-off for this is that the
* backdrop still may be placed too far back and might be culled by objects
* directly behind the object or by the far z-plane. If ATI ever fixes
* the glPolygonOffset problem, polygon offset is probably a slightly
* better solution because you can use smaller offsets. But with the
* current ATI problem, this option may be preferable.*/
DEPTH_RANGE,
/* STENCIL_BUFFER
* (Assuming the backend is written correctly,) the Stencil Buffer is
* the most "correct" and reliable way of producing backdrop text.
* The stencil buffer is a multipass system that allows writing to the
* same z-values without needing to resort to offsets. This implementation
* should not have any of the problems associated with the 3 previous
* implementations. But the trade-off for this mode is that without
* hardware acceleration for the stencil buffer, rendering will be
* extremely slow. (There is also potentially more overhead for this
* algorithm so it could be slower than the other implementations.
* Benchmarking would be required to determine if the speed differences
* are significant on your particular hardware.) This mode is best for
* when quality is important and stencil buffer hardware acceleration
* is available.*/
STENCIL_BUFFER
};
/**
* BackdropType gives you a background shadow text behind your regular
* text. This helps give text extra contrast which can be useful when
* placing text against noisy backgrounds.
* The color of the background shadow text is specified by setBackdropColor().
* DROP_SHADOW_BOTTOM_RIGHT will draw backdrop text to the right and down of
* the normal text. Other DROW_SHADOW_* modes do the same for their repective directions.
* OUTLINE will draw backdrop text so that it appears the text has an outline
* or border around the normal text. This mode is particularly useful against
* really noisy backgrounds that may put text on top of things that have
* all types of colors which you don't have control over.
* Some real world examples of this general technique in use that I know of
* are Google Earth, Sid Meier's Pirates (2004 Remake), and Star Control 2 (PC 1993).
* The default is NONE.
*/
void setBackdropType(BackdropType type);
BackdropType getBackdropType() const { return _backdropType; }
/**
* Sets the amount text is offset to create the backdrop/shadow effect.
* Set the value too high and for example, in OUTLINE mode you will get a "Brady Bunch"
* effect where you see duplicates of the text in a 3x3 grid.
* Set the value too small and you won't see anything.
* The values represent percentages. 1.0 means 100% so a value of 1.0
* in DROW_SHADOW_LEFT_CENTER mode would cause each glyph to be echoed
* next to it self. So the letter 'e' might look like 'ee'.
* Good values tend to be in the 0.03 to 0.10 range (but will be subject
* to your specific font and display characteristics).
* Note that the text bounding boxes are updated to include backdrop offsets.
* However, other metric information such as getCharacterHeight() are unaffected
* by this. This means that individual glyph spacing (kerning?) are unchanged
* even when this mode is used.
* The default is 0.07 (7% offset).
*/
void setBackdropOffset(float offset = 0.07f);
/**
* This overloaded version lets you specify the offset for the horizontal
* and vertical components separately.
*/
void setBackdropOffset(float horizontal, float vertical);
2006-11-08 19:49:35 +08:00
float getBackdropHorizontalOffset() const { return _backdropHorizontalOffset; }
float getBackdropVerticalOffset() const { return _backdropVerticalOffset; }
/**
* This specifies the color of the backdrop text.
* The default is black.
*/
void setBackdropColor(const osg::Vec4& color);
const osg::Vec4& getBackdropColor() const { return _backdropColor; }
/**
* This specifies the underlying backdrop rendering implementation.
* Unfortunately, at this time, there is no "perfect" rendering solution
* so this function is provided to let you 'pick your poison'. Each
* implementation has trade-offs. See BackdropImplementation enum
* docs for details.*/
void setBackdropImplementation(BackdropImplementation implementation);
BackdropImplementation getBackdropImplementation() const { return _backdropImplementation; }
enum ColorGradientMode
{
SOLID = 0, // a.k.a. ColorGradients off
PER_CHARACTER,
OVERALL
};
/**
* This sets different types of text coloring modes.
* When the coloring mode is not set to SOLID, the
* colors specified in setColorGradientCorners() determine
* the colors for the text.
* When the gradient mode is OVERALL, the coloring scheme
* attempts to approximate the effect as if the entire text box/region
* were a single polygon and you had applied colors to each of the four
* corners with GL_SMOOTH enabled. In this mode, OpenGL interpolates
* the colors across the polygon, and this is what OVERALL tries to
* emulate. This can be used to give nice embellishments on things
* like logos and names.
* PER_CHARACTER is similar to OVERALL except that it applies the
* color interpolation to the four corners of each character instead
* of across the overall text box.
* The default is SOLID (a.k.a. off).
*/
void setColorGradientMode(ColorGradientMode mode);
ColorGradientMode getColorGradientMode() const { return _colorGradientMode; }
/**
* Used only for gradient mode, let's you specify the colors of the 4 corners.
* If ColorGradients are off, these values are ignored (and the value from setColor()
* is the only one that is relevant.
*/
void setColorGradientCorners(const osg::Vec4& topLeft, const osg::Vec4& bottomLeft, const osg::Vec4& bottomRight, const osg::Vec4& topRight);
const osg::Vec4& getColorGradientTopLeft() const { return _colorGradientTopLeft; }
const osg::Vec4& getColorGradientBottomLeft() const { return _colorGradientBottomLeft; }
const osg::Vec4& getColorGradientBottomRight() const { return _colorGradientBottomRight; }
const osg::Vec4& getColorGradientTopRight() const { return _colorGradientTopRight; }
void setKerningType(KerningType kerningType) { _kerningType = kerningType; }
KerningType getKerningType() const { return _kerningType; }
2005-12-08 16:57:16 +08:00
/** Get the number of wrapped lines - only valid after computeGlyphRepresentation() has been called, returns 0 otherwise */
unsigned int getLineCount() const { return _lineCount; }
/** Draw the text.*/
virtual void drawImplementation(osg::RenderInfo& renderInfo) const;
2003-03-11 00:40:26 +08:00
/** return false, osgText::Text does not support accept(AttributeFunctor&).*/
virtual bool supports(const osg::Drawable::AttributeFunctor&) const { return false; }
2003-03-11 00:40:26 +08:00
/** return true, osgText::Text does support accept(ConstAttributeFunctor&).*/
virtual bool supports(const osg::Drawable::ConstAttributeFunctor&) const { return true; }
2003-03-11 00:40:26 +08:00
/** accept an ConstAttributeFunctor and call its methods to tell it about the interal attributes that this Drawable has.*/
virtual void accept(osg::Drawable::ConstAttributeFunctor& af) const;
/** return true, osgText::Text does support accept(PrimitiveFunctor&) .*/
virtual bool supports(const osg::PrimitiveFunctor&) const { return true; }
2003-03-11 00:40:26 +08:00
/** accept a PrimtiveFunctor and call its methods to tell it about the interal primtives that this Drawable has.*/
virtual void accept(osg::PrimitiveFunctor& pf) const;
2003-03-11 00:40:26 +08:00
/** Set whether to use a mutex to ensure ref() and unref() are thread safe.*/
virtual void setThreadSafeRefUnref(bool threadSafe);
/** Resize any per context GLObject buffers to specified size. */
virtual void resizeGLObjectBuffers(unsigned int maxSize);
/** If State is non-zero, this function releases OpenGL objects for
* the specified graphics context. Otherwise, releases OpenGL objexts
* for all graphics contexts. */
virtual void releaseGLObjects(osg::State* state=0) const;
2003-03-11 00:40:26 +08:00
// make Font a friend to allow it set the _font to 0 if the font is
// forcefully unloaded.
friend class Font;
public:
// internal structures, variable and methods used for rendering of characters.
struct OSGTEXT_EXPORT GlyphQuads
{
typedef std::vector<Font::Glyph*> Glyphs;
typedef std::vector<unsigned int> LineNumbers;
typedef std::vector<osg::Vec2> Coords2;
typedef std::vector<osg::Vec3> Coords3;
typedef std::vector<osg::Vec2> TexCoords;
typedef std::vector<osg::Vec4> ColorCoords;
Glyphs _glyphs;
Coords2 _coords;
osg::buffered_object<Coords3> _transformedCoords;
TexCoords _texcoords;
LineNumbers _lineNumbers;
osg::buffered_object<Coords3> _transformedBackdropCoords[8];
ColorCoords _colorCoords;
Glyphs getGlyphs() { return _glyphs; }
const Glyphs getGlyphs() const { return _glyphs; }
Coords2& getCoords() { return _coords; }
const Coords2& getCoords() const { return _coords; }
Coords3& getTransformedCoords(unsigned int contexID) { return _transformedCoords[contexID]; }
const Coords3& getTransformedCoords(unsigned int contexID) const { return _transformedCoords[contexID]; }
TexCoords& getTexCoords() { return _texcoords; }
const TexCoords& getTexCoords() const { return _texcoords; }
LineNumbers& getLineNumbers() { return _lineNumbers; }
const LineNumbers& getLineNumbers() const { return _lineNumbers; }
};
typedef std::map<osg::ref_ptr<Font::GlyphTexture>,GlyphQuads> TextureGlyphQuadMap;
/** Direct Access to GlyphQuads */
const GlyphQuads* getGlyphQuads(Font::GlyphTexture* texture) const
{
TextureGlyphQuadMap::iterator itGlyphQuad = _textureGlyphQuadMap.find(texture);
if (itGlyphQuad == _textureGlyphQuadMap.end()) return NULL;
return &itGlyphQuad->second;
}
const TextureGlyphQuadMap& getTextureGlyphQuadMap() const
{
return _textureGlyphQuadMap;
}
virtual osg::BoundingBox computeBound() const;
protected:
virtual ~Text();
Font* getActiveFont();
const Font* getActiveFont() const;
String::iterator computeLastCharacterOnLine(osg::Vec2& cursor, String::iterator first,String::iterator last);
// members which have public access.
osg::ref_ptr<Font> _font;
unsigned int _fontWidth;
unsigned int _fontHeight;
float _characterHeight;
float _characterAspectRatio;
2003-06-24 23:40:09 +08:00
CharacterSizeMode _characterSizeMode;
float _maximumWidth;
float _maximumHeight;
float _lineSpacing;
String _text;
osg::Vec3 _position;
AlignmentType _alignment;
2003-06-24 23:40:09 +08:00
osg::Quat _rotation;
bool _autoRotateToScreen;
Layout _layout;
osg::Vec4 _color;
unsigned int _drawMode;
KerningType _kerningType;
unsigned int _lineCount;
// iternal map used for rendering. Set up by the computeGlyphRepresentation() method.
2003-06-24 23:40:09 +08:00
mutable TextureGlyphQuadMap _textureGlyphQuadMap;
void computeGlyphRepresentation();
// internal caches of the positioning of the text.
2003-06-24 23:40:09 +08:00
struct AutoTransformCache
{
AutoTransformCache():
_traversalNumber(-1),
_width(0),
_height(0) {}
int _traversalNumber;
int _width;
int _height;
osg::Vec3 _transformedPosition;
osg::Matrix _modelview;
osg::Matrix _projection;
osg::Matrix _matrix;
};
mutable osg::buffered_object<AutoTransformCache> _autoTransformCache;
mutable osg::Vec3 _offset;
mutable osg::Vec3 _normal;
mutable osg::BoundingBox _textBB;
bool computeAverageGlyphWidthAndHeight(float& avg_width, float& avg_height) const;
void computePositions();
2003-06-24 23:40:09 +08:00
void computePositions(unsigned int contextID) const;
void computeBackdropPositions(unsigned int contextID) const;
void computeBackdropBoundingBox() const;
void computeColorGradients() const;
void computeColorGradientsOverall() const;
void computeColorGradientsPerCharacter() const;
void drawImplementation(osg::State& state, const osg::Vec4& colorMultiplier) const;
void drawForegroundText(osg::State& state, const GlyphQuads& glyphquad, const osg::Vec4& colorMultiplier) const;
void renderOnlyForegroundText(osg::State& state, const osg::Vec4& colorMultiplier) const;
void renderWithPolygonOffset(osg::State& state, const osg::Vec4& colorMultiplier) const;
void renderWithNoDepthBuffer(osg::State& state, const osg::Vec4& colorMultiplier) const;
void renderWithDepthRange(osg::State& state, const osg::Vec4& colorMultiplier) const;
void renderWithStencilBuffer(osg::State& state, const osg::Vec4& colorMultiplier) const;
BackdropType _backdropType;
BackdropImplementation _backdropImplementation;
float _backdropHorizontalOffset;
float _backdropVerticalOffset;
osg::Vec4 _backdropColor;
ColorGradientMode _colorGradientMode;
osg::Vec4 _colorGradientTopLeft;
osg::Vec4 _colorGradientBottomLeft;
osg::Vec4 _colorGradientBottomRight;
osg::Vec4 _colorGradientTopRight;
// Helper functions for color interpolation
float bilinearInterpolate(float x1, float x2, float y1, float y2, float x, float y, float q11, float q12, float q21, float q22) const;
void convertHsvToRgb( float hsv[], float rgb[] ) const;
void convertRgbToHsv( float rgb[], float hsv[] ) const;
};
}
#endif