From ae2ec4761ad3e4daa3f69ec798c7ba8a2764b026 Mon Sep 17 00:00:00 2001 From: isk Date: Tue, 23 Jun 2015 22:43:45 +0300 Subject: [PATCH] 0026361: Visualization - move OpenGl_TextFormatter to Font_TextFormatter for usage without OpenGL. Split OpenGl_TextFormatter on Font_TextFormatter and OpenGl_TextBuilder. Font_TextFormatter can format a text independetly of OpenGl now. OpenGl_TextBuilder generates primitive array required for rendering text using OpenGl_Font instance. --- src/Font/FILES | 2 + src/Font/Font_FTFont.cxx | 24 ++ src/Font/Font_FTFont.hxx | 17 +- .../Font_TextFormatter.cxx} | 242 +++++------------- .../Font_TextFormatter.hxx} | 66 +++-- src/OpenGl/FILES | 4 +- src/OpenGl/OpenGl_Font.cxx | 30 +++ src/OpenGl/OpenGl_Font.hxx | 5 + src/OpenGl/OpenGl_Text.cxx | 22 +- src/OpenGl/OpenGl_Text.hxx | 2 +- src/OpenGl/OpenGl_TextBuilder.cxx | 217 ++++++++++++++++ src/OpenGl/OpenGl_TextBuilder.hxx | 62 +++++ 12 files changed, 467 insertions(+), 226 deletions(-) rename src/{OpenGl/OpenGl_TextFormatter.cxx => Font/Font_TextFormatter.cxx} (51%) mode change 100755 => 100644 rename src/{OpenGl/OpenGl_TextFormatter.hxx => Font/Font_TextFormatter.hxx} (68%) mode change 100755 => 100644 create mode 100644 src/OpenGl/OpenGl_TextBuilder.cxx create mode 100644 src/OpenGl/OpenGl_TextBuilder.hxx diff --git a/src/Font/FILES b/src/Font/FILES index ad2c3280a2..2aa2c0b149 100644 --- a/src/Font/FILES +++ b/src/Font/FILES @@ -7,3 +7,5 @@ Font_FTLibrary.hxx Font_FTLibrary.cxx Font_NListOfSystemFont.hxx Font_NameOfFont.hxx +Font_TextFormatter.hxx +Font_TextFormatter.cxx \ No newline at end of file diff --git a/src/Font/Font_FTFont.cxx b/src/Font/Font_FTFont.cxx index 684a831185..b0f422ccbe 100755 --- a/src/Font/Font_FTFont.cxx +++ b/src/Font/Font_FTFont.cxx @@ -15,6 +15,8 @@ #include #include +#include + #include #include @@ -257,3 +259,25 @@ float Font_FTFont::AdvanceY (const Standard_Utf32Char theUCharNext) } return fromFTPoints (myKernAdvance.y + myFTFace->glyph->advance.y); } + +// ======================================================================= +// function : BoundingBox +// purpose : +// ======================================================================= +Font_FTFont::Rect Font_FTFont::BoundingBox (const NCollection_String& theString, + const Graphic3d_HorizontalTextAlignment theAlignX, + const Graphic3d_VerticalTextAlignment theAlignY) +{ + Font_TextFormatter aFormatter; + aFormatter.SetupAlignment (theAlignX, theAlignY); + aFormatter.Reset(); + + aFormatter.Append (theString, *this); + aFormatter.Format(); + + Rect aBndBox; + + aFormatter.BndBox (aBndBox); + + return aBndBox; +} diff --git a/src/Font/Font_FTFont.hxx b/src/Font/Font_FTFont.hxx index f4ba85ca8a..eb4c03ff36 100755 --- a/src/Font/Font_FTFont.hxx +++ b/src/Font/Font_FTFont.hxx @@ -16,11 +16,13 @@ #ifndef _Font_FTFont_H__ #define _Font_FTFont_H__ -#include -#include +#include #include +#include +#include #include -#include +#include +#include //! Wrapper over FreeType font. //! Notice that this class uses internal buffers for loaded glyphs @@ -178,6 +180,15 @@ public: theRect.Bottom = float(myFTFace->glyph->bitmap_top - (int )aBitmap.rows); } + //! Computes bounding box of the given text using plain-text formatter (Font_TextFormatter). + //! Note that bounding box takes into account text alignments. It can have negative coordinates. + //! The width and height easy to get by the following formulas: + //! Width = Rect.Right - Rect.Left; + //! Height = Rect.Top - Rect.Bottom; + Standard_EXPORT Rect BoundingBox (const NCollection_String& theString, + const Graphic3d_HorizontalTextAlignment theAlignX, + const Graphic3d_VerticalTextAlignment theAlignY); + protected: //! Convert value to 26.6 fixed-point format for FT library API. diff --git a/src/OpenGl/OpenGl_TextFormatter.cxx b/src/Font/Font_TextFormatter.cxx old mode 100755 new mode 100644 similarity index 51% rename from src/OpenGl/OpenGl_TextFormatter.cxx rename to src/Font/Font_TextFormatter.cxx index 85d5153d3b..b4d6776c0b --- a/src/OpenGl/OpenGl_TextFormatter.cxx +++ b/src/Font/Font_TextFormatter.cxx @@ -13,18 +13,14 @@ // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. -#include - -#include - -#include +#include namespace { //! Auxiliary function to translate rectangle by the vector. - inline void move (Font_FTFont::Rect& theRect, - const OpenGl_Vec2& theVec) + inline void move (Font_FTFont::Rect& theRect, + const NCollection_Vec2& theVec) { theRect.Left += theVec.x(); theRect.Right += theVec.x(); @@ -33,41 +29,27 @@ namespace } //! Auxiliary function to translate rectangles by the vector. - inline void move (NCollection_Vector& theRects, - const OpenGl_Vec2& theMoveVec, - Standard_Integer theCharLower, - const Standard_Integer theCharUpper) + inline void move (NCollection_Vector& theRects, + const NCollection_Vec2& theMoveVec, + Standard_Integer theCharLower, + const Standard_Integer theCharUpper) { for(; theCharLower <= theCharUpper; ++theCharLower) { - Font_FTFont::Rect& aRect = theRects.ChangeValue (theCharLower).px; + Font_FTFont::Rect& aRect = theRects.ChangeValue (theCharLower); move (aRect, theMoveVec); } } - //! Auxiliary function to translate rectangles in horizontal direction. - /*inline void moveX (NCollection_Vector& theRects, - const Standard_ShortReal theMoveVec, - Standard_Integer theCharLower, - const Standard_Integer theCharUpper) - { - for (; theCharLower <= theCharUpper; ++theCharLower) - { - Font_FTFont::Rect& aRect = theRects.ChangeValue (theCharLower).px; - aRect.Left += theMoveVec; - aRect.Right += theMoveVec; - } - }*/ - //! Auxiliary function to translate rectangles in vertical direction. - inline void moveY (NCollection_Vector& theRects, + inline void moveY (NCollection_Vector& theRects, const Standard_ShortReal theMoveVec, Standard_Integer theCharLower, const Standard_Integer theCharUpper) { for(; theCharLower <= theCharUpper; ++theCharLower) { - Font_FTFont::Rect& aRect = theRects.ChangeValue (theCharLower).px; + Font_FTFont::Rect& aRect = theRects.ChangeValue (theCharLower); aRect.Top += theMoveVec; aRect.Bottom += theMoveVec; } @@ -76,23 +58,24 @@ namespace //! Apply floor to vector components. //! @param theVec - vector to change (by reference!) //! @return modified vector - inline OpenGl_Vec2& floor (OpenGl_Vec2& theVec) + inline NCollection_Vec2& floor (NCollection_Vec2& theVec) { theVec.x() = std::floor (theVec.x()); theVec.y() = std::floor (theVec.y()); return theVec; } -}; +} + -IMPLEMENT_STANDARD_HANDLE (OpenGl_TextFormatter, Standard_Transient) -IMPLEMENT_STANDARD_RTTIEXT(OpenGl_TextFormatter, Standard_Transient) +IMPLEMENT_STANDARD_HANDLE (Font_TextFormatter, Standard_Transient) +IMPLEMENT_STANDARD_RTTIEXT(Font_TextFormatter, Standard_Transient) // ======================================================================= -// function : OpenGl_TextFormatter +// function : Font_TextFormatter // purpose : // ======================================================================= -OpenGl_TextFormatter::OpenGl_TextFormatter() +Font_TextFormatter::Font_TextFormatter() : myAlignX (Graphic3d_HTA_LEFT), myAlignY (Graphic3d_VTA_TOP), myTabSize (8), @@ -121,8 +104,8 @@ OpenGl_TextFormatter::OpenGl_TextFormatter() // function : SetupAlignment // purpose : // ======================================================================= -void OpenGl_TextFormatter::SetupAlignment (const Graphic3d_HorizontalTextAlignment theAlignX, - const Graphic3d_VerticalTextAlignment theAlignY) +void Font_TextFormatter::SetupAlignment (const Graphic3d_HorizontalTextAlignment theAlignX, + const Graphic3d_VerticalTextAlignment theAlignY) { myAlignX = theAlignX; myAlignY = theAlignY; @@ -132,7 +115,7 @@ void OpenGl_TextFormatter::SetupAlignment (const Graphic3d_HorizontalTextAlignme // function : Reset // purpose : // ======================================================================= -void OpenGl_TextFormatter::Reset() +void Font_TextFormatter::Reset() { myIsFormatted = false; myString.Clear(); @@ -143,142 +126,12 @@ void OpenGl_TextFormatter::Reset() myNewLines.Clear(); } -// ======================================================================= -// function : Result -// purpose : -// ======================================================================= -void OpenGl_TextFormatter::Result (NCollection_Vector& theTextures, - NCollection_Vector< NCollection_Handle > >& theVertsPerTexture, - NCollection_Vector< NCollection_Handle > >& theTCrdsPerTexture) const -{ - OpenGl_Vec2 aVec (0.0f, 0.0f); - theTextures.Clear(); - theVertsPerTexture.Clear(); - theTCrdsPerTexture.Clear(); - for (Standard_Integer aRectIter = 0; aRectIter < myRectsNb; ++aRectIter) - { - const Font_FTFont::Rect& aRect = myRects.Value (aRectIter).px; - const Font_FTFont::Rect& aRectUV = myRects.Value (aRectIter).uv; - const GLuint aTexture = myRects.Value (aRectIter).texture; - - Standard_Integer aListId = 0; - for (aListId = 0; aListId < theTextures.Length(); ++aListId) - { - if (theTextures.Value (aListId) == aTexture) - { - break; - } - } - if (aListId >= theTextures.Length()) - { - theTextures.Append (aTexture); - theVertsPerTexture.Append (new NCollection_Vector()); - theTCrdsPerTexture.Append (new NCollection_Vector()); - } - - NCollection_Vector& aVerts = *theVertsPerTexture.ChangeValue (aListId); - NCollection_Vector& aTCrds = *theTCrdsPerTexture.ChangeValue (aListId); - - // apply floor on position to avoid blurring issues - // due to cross-pixel coordinates - aVerts.Append (floor(aRect.TopRight (aVec))); - aVerts.Append (floor(aRect.TopLeft (aVec))); - aVerts.Append (floor(aRect.BottomLeft (aVec))); - aTCrds.Append (aRectUV.TopRight (aVec)); - aTCrds.Append (aRectUV.TopLeft (aVec)); - aTCrds.Append (aRectUV.BottomLeft (aVec)); - - aVerts.Append (floor(aRect.BottomRight (aVec))); - aVerts.Append (floor(aRect.TopRight (aVec))); - aVerts.Append (floor(aRect.BottomLeft (aVec))); - aTCrds.Append (aRectUV.BottomRight (aVec)); - aTCrds.Append (aRectUV.TopRight (aVec)); - aTCrds.Append (aRectUV.BottomLeft (aVec)); - } -} - -// ======================================================================= -// function : Result -// purpose : -// ======================================================================= -void OpenGl_TextFormatter::Result (const Handle(OpenGl_Context)& theCtx, - NCollection_Vector& theTextures, - NCollection_Vector& theVertsPerTexture, - NCollection_Vector& theTCrdsPerTexture) const -{ - NCollection_Vector< NCollection_Handle > > aVertsPerTexture; - NCollection_Vector< NCollection_Handle > > aTCrdsPerTexture; - Result (theTextures, aVertsPerTexture, aTCrdsPerTexture); - - if (theVertsPerTexture.Length() != theTextures.Length()) - { - for (Standard_Integer aTextureIter = 0; aTextureIter < theVertsPerTexture.Length(); ++aTextureIter) - { - theVertsPerTexture.Value (aTextureIter)->Release (theCtx.operator->()); - theTCrdsPerTexture.Value (aTextureIter)->Release (theCtx.operator->()); - } - theVertsPerTexture.Clear(); - theTCrdsPerTexture.Clear(); - - const bool isNormalMode = theCtx->ToUseVbo(); - Handle(OpenGl_VertexBuffer) aVertsVbo, aTcrdsVbo; - while (theVertsPerTexture.Length() < theTextures.Length()) - { - if (isNormalMode) - { - aVertsVbo = new OpenGl_VertexBuffer(); - aTcrdsVbo = new OpenGl_VertexBuffer(); - } - else - { - aVertsVbo = new OpenGl_VertexBufferCompat(); - aTcrdsVbo = new OpenGl_VertexBufferCompat(); - } - theVertsPerTexture.Append (aVertsVbo); - theTCrdsPerTexture.Append (aTcrdsVbo); - aVertsVbo->Create (theCtx); - aTcrdsVbo->Create (theCtx); - } - } - - for (Standard_Integer aTextureIter = 0; aTextureIter < theTextures.Length(); ++aTextureIter) - { - const NCollection_Vector& aVerts = *aVertsPerTexture.Value (aTextureIter); - Handle(OpenGl_VertexBuffer)& aVertsVbo = theVertsPerTexture.ChangeValue (aTextureIter); - if (!aVertsVbo->Init (theCtx, 2, aVerts.Length(), (GLfloat* )NULL) - || !myVboEditor.Init (theCtx, aVertsVbo)) - { - continue; - } - for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter, myVboEditor.Next()) - { - myVboEditor.Value() = aVerts.Value (aVertIter); - } - myVboEditor.Flush(); - - const NCollection_Vector& aTCrds = *aTCrdsPerTexture.Value (aTextureIter); - Handle(OpenGl_VertexBuffer)& aTCrdsVbo = theTCrdsPerTexture.ChangeValue (aTextureIter); - if (!aTCrdsVbo->Init (theCtx, 2, aVerts.Length(), (GLfloat* )NULL) - || !myVboEditor.Init (theCtx, aTCrdsVbo)) - { - continue; - } - for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter, myVboEditor.Next()) - { - myVboEditor.Value() = aTCrds.Value (aVertIter); - } - myVboEditor.Flush(); - } - myVboEditor.Init (NULL, NULL); -} - // ======================================================================= // function : Append // purpose : // ======================================================================= -void OpenGl_TextFormatter::Append (const Handle(OpenGl_Context)& theCtx, - const NCollection_String& theString, - OpenGl_Font& theFont) +void Font_TextFormatter::Append (const NCollection_String& theString, + Font_FTFont& theFont) { if (theString.IsEmpty()) { @@ -292,8 +145,7 @@ void OpenGl_TextFormatter::Append (const Handle(OpenGl_Context)& theCtx, int aSymbolsCounter = 0; // special counter to process tabulation symbols // first pass - render all symbols using associated font on single ZERO baseline - OpenGl_Font::Tile aTile; - memset (&aTile, 0, sizeof(aTile)); + Font_FTFont::Rect aRect = {}; for (NCollection_Utf8Iter anIter = theString.Iterator(); *anIter != 0;) { const Standard_Utf32Char aCharThis = *anIter; @@ -328,10 +180,18 @@ void OpenGl_TextFormatter::Append (const Handle(OpenGl_Context)& theCtx, } ++aSymbolsCounter; - theFont.RenderGlyph (theCtx, - aCharThis, aCharNext, - aTile, myPen); - myRects.Append (aTile); + + theFont.RenderGlyph (aCharThis); + theFont.GlyphRect (aRect); + + aRect.Top += myPen.y(); + aRect.Bottom += myPen.y(); + aRect.Left += myPen.x(); + aRect.Right += myPen.x(); + + myPen.x() += theFont.AdvanceX (aCharThis, aCharNext); + + myRects.Append (aRect); ++myRectsNb; } @@ -341,7 +201,7 @@ void OpenGl_TextFormatter::Append (const Handle(OpenGl_Context)& theCtx, // function : newLine // purpose : // ======================================================================= -void OpenGl_TextFormatter::newLine (const Standard_Integer theLastRect) +void Font_TextFormatter::newLine (const Standard_Integer theLastRect) { if (myRectLineStart >= myRectsNb) { @@ -386,7 +246,7 @@ void OpenGl_TextFormatter::newLine (const Standard_Integer theLastRect) myRectLineStart = myRectWordStart = theLastRect + 1; if (myRectLineStart < myRectsNb) { - myLineLeft = myRects.Value (myRectLineStart).px.Left; + myLineLeft = myRects.Value (myRectLineStart).Left; } } @@ -394,7 +254,7 @@ void OpenGl_TextFormatter::newLine (const Standard_Integer theLastRect) // function : Format // purpose : // ======================================================================= -void OpenGl_TextFormatter::Format() +void Font_TextFormatter::Format() { if (myRectsNb == 0 || myIsFormatted) { @@ -413,6 +273,7 @@ void OpenGl_TextFormatter::Format() myPenCurrLine = -myAscender; Standard_Integer aRectIter = 0; myNewLineNb = 0; + Standard_ShortReal aMaxLineWidth = -1.0f; for (NCollection_Utf8Iter anIter = myString.Iterator(); *anIter != 0; ++anIter) { const Standard_Utf32Char aCharThis = *anIter; @@ -426,6 +287,16 @@ void OpenGl_TextFormatter::Format() } 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); ++myNewLineNb; @@ -438,12 +309,21 @@ void OpenGl_TextFormatter::Format() continue; } - Standard_ShortReal aWidth = myRects.Value (aRectIter).px.Right - myLineLeft; - myBndWidth = Max (myBndWidth, aWidth); - ++aRectIter; } + // If only one line + if (aMaxLineWidth < 0.0f) + { + aMaxLineWidth = myPen.x(); + } + else // Consider last line + { + aMaxLineWidth = Max (aMaxLineWidth, myPen.x() - myNewLines.Value (myNewLineNb - 1)); + } + + myBndWidth = aMaxLineWidth; + // move last line newLine (myRectsNb - 1); diff --git a/src/OpenGl/OpenGl_TextFormatter.hxx b/src/Font/Font_TextFormatter.hxx old mode 100755 new mode 100644 similarity index 68% rename from src/OpenGl/OpenGl_TextFormatter.hxx rename to src/Font/Font_TextFormatter.hxx index adca108a8d..174db88968 --- a/src/OpenGl/OpenGl_TextFormatter.hxx +++ b/src/Font/Font_TextFormatter.hxx @@ -13,25 +13,19 @@ // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. -#ifndef _OpenGl_TextFormatter_H__ -#define _OpenGl_TextFormatter_H__ +#ifndef Font_TextFormatter_Header +#define Font_TextFormatter_Header -#include -#include - -#include -#include - -#include +#include +#include //! This class intended to prepare formatted text. -class OpenGl_TextFormatter : public Standard_Transient +class Font_TextFormatter : public Standard_Transient { - public: //! Default constructor. - Standard_EXPORT OpenGl_TextFormatter(); + Standard_EXPORT Font_TextFormatter(); //! Setup alignment style. Standard_EXPORT void SetupAlignment (const Graphic3d_HorizontalTextAlignment theAlignX, @@ -41,24 +35,30 @@ public: Standard_EXPORT void Reset(); //! Render specified text to inner buffer. - Standard_EXPORT void Append (const Handle(OpenGl_Context)& theCtx, - const NCollection_String& theString, - OpenGl_Font& theFont); + Standard_EXPORT void Append (const NCollection_String& theString, + Font_FTFont& theFont); //! Perform formatting on the buffered text. //! Should not be called more than once after initialization! Standard_EXPORT void Format(); - //! Retrieve formatting results. - Standard_EXPORT void Result (NCollection_Vector& theTextures, - NCollection_Vector< NCollection_Handle > >& theVertsPerTexture, - NCollection_Vector< NCollection_Handle > >& theTCrdsPerTexture) const; + //! Returns specific glyph rectangle. + inline const Font_FTFont::Rect& Rect (const Standard_Integer theIndex) const + { + return myRects.Value (theIndex); + } + + //! Returns current rendering string. + inline const NCollection_String& String() const + { + return myString; + } - //! Retrieve formatting results. - Standard_EXPORT void Result (const Handle(OpenGl_Context)& theCtx, - NCollection_Vector& theTextures, - NCollection_Vector& theVertsPerTexture, - NCollection_Vector& theTCrdsPerTexture) const; + //! Returns tab size. + inline Standard_Integer TabSize() const + { + return myTabSize; + } //! @return width of formatted text. inline Standard_ShortReal ResultWidth() const @@ -106,8 +106,9 @@ protected: //! @name configuration protected: //! @name input data NCollection_String myString; //!< currently rendered text - OpenGl_Vec2 myPen; //!< current pen position - NCollection_Vector + NCollection_Vec2 + myPen; //!< current pen position + NCollection_Vector myRects; //!< glyphs rectangles Standard_Integer myRectsNb; //!< rectangles number NCollection_Vector @@ -116,10 +117,6 @@ protected: //! @name input data Standard_ShortReal myAscender; //!< bool myIsFormatted; //!< formatting state -protected: - - mutable OpenGl_VertexBufferEditor myVboEditor; - protected: //! @name temporary variables for formatting routines Standard_Integer myLinesNb; //!< overall (new)lines number (including splitting by width limit) @@ -132,14 +129,15 @@ protected: //! @name temporary variables for formatting routines Standard_ShortReal myLineTail; Standard_ShortReal myBndTop; Standard_ShortReal myBndWidth; - OpenGl_Vec2 myMoveVec; //!< local variable + NCollection_Vec2 + myMoveVec; //!< local variable public: - DEFINE_STANDARD_RTTI(OpenGl_TextFormatter) // Type definition + DEFINE_STANDARD_RTTI(Font_TextFormatter) // Type definition }; -DEFINE_STANDARD_HANDLE(OpenGl_TextFormatter, Standard_Transient) +DEFINE_STANDARD_HANDLE(Font_TextFormatter, Standard_Transient) -#endif // _OpenGl_TextFormatter_H__ +#endif // Font_TextFormatter_Header diff --git a/src/OpenGl/FILES b/src/OpenGl/FILES index 37d3e63a1f..de9014dd12 100755 --- a/src/OpenGl/FILES +++ b/src/OpenGl/FILES @@ -26,8 +26,6 @@ OpenGl_Element.hxx OpenGl_Element.cxx OpenGl_Text.hxx OpenGl_Text.cxx -OpenGl_TextFormatter.hxx -OpenGl_TextFormatter.cxx OpenGl_PointSprite.hxx OpenGl_PointSprite.cxx Handle_OpenGl_PointSprite.hxx @@ -169,3 +167,5 @@ OpenGl_Sphere.hxx OpenGl_Sphere.cxx OpenGl_BackgroundArray.hxx OpenGl_BackgroundArray.cxx +OpenGl_TextBuilder.hxx +OpenGl_TextBuilder.cxx diff --git a/src/OpenGl/OpenGl_Font.cxx b/src/OpenGl/OpenGl_Font.cxx index 1a17c604ab..54e9db700c 100755 --- a/src/OpenGl/OpenGl_Font.cxx +++ b/src/OpenGl/OpenGl_Font.cxx @@ -234,3 +234,33 @@ void OpenGl_Font::RenderGlyph (const Handle(OpenGl_Context)& theCtx, thePen.x() += myFont->AdvanceX (theUChar, theUCharNext); } + +// ======================================================================= +// function : RenderGlyph +// purpose : +// ======================================================================= +bool OpenGl_Font::RenderGlyph (const Handle(OpenGl_Context)& theCtx, + const Standard_Utf32Char theUChar, + Tile& theGlyph) +{ + Standard_Integer aTileId = 0; + if (!myGlyphMap.Find (theUChar,aTileId)) + { + if (renderGlyph (theCtx, theUChar)) + { + aTileId = myLastTileId; + } + else + { + return false; + } + + myGlyphMap.Bind (theUChar, aTileId); + } + + const OpenGl_Font::Tile& aTile = myTiles.Value (aTileId); + theGlyph.uv = aTile.uv; + theGlyph.texture = aTile.texture; + + return true; +} diff --git a/src/OpenGl/OpenGl_Font.hxx b/src/OpenGl/OpenGl_Font.hxx index fd95912d1d..4ba8d3a588 100755 --- a/src/OpenGl/OpenGl_Font.hxx +++ b/src/OpenGl/OpenGl_Font.hxx @@ -128,6 +128,11 @@ public: Tile& theGlyph, OpenGl_Vec2& thePen); + //! Render glyph to texture if not already. + Standard_EXPORT bool RenderGlyph (const Handle(OpenGl_Context)& theCtx, + const Standard_Utf32Char theUChar, + Tile& theGlyph); + protected: //! Render new glyph to the texture. diff --git a/src/OpenGl/OpenGl_Text.cxx b/src/OpenGl/OpenGl_Text.cxx index a67ea82ed6..d98a62da76 100644 --- a/src/OpenGl/OpenGl_Text.cxx +++ b/src/OpenGl/OpenGl_Text.cxx @@ -146,6 +146,7 @@ OpenGl_Text::OpenGl_Text() myWinZ (0.0f), myScaleHeight (1.0f), myPoint (0.0f, 0.0f, 0.0f), + myIs2d (false) { myParams.Height = 10; @@ -174,6 +175,7 @@ OpenGl_Text::OpenGl_Text (const Standard_Utf8Char* theText, } // ======================================================================= + // function : SetPosition // purpose : // ======================================================================= @@ -464,8 +466,7 @@ void OpenGl_Text::setupMatrix (const Handle(OpenGl_PrinterContext)& thePrintCtx, anObjZ); OpenGl_Utils::Translate (aModViewMat, anObjX, anObjY, anObjZ); - OpenGl_Utils::Rotate (aModViewMat, theTextAspect.Angle(), 0.0, 0.0, 1.0); - + OpenGl_Utils::Rotate (aModViewMat, theTextAspect.Angle(), 0.0, 0.0, 1.0); if (!theTextAspect.IsZoomable()) { #ifdef _WIN32 @@ -580,6 +581,7 @@ Handle(OpenGl_Font) OpenGl_Text::FindFont (const Handle(OpenGl_Context)& theCtx, if (!aRequestedFont.IsNull()) { aFontFt = new Font_FTFont (NULL); + if (aFontFt->Init (aRequestedFont->FontPath()->ToCString(), theHeight)) { aFont = new OpenGl_Font (aFontFt, theKey); @@ -655,13 +657,23 @@ void OpenGl_Text::render (const Handle(OpenGl_PrinterContext)& thePrintCtx, if (myTextures.IsEmpty()) { - OpenGl_TextFormatter aFormatter; + + Font_TextFormatter aFormatter; aFormatter.SetupAlignment (myParams.HAlign, myParams.VAlign); aFormatter.Reset(); - aFormatter.Append (theCtx, myString, *myFont.operator->()); + + + aFormatter.Append (myString, *myFont->FTFont()); aFormatter.Format(); - aFormatter.Result (theCtx, myTextures, myVertsVbo, myTCrdsVbo); + OpenGl_TextBuilder aBuilder; + aBuilder.Perform (aFormatter, + theCtx, + *myFont.operator->(), + myTextures, + myVertsVbo, + myTCrdsVbo); + aFormatter.BndBox (myBndBox); } diff --git a/src/OpenGl/OpenGl_Text.hxx b/src/OpenGl/OpenGl_Text.hxx index 68d8514a51..71200ee30a 100755 --- a/src/OpenGl/OpenGl_Text.hxx +++ b/src/OpenGl/OpenGl_Text.hxx @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include diff --git a/src/OpenGl/OpenGl_TextBuilder.cxx b/src/OpenGl/OpenGl_TextBuilder.cxx new file mode 100644 index 0000000000..216de4f255 --- /dev/null +++ b/src/OpenGl/OpenGl_TextBuilder.cxx @@ -0,0 +1,217 @@ +// Created on: 2015-06-18 +// Created by: Ilya SEVRIKOV +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include +#include + +namespace +{ + //! Apply floor to vector components. + //! @param theVec - vector to change (by reference!) + //! @return modified vector + inline OpenGl_Vec2& floor (OpenGl_Vec2& theVec) + { + theVec.x() = std::floor (theVec.x()); + theVec.y() = std::floor (theVec.y()); + return theVec; + } +}; + +// ======================================================================= +// function : OpenGl_TextBuilder +// purpose : +// ======================================================================= +OpenGl_TextBuilder::OpenGl_TextBuilder() +{ + // +} + +// ======================================================================= +// function : createGlyphs +// purpose : +// ======================================================================= +void OpenGl_TextBuilder::createGlyphs (const Font_TextFormatter& theFormatter, + const Handle(OpenGl_Context)& theCtx, + OpenGl_Font& theFont, + NCollection_Vector& theTextures, + NCollection_Vector > >& theVertsPerTexture, + NCollection_Vector > >& theTCrdsPerTexture) +{ + OpenGl_Vec2 aVec (0.0f, 0.0f); + + theTextures.Clear(); + theVertsPerTexture.Clear(); + theTCrdsPerTexture.Clear(); + + OpenGl_Font::Tile aTile = {}; + OpenGl_Vec2 aPen (0.0f, 0.0f); + Standard_Integer aRectsNb = 0; + Standard_Integer aSymbolsCounter = 0; + + for (NCollection_Utf8Iter anIter = theFormatter.String().Iterator(); *anIter != 0;) + { + 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.AdvanceX (' ', aCharNext); + continue; + } + else if (aCharThis == '\t') + { + const Standard_Integer aSpacesNum = (theFormatter.TabSize() - (aSymbolsCounter - 1) % theFormatter.TabSize()); + aPen.x() += theFont.AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum); + aSymbolsCounter += aSpacesNum; + continue; + } + + ++aSymbolsCounter; + + theFont.RenderGlyph (theCtx, aCharThis, aTile); + + const Font_FTFont::Rect& aRect = theFormatter.Rect (aRectsNb); + const Font_FTFont::Rect& aRectUV = aTile.uv; + const GLuint aTexture = aTile.texture; + + Standard_Integer aListId = 0; + for (aListId = 0; aListId < theTextures.Length(); ++aListId) + { + if (theTextures.Value (aListId) == aTexture) + { + break; + } + } + if (aListId >= theTextures.Length()) + { + theTextures.Append (aTexture); + theVertsPerTexture.Append (new NCollection_Vector()); + theTCrdsPerTexture.Append (new NCollection_Vector()); + } + + NCollection_Vector& aVerts = *theVertsPerTexture.ChangeValue (aListId); + NCollection_Vector& aTCrds = *theTCrdsPerTexture.ChangeValue (aListId); + + // apply floor on position to avoid blurring issues + // due to cross-pixel coordinates + aVerts.Append (floor(aRect.TopRight (aVec))); + aVerts.Append (floor(aRect.TopLeft (aVec))); + aVerts.Append (floor(aRect.BottomLeft (aVec))); + aTCrds.Append (aRectUV.TopRight (aVec)); + aTCrds.Append (aRectUV.TopLeft (aVec)); + aTCrds.Append (aRectUV.BottomLeft (aVec)); + + aVerts.Append (floor(aRect.BottomRight (aVec))); + aVerts.Append (floor(aRect.TopRight (aVec))); + aVerts.Append (floor(aRect.BottomLeft (aVec))); + 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, + const Handle_OpenGl_Context& theCtx, + OpenGl_Font& theFont, + NCollection_Vector& theTextures, + NCollection_Vector& theVertsPerTexture, + NCollection_Vector& theTCrdsPerTexture) +{ + NCollection_Vector< NCollection_Handle > > aVertsPerTexture; + NCollection_Vector< NCollection_Handle > > aTCrdsPerTexture; + + createGlyphs (theFormatter, theCtx, theFont, theTextures, aVertsPerTexture, aTCrdsPerTexture); + + if (theVertsPerTexture.Length() != theTextures.Length()) + { + for (Standard_Integer aTextureIter = 0; aTextureIter < theVertsPerTexture.Length(); ++aTextureIter) + { + theVertsPerTexture.Value (aTextureIter)->Release (theCtx.operator->()); + theTCrdsPerTexture.Value (aTextureIter)->Release (theCtx.operator->()); + } + theVertsPerTexture.Clear(); + theTCrdsPerTexture.Clear(); + + const bool isNormalMode = theCtx->ToUseVbo(); + Handle(OpenGl_VertexBuffer) aVertsVbo, aTcrdsVbo; + while (theVertsPerTexture.Length() < theTextures.Length()) + { + if (isNormalMode) + { + aVertsVbo = new OpenGl_VertexBuffer(); + aTcrdsVbo = new OpenGl_VertexBuffer(); + } + else + { + aVertsVbo = new OpenGl_VertexBufferCompat(); + aTcrdsVbo = new OpenGl_VertexBufferCompat(); + } + theVertsPerTexture.Append (aVertsVbo); + theTCrdsPerTexture.Append (aTcrdsVbo); + aVertsVbo->Create (theCtx); + aTcrdsVbo->Create (theCtx); + } + } + + for (Standard_Integer aTextureIter = 0; aTextureIter < theTextures.Length(); ++aTextureIter) + { + const NCollection_Vector& aVerts = *aVertsPerTexture.Value (aTextureIter); + Handle(OpenGl_VertexBuffer)& aVertsVbo = theVertsPerTexture.ChangeValue (aTextureIter); + if (!aVertsVbo->Init (theCtx, 2, aVerts.Length(), (GLfloat* )NULL) + || !myVboEditor.Init (theCtx, aVertsVbo)) + { + continue; + } + for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter, myVboEditor.Next()) + { + myVboEditor.Value() = aVerts.Value (aVertIter); + } + myVboEditor.Flush(); + + const NCollection_Vector& aTCrds = *aTCrdsPerTexture.Value (aTextureIter); + Handle(OpenGl_VertexBuffer)& aTCrdsVbo = theTCrdsPerTexture.ChangeValue (aTextureIter); + if (!aTCrdsVbo->Init (theCtx, 2, aVerts.Length(), (GLfloat* )NULL) + || !myVboEditor.Init (theCtx, aTCrdsVbo)) + { + continue; + } + for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter, myVboEditor.Next()) + { + myVboEditor.Value() = aTCrds.Value (aVertIter); + } + myVboEditor.Flush(); + } + myVboEditor.Init (NULL, NULL); +} diff --git a/src/OpenGl/OpenGl_TextBuilder.hxx b/src/OpenGl/OpenGl_TextBuilder.hxx new file mode 100644 index 0000000000..016e518267 --- /dev/null +++ b/src/OpenGl/OpenGl_TextBuilder.hxx @@ -0,0 +1,62 @@ +// Created on: 2015-06-18 +// Created by: Ilya SEVRIKOV +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef OpenGl_TextBuilder_Header +#define OpenGl_TextBuilder_Header + +#include + +#include +#include +#include +#include +#include + +#include +#include + + +//! This class generates primitive array required for rendering textured text using OpenGl_Font instance. +class OpenGl_TextBuilder +{ +public: + + //! Creates empty object. + OpenGl_TextBuilder(); + + //! Creates texture quads for the given text. + Standard_EXPORT void Perform (const Font_TextFormatter& theFormatter, + const Handle(OpenGl_Context)& theContext, + OpenGl_Font& theFont, + NCollection_Vector& theTextures, + NCollection_Vector& theVertsPerTexture, + NCollection_Vector& theTCrdsPerTexture); + +protected: //! @name class auxillary methods + + Standard_EXPORT void createGlyphs (const Font_TextFormatter& theFormatter, + const Handle(OpenGl_Context)& theCtx, + OpenGl_Font& theFont, + NCollection_Vector& theTextures, + NCollection_Vector< NCollection_Handle < NCollection_Vector > >& theVertsPerTexture, + NCollection_Vector< NCollection_Handle < NCollection_Vector > >& theTCrdsPerTexture); + +protected: //! @name class auxillary fields + + NCollection_Vector myTileRects; + OpenGl_VertexBufferEditor myVboEditor; +}; + +#endif // OpenGl_TextBuilder_Header -- 2.39.5