Font_TextFormatter inherits Standard_Transient, now it is given as a handle in functions.
Graphic3d_Text - extended with Font_TextFormatter to be able to have it filled out of text render. If it is not defined here, the default text formatter of context is used.
OpenGl_Context - has default Font_TextFormatter for rendering OpenGl_Text.
#define Font_BRepTextBuilder_Header
#include <StdPrs_BRepTextBuilder.hxx>
+class Font_TextFormatter;
+
//! Alias for porting from old name.
typedef StdPrs_BRepTextBuilder Font_BRepTextBuilder;
#include <Font_FTFont.hxx>
+#include <Precision.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT (Font_TextFormatter, Standard_Transient)
+
namespace
{
typedef NCollection_Vec2<Standard_ShortReal> Vec2f;
: myAlignX (Graphic3d_HTA_LEFT),
myAlignY (Graphic3d_VTA_TOP),
myTabSize (8),
+ myWrappingWidth (0.0f),
+ myLastSymbolWidth (0.0f),
+ myMaxSymbolWidth (0.0f),
//
myPen (0.0f, 0.0f),
- myRectsNb (0),
myLineSpacing (0.0f),
myAscender (0.0f),
myIsFormatted (false),
//
myLinesNb (0),
myRectLineStart (0),
- myRectWordStart (0),
myNewLineNb(0),
myPenCurrLine (0.0f),
myBndTop (0.0f),
myIsFormatted = false;
myString.Clear();
myPen.x() = myPen.y() = 0.0f;
- myRectsNb = 0;
myLineSpacing = myAscender = 0.0f;
myCorners.Clear();
myNewLines.Clear();
+
+ myLastSymbolWidth = 0.0f;
+ myMaxSymbolWidth = 0.0f;
}
// =======================================================================
int aSymbolsCounter = 0; // special counter to process tabulation symbols
// first pass - render all symbols using associated font on single ZERO baseline
- for (NCollection_Utf8Iter anIter = theString.Iterator(); *anIter != 0;)
+ Standard_Utf32Char aCharThis;
+ for (Font_TextFormatter::Iterator aFormatterIt (*this); aFormatterIt .More(); aFormatterIt .Next())
{
- const Standard_Utf32Char aCharThis = *anIter;
- const Standard_Utf32Char aCharNext = *++anIter;
-
- if (aCharThis == '\x0D' // CR (carriage return)
- || aCharThis == '\a' // BEL (alarm)
- || aCharThis == '\f' // FF (form feed) NP (new page)
- || aCharThis == '\b' // BS (backspace)
- || aCharThis == '\v') // VT (vertical tab)
+ aCharThis = aFormatterIt.Symbol();
+ const Standard_Utf32Char aCharNext = aFormatterIt.SymbolNext();
+
+ Standard_ShortReal anAdvanceX = 0;
+ if (IsCommandSymbol (aCharThis))
{
continue; // skip unsupported carriage control codes
}
{
aSymbolsCounter = 0;
myNewLines.Append (myPen.x());
- continue; // will be processed on second pass
+ anAdvanceX = 0; // the symbol has null width
}
else if (aCharThis == ' ')
{
++aSymbolsCounter;
- myPen.x() += theFont.AdvanceX (' ', aCharNext);
- continue;
+ anAdvanceX = theFont.AdvanceX (' ', aCharNext);
}
else if (aCharThis == '\t')
{
const Standard_Integer aSpacesNum = (myTabSize - (aSymbolsCounter - 1) % myTabSize);
- myPen.x() += theFont.AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum);
+ anAdvanceX = theFont.AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum);
aSymbolsCounter += aSpacesNum;
- continue;
}
+ else
+ anAdvanceX = theFont.AdvanceX (aCharThis, aCharNext);
++aSymbolsCounter;
-
myCorners.Append (myPen);
-
- myPen.x() += theFont.AdvanceX (aCharThis, aCharNext);
-
- ++myRectsNb;
+ myPen.x() += anAdvanceX;
+ myMaxSymbolWidth = Max (myMaxSymbolWidth, anAdvanceX);
}
+ myLastSymbolWidth = myPen.x() - myCorners.Last().x();
}
// =======================================================================
// function : newLine
// purpose :
// =======================================================================
-void Font_TextFormatter::newLine (const Standard_Integer theLastRect)
+void Font_TextFormatter::newLine (const Standard_Integer theLastRect,
+ const Standard_ShortReal theMaxLineWidth)
{
- if (myRectLineStart >= myRectsNb)
+ Standard_Integer aFirstCornerId = myRectLineStart;
+ Standard_Integer aLastCornerId = theLastRect;
+
+ if (aFirstCornerId >= myCorners.Length())
{
++myLinesNb;
myPenCurrLine -= myLineSpacing;
return;
}
+ Standard_ShortReal aXMin = BottomLeft (aFirstCornerId).x();
+ Font_Rect aBndBox;
+ BndBox (aLastCornerId, aBndBox);
+ Standard_ShortReal aXMax = aBndBox.Right;
+
myMoveVec.y() = myPenCurrLine;
switch (myAlignX)
{
default:
- case Graphic3d_HTA_LEFT:
- {
- myMoveVec.x() = (myNewLineNb > 0) ? -myNewLines.Value (myNewLineNb - 1) : 0.0f;
- break;
- }
- case Graphic3d_HTA_RIGHT:
- {
- myMoveVec.x() = (myNewLineNb < myNewLines.Length())
- ? -myNewLines.Value (myNewLineNb)
- : -myPen.x();
- break;
- }
- case Graphic3d_HTA_CENTER:
- {
- const Standard_ShortReal aFrom = (myNewLineNb > 0)
- ? myNewLines.Value (myNewLineNb - 1)
- : 0.0f;
- const Standard_ShortReal aTo = (myNewLineNb < myNewLines.Length())
- ? myNewLines.Value (myNewLineNb)
- : myPen.x();
- myMoveVec.x() = -0.5f * (aFrom + aTo);
- break;
- }
+ case Graphic3d_HTA_LEFT: myMoveVec.x() = -aXMin; break;
+ case Graphic3d_HTA_RIGHT: myMoveVec.x() = -aXMin + (theMaxLineWidth - (aXMax - aXMin)) - theMaxLineWidth; break;
+ case Graphic3d_HTA_CENTER: myMoveVec.x() = -aXMin + 0.5f * (theMaxLineWidth - (aXMax - aXMin)) - 0.5f * theMaxLineWidth; break;
}
move (myCorners, myMoveVec, myRectLineStart, theLastRect);
++myLinesNb;
myPenCurrLine -= myLineSpacing;
- myRectLineStart = myRectWordStart = theLastRect + 1;
+ myRectLineStart = theLastRect + 1;
}
// =======================================================================
// =======================================================================
void Font_TextFormatter::Format()
{
- if (myRectsNb == 0 || myIsFormatted)
+ if (myCorners.Length() == 0 || myIsFormatted)
{
return;
}
myIsFormatted = true;
- myLinesNb = myRectLineStart = myRectWordStart = 0;
+ myLinesNb = myRectLineStart = 0;
myBndTop = 0.0f;
myBndWidth = 0.0f;
myMoveVec.x() = myMoveVec.y() = 0.0f;
myPenCurrLine = -myAscender;
Standard_Integer aRectIter = 0;
myNewLineNb = 0;
- Standard_ShortReal aMaxLineWidth = -1.0f;
- for (NCollection_Utf8Iter anIter = myString.Iterator(); *anIter != 0; ++anIter)
+
+ Standard_ShortReal aMaxLineWidth = Wrapping();
+ if (HasWrapping())
{
- const Standard_Utf32Char aCharThis = *anIter;
- if (aCharThis == '\x0D' // CR (carriage return)
- || aCharThis == '\a' // BEL (alarm)
- || aCharThis == '\f' // FF (form feed) NP (new page)
- || aCharThis == '\b' // BS (backspace)
- || aCharThis == '\v') // VT (vertical tab)
+ aMaxLineWidth = Max (aMaxLineWidth, MaximumSymbolWidth()); // it is not possible to wrap less than symbol width
+ }
+ else
+ {
+ if (myNewLines.IsEmpty()) // If only one line
+ aMaxLineWidth = myPen.x();
+ else
{
- continue; // skip unsupported carriage control codes
+ for (int aLineIt = 0; aLineIt < myNewLines.Size(); aLineIt++)
+ aMaxLineWidth = Max (aMaxLineWidth, LineWidth (aLineIt));
+ aMaxLineWidth = Max (aMaxLineWidth, LineWidth (myNewLines.Size())); // processing the last line also
}
- else if (aCharThis == '\x0A') // LF (line feed, new line)
- {
- // calculate max line width
- if (myNewLineNb == 0)
- {
- aMaxLineWidth = myNewLines.Value(0);
- }
- else
- {
- aMaxLineWidth = Max (aMaxLineWidth, myNewLines.Value (myNewLineNb) - myNewLines.Value (myNewLineNb - 1));
- }
+ }
- const Standard_Integer aLastRect = aRectIter - 1; // last rect on current line
- newLine (aLastRect);
+ for (Font_TextFormatter::Iterator aFormatterIt (*this);
+ aFormatterIt .More(); aFormatterIt .Next())
+ {
+ const Standard_Utf32Char aCharThis = aFormatterIt.Symbol();
+ aRectIter = aFormatterIt.SymbolPosition();
+
+ if (aCharThis == '\x0A') // LF (line feed, new line)
+ {
+ const Standard_Integer aLastRect = aRectIter; // last rect on current line
+ newLine (aLastRect, aMaxLineWidth);
++myNewLineNb;
continue;
}
- else if (aCharThis == ' '
- || aCharThis == '\t')
+ else if (HasWrapping()) // wrap lines longer than maximum width
{
- myRectWordStart = aRectIter;
- continue;
- }
-
- ++aRectIter;
- }
+ Standard_Integer aFirstCornerId = myRectLineStart;
- // If only one line
- if (aMaxLineWidth < 0.0f)
- {
- aMaxLineWidth = myPen.x();
- }
- else // Consider last line
- {
- aMaxLineWidth = Max (aMaxLineWidth, myPen.x() - myNewLines.Value (myNewLineNb - 1));
+ Font_Rect aBndBox;
+ BndBox (aRectIter, aBndBox);
+ const Standard_ShortReal aNextXPos = aBndBox.Right - BottomLeft (aFirstCornerId).x();
+ if (aNextXPos > aMaxLineWidth) // wrap the line and do processing of the symbol
+ {
+ const Standard_Integer aLastRect = aRectIter - 1; // last rect on current line
+ newLine (aLastRect, aMaxLineWidth);
+ }
+ }
}
myBndWidth = aMaxLineWidth;
// move last line
- newLine (myRectsNb - 1);
+ newLine (myCorners.Length() - 1, aMaxLineWidth);
// apply vertical alignment style
if (myAlignY == Graphic3d_VTA_BOTTOM)
if (myAlignY != Graphic3d_VTA_TOP)
{
- moveY (myCorners, myBndTop, 0, myRectsNb - 1);
+ moveY (myCorners, myBndTop, 0, myCorners.Length() - 1);
}
}
+
+// =======================================================================
+// function : BndBox
+// purpose :
+// =======================================================================
+Standard_Boolean Font_TextFormatter::BndBox (const Standard_Integer theIndex, Font_Rect& theBndBox) const
+{
+ if (theIndex < 0 || theIndex >= Corners().Size())
+ return Standard_False;
+
+ const NCollection_Vec2<Standard_ShortReal>& aLeftCorner = BottomLeft (theIndex);
+ if (theIndex + 1 < myCorners.Length()) // not the last symbol
+ {
+ const NCollection_Vec2<Standard_ShortReal>& aNextLeftCorner = BottomLeft (theIndex + 1);
+ theBndBox.Left = aLeftCorner.x();
+ theBndBox.Bottom = aLeftCorner.y();
+ theBndBox.Top = theBndBox.Bottom + myLineSpacing;
+ if (Abs (aLeftCorner.y() - aNextLeftCorner.y()) < Precision::Confusion()) // in the same row
+ {
+ theBndBox.Right = aNextLeftCorner.x();
+ }
+ else
+ {
+ // the next symbol is on the next row either by '\n' or by wrapping
+ Standard_ShortReal aLineWidth = LineWidth (LineIndex (theIndex));
+ theBndBox.Left = aLeftCorner.x();
+ switch (myAlignX)
+ {
+ case Graphic3d_HTA_LEFT: theBndBox.Right = aLineWidth; break;
+ case Graphic3d_HTA_RIGHT: theBndBox.Right = myBndWidth; break;
+ case Graphic3d_HTA_CENTER: theBndBox.Right = 0.5f * (myBndWidth + aLineWidth); break;
+ }
+ }
+ }
+ else // the last symbol
+ {
+ theBndBox.Left = aLeftCorner.x();
+ theBndBox.Right = aLeftCorner.x() + myLastSymbolWidth;
+ theBndBox.Bottom = aLeftCorner.y();
+ theBndBox.Top = theBndBox.Bottom + myLineSpacing;
+ }
+ return Standard_True;
+}
+
+
+// =======================================================================
+// function : IsLFSymbol
+// purpose :
+// =======================================================================
+Standard_Boolean Font_TextFormatter::IsLFSymbol (const Standard_Integer theIndex) const
+{
+ Font_Rect aBndBox;
+ if (!BndBox (theIndex, aBndBox))
+ return Standard_False;
+
+ return Abs (aBndBox.Right - aBndBox.Left) < Precision::Confusion();
+}
+
+// =======================================================================
+// function : FirstPosition
+// purpose :
+// =======================================================================
+Standard_ShortReal Font_TextFormatter::FirstPosition() const
+{
+ switch (myAlignX)
+ {
+ default:
+ case Graphic3d_HTA_LEFT: return 0; break;
+ case Graphic3d_HTA_RIGHT: return myBndWidth; break;
+ case Graphic3d_HTA_CENTER: return 0.5f * myBndWidth; break;
+ }
+}
+
+// =======================================================================
+// function : LinePositionIndex
+// purpose :
+// =======================================================================
+Standard_Integer Font_TextFormatter::LinePositionIndex (const Standard_Integer theIndex) const
+{
+ Standard_Integer anIndex = 0;
+
+ Standard_ShortReal anIndexHeight = BottomLeft (theIndex).y();
+ for (Standard_Integer aPrevIndex = theIndex-1; aPrevIndex >= 0; aPrevIndex--)
+ {
+ if (BottomLeft (aPrevIndex).y() > anIndexHeight)
+ break;
+ anIndex++;
+ }
+ return anIndex;
+}
+
+// =======================================================================
+// function : LineIndex
+// purpose :
+// =======================================================================
+Standard_Integer Font_TextFormatter::LineIndex (const Standard_Integer theIndex) const
+{
+ if (myLineSpacing < 0.0f)
+ return 0;
+
+ return (Standard_Integer)Abs((BottomLeft (theIndex).y() + myAscender) / myLineSpacing);
+}
+
+// =======================================================================
+// function : LineWidth
+// purpose :
+// =======================================================================
+Standard_ShortReal Font_TextFormatter::LineWidth (const Standard_Integer theIndex) const
+{
+ if (theIndex < 0)
+ return 0;
+
+ if (theIndex < myNewLines.Length())
+ return theIndex == 0 ? myNewLines[0] : myNewLines[theIndex] - myNewLines[theIndex -1];
+
+ if (theIndex == myNewLines.Length()) // the last line
+ return theIndex == 0 ? myPen.x() : myPen.x() - myNewLines[theIndex -1];
+
+ return 0;
+}
class Font_FTFont;
+DEFINE_STANDARD_HANDLE(Font_TextFormatter, Standard_Transient)
+
//! This class intended to prepare formatted text.
-class Font_TextFormatter
+//! Case of the formatter using:
+//! Handle(Font_TextFormatter) aFormatter = new Font_TextFormatter();
+//! aFormatter->Append(text_1, aFont1);
+//! aFormatter->Append(text_2, aFont2);
+//! aFormatter->Format();
+//!
+//! Example of corners indices for the text:
+//! "row_1\n" - 0-5
+//! "\n" - 6
+//! "\n" - 7
+//! "row_2\n" - 8-13
+//! Processing of \n symbol:
+//! - it is placed on the row where it appears
+//! - BndBox for \n has zero width
+//! - if the last symbol is \n, use LastBndBox() to get position on the next row
+//!
+//! Pay attention that fonts should have the same LineSpacing value
+//!
+class Font_TextFormatter : public Standard_Transient
{
public:
+ //! Iteration filter flags. Command symbols are skipped with any filter.
+ enum IterationFilter
+ {
+ IterationFilter_None = 0x0000, //!< no filter
+ IterationFilter_ExcludeInvisible = 0x0002, //!< exclude ' ', '\t', '\n'
+ };
+
+ //! Iterator through light sources.
+ class Iterator
+ {
+ public:
+ //! Constructor with initialization.
+ Iterator (const Font_TextFormatter& theFormatter,
+ IterationFilter theFilter = IterationFilter_None)
+ : myFilter (theFilter), myIter (theFormatter.myString.Iterator())
+ {
+ mySymbolPosition = readNextSymbol (-1, mySymbolChar);
+ mySymbolNext = readNextSymbol (mySymbolPosition, mySymbolCharNext);
+ }
+
+ //! Returns TRUE if iterator points to a valid item.
+ Standard_Boolean More() const { return mySymbolPosition >= 0; }
+
+ //! Returns TRUE if next item exists
+ Standard_Boolean HasNext() const { return mySymbolNext >= 0; }
+
+ //! Returns current symbol.
+ Standard_Utf32Char Symbol() const { return mySymbolChar; }
+
+ //! Returns the next symbol if exists.
+ Standard_Utf32Char SymbolNext() const { return mySymbolCharNext; }
+
+ //! Returns current symbol position.
+ Standard_Integer SymbolPosition() const { return mySymbolPosition; }
+
+ //! Returns the next symbol position.
+ Standard_Integer SymbolPositionNext() const { return mySymbolNext; }
+
+ //! Moves to the next item.
+ void Next()
+ {
+ mySymbolPosition = mySymbolNext;
+ mySymbolChar = mySymbolCharNext;
+ mySymbolNext = readNextSymbol (mySymbolPosition, mySymbolCharNext);
+ }
+
+ protected:
+ Standard_Integer readNextSymbol (const Standard_Integer aSymbolStartingFrom, Standard_Utf32Char& theSymbolChar)
+ {
+ Standard_Integer aNextSymbol = aSymbolStartingFrom;
+ for (; *myIter != 0; ++myIter)
+ {
+ const Standard_Utf32Char aCharCurr = *myIter;
+ if (Font_TextFormatter::IsCommandSymbol (aCharCurr))
+ {
+ continue; // skip unsupported carriage control codes
+ }
+ aNextSymbol++;
+ if ((myFilter & IterationFilter_ExcludeInvisible) != 0)
+ {
+ if (aCharCurr == '\x0A'|| // LF (line feed, new line)
+ aCharCurr == ' ' ||
+ aCharCurr == '\t')
+ continue;
+ }
+ ++myIter;
+ theSymbolChar = aCharCurr;
+ return aNextSymbol; // found the first next, not command and not filtered symbol
+ }
+ return -1; // the next symbol is not found
+ }
+
+ protected:
+ IterationFilter myFilter; //!< possibility to filter not-necessary symbols
+
+ NCollection_Utf8Iter myIter; //!< the next symbol iterator value over the text formatter string
+ Standard_Integer mySymbolPosition; //!< the current position
+ Standard_Utf32Char mySymbolChar; //!< the current symbol
+ Standard_Integer mySymbolNext; //!< position of the next symbol in iterator, if zero, the iterator is finished
+ Standard_Utf32Char mySymbolCharNext; //!< the current symbol
+ };
//! Default constructor.
Standard_EXPORT Font_TextFormatter();
Standard_EXPORT void Format();
//! Returns specific glyph rectangle.
- inline const NCollection_Vec2<Standard_ShortReal>& TopLeft (const Standard_Integer theIndex) const
- {
- return myCorners.Value (theIndex);
- }
+ inline const NCollection_Vec2<Standard_ShortReal>& BottomLeft (const Standard_Integer theIndex) const
+ { return myCorners.Value (theIndex); }
- //! Returns current rendering string.
- inline const NCollection_String& String() const
- {
- return myString;
- }
+ //! Returns symbol bounding box
+ //! @param bounding box.
+ Standard_EXPORT Standard_Boolean BndBox (const Standard_Integer theIndex, Font_Rect& theBndBox) const;
+
+ //! Returns the line height
+ //! \param theIndex a line index, obtained by LineIndex()
+ Standard_ShortReal LineHeight (const Standard_Integer theIndex) const
+ { return theIndex == 0 ? myAscender : myLineSpacing; }
+
+ //!< Returns width of a line
+ Standard_EXPORT Standard_ShortReal LineWidth (const Standard_Integer theIndex) const;
+
+ //! Returns true if the symbol by the index is '\n'. The width of the symbol is zero.
+ Standard_EXPORT Standard_Boolean IsLFSymbol (const Standard_Integer theIndex) const;
+
+ //! Returns position of the first symbol in a line using alignment
+ Standard_EXPORT Standard_ShortReal FirstPosition() const;
+
+ //! Returns column index of the corner index in the current line
+ Standard_EXPORT Standard_Integer LinePositionIndex (const Standard_Integer theIndex) const;
+
+ //! Returns row index of the corner index among text lines
+ Standard_EXPORT Standard_Integer LineIndex (const Standard_Integer theIndex) const;
//! Returns tab size.
inline Standard_Integer TabSize() const
return myTabSize;
}
+ //!< Returns horizontal alignment style
+ Graphic3d_HorizontalTextAlignment HorizontalTextAlignment() const { return myAlignX; }
+
+ //!< Returns vertical alignment style
+ Graphic3d_VerticalTextAlignment VerticalTextAlignment() const { return myAlignY; }
+
+ //!< Sets text wrapping width, zero means that the text is not bounded by width
+ void SetWrapping (const Standard_ShortReal theWidth) { myWrappingWidth = theWidth; }
+
+ //!< Returns text maximum width, zero means that the text is not bounded by width
+ Standard_Boolean HasWrapping() const { return myWrappingWidth > 0; }
+
+ //!< Returns text maximum width, zero means that the text is not bounded by width
+ Standard_ShortReal Wrapping() const { return myWrappingWidth; }
+
//! @return width of formatted text.
inline Standard_ShortReal ResultWidth() const
{
return myLineSpacing * Standard_ShortReal(myLinesNb);
}
+ //!< @return maximum width of the text symbol
+ inline Standard_ShortReal MaximumSymbolWidth() const { return myMaxSymbolWidth; }
+
//! @param bounding box.
inline void BndBox (Font_Rect& theBndBox) const
{
theBndBox.Bottom = theBndBox.Top - myLineSpacing * Standard_ShortReal(myLinesNb);
}
+ //!< Returns internal container of the top left corners of a formatted rectangles.
+ const NCollection_Vector < NCollection_Vec2<Standard_ShortReal> >& Corners() const { return myCorners; }
+
+ const NCollection_Vector<Standard_ShortReal>& NewLines() const { return myNewLines; }
+
+ //!< Returns true if the symbol is CR, BEL, FF, NP, BS or VT
+ static inline Standard_Boolean IsCommandSymbol (const Standard_Utf32Char& theSymbol)
+ {
+ if (theSymbol == '\x0D' // CR (carriage return)
+ || theSymbol == '\a' // BEL (alarm)
+ || theSymbol == '\f' // FF (form feed) NP (new page)
+ || theSymbol == '\b' // BS (backspace)
+ || theSymbol == '\v') // VT (vertical tab)
+ return Standard_True;
+
+ return Standard_False;
+ }
+
+ DEFINE_STANDARD_RTTIEXT (Font_TextFormatter, Standard_Transient)
+
protected: //! @name class auxiliary methods
//! Move glyphs on the current line to correct position.
- Standard_EXPORT void newLine (const Standard_Integer theLastRect);
+ Standard_EXPORT void newLine (const Standard_Integer theLastRect,
+ const Standard_ShortReal theMaxLineWidth);
protected: //! @name configuration
Graphic3d_HorizontalTextAlignment myAlignX; //!< horizontal alignment style
Graphic3d_VerticalTextAlignment myAlignY; //!< vertical alignment style
Standard_Integer myTabSize; //!< horizontal tabulation width (number of space symbols)
+ Standard_ShortReal myWrappingWidth; //!< text is wrapped by the width if it is defined (more 0)
+ Standard_ShortReal myLastSymbolWidth; //!< width of the last symbol
+ Standard_ShortReal myMaxSymbolWidth; //!< maximum symbol width of the formatter string
protected: //! @name input data
myPen; //!< current pen position
NCollection_Vector < NCollection_Vec2<Standard_ShortReal> >
myCorners; //!< The top left corners of a formatted rectangles.
- Standard_Integer myRectsNb; //!< rectangles number
NCollection_Vector<Standard_ShortReal>
myNewLines; //!< position at LF
Standard_ShortReal myLineSpacing; //!< line spacing (computed as maximum of all fonts involved in text formatting)
- Standard_ShortReal myAscender; //!<
+ Standard_ShortReal myAscender; //!< line spacing for the first line
bool myIsFormatted; //!< formatting state
protected: //! @name temporary variables for formatting routines
Standard_Integer myLinesNb; //!< overall (new)lines number (including splitting by width limit)
Standard_Integer myRectLineStart; //!< id of first rectangle on the current line
- Standard_Integer myRectWordStart; //!< id of first rectangle in the current word
Standard_Integer myNewLineNb;
Standard_ShortReal myPenCurrLine; //!< current baseline position
Standard_ShortReal myBndWidth;
NCollection_Vec2<Standard_ShortReal>
myMoveVec; //!< local variable
+
+ friend Iterator;
};
#endif // Font_TextFormatter_Header
#include <gp_Ax2.hxx>
#include <Graphic3d_Vertex.hxx>
+#include <Font_TextFormatter.hxx>
#include <Graphic3d_HorizontalTextAlignment.hxx>
#include <Graphic3d_VerticalTextAlignment.hxx>
#include <NCollection_String.hxx>
//! - text formatter. Formatter contains text, height and alignment parameter.
//!
//! This class also has parameters of the text height and H/V alignments.
+//! More compilated formatting is available using Font_TextFormatter.
class Graphic3d_Text : public Standard_Transient
{
DEFINE_STANDARD_RTTIEXT(Graphic3d_Text, Standard_Transient)
//! Sets text value.
void SetText (Standard_CString theText) { myText = theText; }
+ //! @return text formatter
+ const Handle(Font_TextFormatter)& TextFormatter() const { return myFormatter; }
+
+ //! @return default formatter of text withing this context
+ void SetTextFormatter (const Handle(Font_TextFormatter)& theFormatter) { myFormatter = theFormatter; }
+
//! The 3D point of attachment is projected.
//! If the orientation is defined, the text is written in the plane of projection.
const gp_Pnt& Position() const { return myOrientation.Location(); }
void SetVerticalAlignment (const Graphic3d_VerticalTextAlignment theJustification) { myVAlign = theJustification; }
protected:
+ Handle(Font_TextFormatter) myFormatter; //!< text formatter
+
NCollection_String myText; //!< text value
gp_Ax2 myOrientation; //!< Text orientation in 3D space.
#include <Graphic3d_TransformUtils.hxx>
#include <Graphic3d_RenderingParams.hxx>
+#include <Font_TextFormatter.hxx>
+
#include <Message_Messenger.hxx>
#include <NCollection_Vector.hxx>
memset (myFuncs.operator->(), 0, sizeof(OpenGl_GlFunctions));
myShaderManager = new OpenGl_ShaderManager (this);
+
+ myDefaultFormatter = new Font_TextFormatter();
}
// =======================================================================
typedef OpenGl_TmplCore45<OpenGl_GlCore44Back> OpenGl_GlCore45Back;
typedef OpenGl_TmplCore45<OpenGl_GlCore44> OpenGl_GlCore45;
+class Font_TextFormatter;
class Graphic3d_PresentationAttributes;
class OpenGl_Aspects;
class OpenGl_FrameBuffer;
//! @return tool for management of shader programs within this context.
inline const Handle(OpenGl_ShaderManager)& ShaderManager() const { return myShaderManager; }
+ //! @return default formatter of text withing this context
+ inline const Handle(Font_TextFormatter)& DefaultTextFormatter() const { return myDefaultFormatter; }
+
public:
//! Either GL_CLAMP_TO_EDGE (1.2+) or GL_CLAMP (1.1).
Graphic3d_TextureUnit myPBRSpecIBLMapTexUnit; //!< samplerCube occSpecIBLMap, texture unit where specular IBL map is expected to be binded (0 if PBR is not supported)
Handle(OpenGl_ShaderManager) myShaderManager; //! support object for managing shader programs
+ Handle(Font_TextFormatter) myDefaultFormatter;//!< default text formatter, an alternative to text params
private: //! @name fields tracking current state
#include <Font_FontMgr.hxx>
#include <Font_FTFont.hxx>
+#include <Font_TextFormatter.hxx>
#include <Graphic3d_TransformUtils.hxx>
#include <TCollection_HAsciiString.hxx>
const OpenGl_Vec4& theColorSubs,
unsigned int theResolution) const
{
- if (myText->Text().IsEmpty())
+ if (myText->Text().IsEmpty() && myText->TextFormatter().IsNull())
{
return;
}
if (myTextures.IsEmpty())
{
- Font_TextFormatter aFormatter;
-
- aFormatter.SetupAlignment (myText->HorizontalAlignment(), myText->VerticalAlignment());
- aFormatter.Reset();
+ Handle(Font_TextFormatter) aFormatter = myText->TextFormatter();
+ if (aFormatter.IsNull())
+ {
+ aFormatter = theCtx->DefaultTextFormatter();
+ aFormatter->SetupAlignment (myText->HorizontalAlignment(), myText->VerticalAlignment());
+ aFormatter->Reset();
- aFormatter.Append (myText->Text(), *myFont->FTFont());
- aFormatter.Format();
+ aFormatter->Append (myText->Text(), *myFont->FTFont());
+ aFormatter->Format();
+ }
OpenGl_TextBuilder aBuilder;
aBuilder.Perform (aFormatter,
myVertsVbo,
myTCrdsVbo);
- aFormatter.BndBox (myBndBox);
+ aFormatter->BndBox (myBndBox);
if (!myBndVertsVbo.IsNull())
{
myBndVertsVbo->Release (theCtx.get());
#include <OpenGl_VertexBufferCompat.hxx>
#include <Font_FTFont.hxx>
+#include <Font_TextFormatter.hxx>
namespace
{
// function : createGlyphs
// purpose :
// =======================================================================
-void OpenGl_TextBuilder::createGlyphs (const Font_TextFormatter& theFormatter,
+void OpenGl_TextBuilder::createGlyphs (const Handle(Font_TextFormatter)& theFormatter,
const Handle(OpenGl_Context)& theCtx,
OpenGl_Font& theFont,
NCollection_Vector<GLuint>& theTextures,
theTCrdsPerTexture.Clear();
OpenGl_Font::Tile aTile = {Font_Rect(), Font_Rect(), 0u};
- OpenGl_Vec2 aPen (0.0f, 0.0f);
- Standard_Integer aRectsNb = 0;
- Standard_Integer aSymbolsCounter = 0;
-
- for (NCollection_Utf8Iter anIter = theFormatter.String().Iterator(); *anIter != 0;)
+ for (Font_TextFormatter::Iterator aFormatterIt (*theFormatter, Font_TextFormatter::IterationFilter_ExcludeInvisible);
+ aFormatterIt .More(); aFormatterIt .Next())
{
- const Standard_Utf32Char aCharThis = *anIter;
- const Standard_Utf32Char aCharNext = *++anIter;
-
- if (aCharThis == '\x0D' // CR (carriage return)
- || aCharThis == '\a' // BEL (alarm)
- || aCharThis == '\f' // FF (form feed) NP (new page)
- || aCharThis == '\b' // BS (backspace)
- || aCharThis == '\v') // VT (vertical tab)
- {
- continue; // skip unsupported carriage control codes
- }
- else if (aCharThis == '\x0A') // LF (line feed, new line)
- {
- aSymbolsCounter = 0;
- continue; // will be processed on second pass
- }
- else if (aCharThis == ' ')
- {
- ++aSymbolsCounter;
- aPen.x() += theFont.FTFont()->AdvanceX (' ', aCharNext);
- continue;
- }
- else if (aCharThis == '\t')
- {
- const Standard_Integer aSpacesNum = (theFormatter.TabSize() - (aSymbolsCounter - 1) % theFormatter.TabSize());
- aPen.x() += theFont.FTFont()->AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum);
- aSymbolsCounter += aSpacesNum;
- continue;
- }
+ theFont.RenderGlyph (theCtx, aFormatterIt.Symbol(), aTile);
- ++aSymbolsCounter;
-
- theFont.RenderGlyph (theCtx, aCharThis, aTile);
-
- const OpenGl_Vec2& aTopLeft = theFormatter.TopLeft (aRectsNb);
- aTile.px.Right += aTopLeft.x();
- aTile.px.Left += aTopLeft.x();
- aTile.px.Bottom += aTopLeft.y();
- aTile.px.Top += aTopLeft.y();
+ const OpenGl_Vec2& aBottomLeft = theFormatter->BottomLeft (aFormatterIt.SymbolPosition());
+ aTile.px.Right += aBottomLeft.x();
+ aTile.px.Left += aBottomLeft.x();
+ aTile.px.Bottom += aBottomLeft.y();
+ aTile.px.Top += aBottomLeft.y();
const Font_Rect& aRectUV = aTile.uv;
const GLuint aTexture = aTile.texture;
aTCrds.Append (aRectUV.BottomRight (aVec));
aTCrds.Append (aRectUV.TopRight (aVec));
aTCrds.Append (aRectUV.BottomLeft (aVec));
-
- ++aRectsNb;
}
}
// function : CreateTextures
// purpose :
// =======================================================================
-void OpenGl_TextBuilder::Perform (const Font_TextFormatter& theFormatter,
+void OpenGl_TextBuilder::Perform (const Handle(Font_TextFormatter)& theFormatter,
const Handle(OpenGl_Context)& theCtx,
OpenGl_Font& theFont,
NCollection_Vector<GLuint>& theTextures,
#ifndef OpenGl_TextBuilder_Header
#define OpenGl_TextBuilder_Header
-#include <Font_TextFormatter.hxx>
-
#include <OpenGl_Context.hxx>
#include <OpenGl_Font.hxx>
#include <OpenGl_VertexBuffer.hxx>
#include <NCollection_Vector.hxx>
#include <NCollection_Handle.hxx>
+class Font_TextFormatter;
//! This class generates primitive array required for rendering textured text using OpenGl_Font instance.
class OpenGl_TextBuilder
Standard_EXPORT OpenGl_TextBuilder();
//! Creates texture quads for the given text.
- Standard_EXPORT void Perform (const Font_TextFormatter& theFormatter,
+ Standard_EXPORT void Perform (const Handle(Font_TextFormatter)& theFormatter,
const Handle(OpenGl_Context)& theContext,
OpenGl_Font& theFont,
NCollection_Vector<GLuint>& theTextures,
protected: //! @name class auxillary methods
- Standard_EXPORT void createGlyphs (const Font_TextFormatter& theFormatter,
+ Standard_EXPORT void createGlyphs (const Handle(Font_TextFormatter)& theFormatter,
const Handle(OpenGl_Context)& theCtx,
OpenGl_Font& theFont,
NCollection_Vector<GLuint>& theTextures,
#include <StdPrs_BRepTextBuilder.hxx>
+#include <Font_TextFormatter.hxx>
+
// =======================================================================
// Function : Perfrom
// Purpose :
// =======================================================================
TopoDS_Shape StdPrs_BRepTextBuilder::Perform (StdPrs_BRepFont& theFont,
- const Font_TextFormatter& theFormatter,
+ const Handle(Font_TextFormatter)& theFormatter,
const gp_Ax3& thePenLoc)
{
gp_Trsf aTrsf;
myBuilder.MakeCompound (aResult);
- Standard_Integer aSymbolCounter = 0;
- Standard_Real aScaleUnits = theFont.Scale();
- for (NCollection_Utf8Iter anIter = theFormatter.String().Iterator(); *anIter != 0; ++anIter)
+ Standard_Real aScaleUnits = theFont.Scale();
+ for (Font_TextFormatter::Iterator aFormatterIt (*theFormatter, Font_TextFormatter::IterationFilter_ExcludeInvisible);
+ aFormatterIt .More(); aFormatterIt .Next())
{
- const Standard_Utf32Char aCharCurr = *anIter;
- if (aCharCurr == '\x0D' // CR (carriage return)
- || aCharCurr == '\a' // BEL (alarm)
- || aCharCurr == '\f' // FF (form feed) NP (new page)
- || aCharCurr == '\b' // BS (backspace)
- || aCharCurr == '\v' // VT (vertical tab)
- || aCharCurr == ' '
- || aCharCurr == '\t'
- || aCharCurr == '\n')
- {
- continue; // skip unsupported carriage control codes
- }
+ const NCollection_Vec2<Standard_ShortReal>& aCorner = theFormatter->BottomLeft (aFormatterIt.SymbolPosition());
- const NCollection_Vec2<Standard_ShortReal>& aCorner = theFormatter.TopLeft (aSymbolCounter);
aPen.SetCoord (aCorner.x() * aScaleUnits, aCorner.y() * aScaleUnits, 0.0);
- aGlyphShape = theFont.RenderGlyph (aCharCurr);
+ aGlyphShape = theFont.RenderGlyph (aFormatterIt.Symbol());
if (!aGlyphShape.IsNull())
{
aTrsf.SetTranslation (gp_Vec (aPen));
aGlyphShape.Move (aTrsf);
myBuilder.Add (aResult, aGlyphShape);
}
-
- ++aSymbolCounter;
}
aTrsf.SetTransformation (thePenLoc, gp_Ax3 (gp::XOY()));
const Graphic3d_HorizontalTextAlignment theHAlign,
const Graphic3d_VerticalTextAlignment theVAlign)
{
- Font_TextFormatter aFormatter;
+ Handle(Font_TextFormatter) aFormatter = new Font_TextFormatter();
- aFormatter.Reset();
- aFormatter.SetupAlignment (theHAlign, theVAlign);
+ aFormatter->Reset();
+ aFormatter->SetupAlignment (theHAlign, theVAlign);
- aFormatter.Append (theString, *(reinterpret_cast<Font_FTFont*> (&theFont)));
- aFormatter.Format();
+ aFormatter->Append (theString, *(reinterpret_cast<Font_FTFont*> (&theFont)));
+ aFormatter->Format();
return Perform (theFont, aFormatter, thePenLoc);
}
//! @param thePenLoc start position and orientation on the baseline
//! @param theFormatter formatter which defines alignment for the text
//! @return result shape with pen transformation applied as shape location
- Standard_EXPORT TopoDS_Shape Perform (StdPrs_BRepFont& theFont,
- const Font_TextFormatter& theFormatter,
- const gp_Ax3& thePenLoc = gp_Ax3());
+ Standard_EXPORT TopoDS_Shape Perform (StdPrs_BRepFont& theFont,
+ const Handle(Font_TextFormatter)& theFormatter,
+ const gp_Ax3& thePenLoc = gp_Ax3());
//! Render text as BRep shape.
//! @param theString text in UTF-8 encoding
//! @param thePenLoc start position and orientation on the baseline