From 317d68c924af34f28b5c06cdaa8526038cb47f56 Mon Sep 17 00:00:00 2001 From: isk Date: Wed, 29 Jul 2015 13:28:49 +0300 Subject: [PATCH] 0026361: Visualization - move OpenGl_TextFormatter to Font_TextFormatter for usage without OpenGL. Split OpenGl_TextFormatter into 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 | 3 + src/Font/Font_FTFont.cxx | 24 + src/Font/Font_FTFont.hxx | 32 +- src/Font/Font_TextFormatter.cxx | 308 ++++++++++++ .../Font_TextFormatter.hxx} | 74 ++- src/OpenGl/FILES | 114 ++--- src/OpenGl/OpenGl_Font.cxx | 23 +- src/OpenGl/OpenGl_Font.hxx | 17 +- src/OpenGl/OpenGl_Text.cxx | 18 +- src/OpenGl/OpenGl_Text.hxx | 2 +- src/OpenGl/OpenGl_TextBuilder.cxx | 221 +++++++++ src/OpenGl/OpenGl_TextBuilder.hxx | 62 +++ src/OpenGl/OpenGl_TextFormatter.cxx | 459 ------------------ 13 files changed, 767 insertions(+), 590 deletions(-) create mode 100644 src/Font/Font_TextFormatter.cxx rename src/{OpenGl/OpenGl_TextFormatter.hxx => Font/Font_TextFormatter.hxx} (64%) create mode 100644 src/OpenGl/OpenGl_TextBuilder.cxx create mode 100644 src/OpenGl/OpenGl_TextBuilder.hxx delete mode 100755 src/OpenGl/OpenGl_TextFormatter.cxx diff --git a/src/Font/FILES b/src/Font/FILES index ecd9c6e8c4..10bee7ac04 100644 --- a/src/Font/FILES +++ b/src/Font/FILES @@ -11,3 +11,6 @@ Font_NameOfFont.hxx Font_NListOfSystemFont.hxx Font_SystemFont.cxx Font_SystemFont.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 1e6403e796..d05739e86a 100755 --- a/src/Font/Font_FTFont.cxx +++ b/src/Font/Font_FTFont.cxx @@ -15,6 +15,8 @@ #include #include +#include + #include #include @@ -255,3 +257,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 f81fa4ed2d..9810abe610 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 +#include //! Wrapper over FreeType font. //! Notice that this class uses internal buffers for loaded glyphs @@ -38,6 +40,11 @@ public: float Top; float Bottom; + NCollection_Vec2 TopLeft() const + { + return NCollection_Vec2 (Left, Top); + } + NCollection_Vec2& TopLeft (NCollection_Vec2& theVec) const { theVec.x() = Left; @@ -66,6 +73,16 @@ public: return theVec; } + float Width () const + { + return Right - Left; + } + + float Height () const + { + return Top - Bottom; + } + }; public: @@ -178,6 +195,13 @@ 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 the text alignment options. + //! Its corners are relative to the text alignment anchor point, their coordinates can be negative. + 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/Font/Font_TextFormatter.cxx b/src/Font/Font_TextFormatter.cxx new file mode 100644 index 0000000000..a190f347da --- /dev/null +++ b/src/Font/Font_TextFormatter.cxx @@ -0,0 +1,308 @@ +// Created on: 2013-01-29 +// Created by: Kirill GAVRILOV +// Copyright (c) 2013-2014 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 + +namespace +{ + typedef NCollection_Vec2 Vec2f; + + //! Auxiliary function to translate corners by the vector. + inline void move (NCollection_Vector< Vec2f >& theCorners, + const Vec2f& theMoveVec, + Standard_Integer theCharLower, + const Standard_Integer theCharUpper) + { + for(; theCharLower <= theCharUpper; ++theCharLower) + { + theCorners.ChangeValue (theCharLower) += theMoveVec; + } + } + + //! Auxiliary function to translate corners in vertical direction. + inline void moveY (NCollection_Vector& theCorners, + const Standard_ShortReal theMoveVec, + Standard_Integer theCharLower, + const Standard_Integer theCharUpper) + { + for(; theCharLower <= theCharUpper; ++theCharLower) + { + theCorners.ChangeValue (theCharLower).y() += theMoveVec; + } + } + + //! Apply floor to vector components. + //! @param theVec - vector to change (by reference!) + //! @return modified vector + inline Vec2f& floor (Vec2f& theVec) + { + theVec.x() = std::floor (theVec.x()); + theVec.y() = std::floor (theVec.y()); + return theVec; + } + +} + +// ======================================================================= +// function : Font_TextFormatter +// purpose : +// ======================================================================= +Font_TextFormatter::Font_TextFormatter() +: myAlignX (Graphic3d_HTA_LEFT), + myAlignY (Graphic3d_VTA_TOP), + myTabSize (8), + // + 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), + myBndWidth (0.0f), + myMoveVec (0.0f, 0.0f) +{ + // +} + +// ======================================================================= +// function : SetupAlignment +// purpose : +// ======================================================================= +void Font_TextFormatter::SetupAlignment (const Graphic3d_HorizontalTextAlignment theAlignX, + const Graphic3d_VerticalTextAlignment theAlignY) +{ + myAlignX = theAlignX; + myAlignY = theAlignY; +} + +// ======================================================================= +// function : Reset +// purpose : +// ======================================================================= +void Font_TextFormatter::Reset() +{ + myIsFormatted = false; + myString.Clear(); + myPen.x() = myPen.y() = 0.0f; + myRectsNb = 0; + myLineSpacing = myAscender = 0.0f; + myCorners.Clear(); + myNewLines.Clear(); +} + +// ======================================================================= +// function : Append +// purpose : +// ======================================================================= +void Font_TextFormatter::Append (const NCollection_String& theString, + Font_FTFont& theFont) +{ + if (theString.IsEmpty()) + { + return; + } + + myAscender = Max (myAscender, theFont.Ascender()); + myLineSpacing = Max (myLineSpacing, theFont.LineSpacing()); + myString += theString; + + 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;) + { + 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; + myNewLines.Append (myPen.x()); + continue; // will be processed on second pass + } + else if (aCharThis == ' ') + { + ++aSymbolsCounter; + myPen.x() += theFont.AdvanceX (' ', aCharNext); + continue; + } + else if (aCharThis == '\t') + { + const Standard_Integer aSpacesNum = (myTabSize - (aSymbolsCounter - 1) % myTabSize); + myPen.x() += theFont.AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum); + aSymbolsCounter += aSpacesNum; + continue; + } + + ++aSymbolsCounter; + + myCorners.Append (myPen); + + myPen.x() += theFont.AdvanceX (aCharThis, aCharNext); + + ++myRectsNb; + } +} + +// ======================================================================= +// function : newLine +// purpose : +// ======================================================================= +void Font_TextFormatter::newLine (const Standard_Integer theLastRect) +{ + if (myRectLineStart >= myRectsNb) + { + ++myLinesNb; + myPenCurrLine -= myLineSpacing; + return; + } + + 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; + } + } + + move (myCorners, myMoveVec, myRectLineStart, theLastRect); + + ++myLinesNb; + myPenCurrLine -= myLineSpacing; + myRectLineStart = myRectWordStart = theLastRect + 1; +} + +// ======================================================================= +// function : Format +// purpose : +// ======================================================================= +void Font_TextFormatter::Format() +{ + if (myRectsNb == 0 || myIsFormatted) + { + return; + } + + myIsFormatted = true; + myLinesNb = myRectLineStart = myRectWordStart = 0; + myBndTop = 0.0f; + myBndWidth = 0.0f; + myMoveVec.x() = myMoveVec.y() = 0.0f; + + // split text into lines and apply horizontal alignment + 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; + 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) + { + // 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; + continue; + } + else if (aCharThis == ' ' + || aCharThis == '\t') + { + myRectWordStart = aRectIter; + continue; + } + + ++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); + + // apply vertical alignment style + if (myAlignY == Graphic3d_VTA_BOTTOM) + { + myBndTop = -myLineSpacing - myPenCurrLine; + moveY (myCorners, myBndTop, 0, myRectsNb - 1); + } + else if (myAlignY == Graphic3d_VTA_CENTER) + { + myBndTop = 0.5f * (myLineSpacing * Standard_ShortReal(myLinesNb)); + moveY (myCorners, myBndTop, 0, myRectsNb - 1); + } +} diff --git a/src/OpenGl/OpenGl_TextFormatter.hxx b/src/Font/Font_TextFormatter.hxx similarity index 64% rename from src/OpenGl/OpenGl_TextFormatter.hxx rename to src/Font/Font_TextFormatter.hxx index aa88497c19..f63d524524 100755 --- a/src/OpenGl/OpenGl_TextFormatter.hxx +++ b/src/Font/Font_TextFormatter.hxx @@ -13,25 +13,20 @@ // 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 +#include //! This class intended to prepare formatted text. -class OpenGl_TextFormatter : public Standard_Transient +class Font_TextFormatter { - public: //! Default constructor. - Standard_EXPORT OpenGl_TextFormatter(); + Standard_EXPORT Font_TextFormatter(); //! Setup alignment style. Standard_EXPORT void SetupAlignment (const Graphic3d_HorizontalTextAlignment theAlignX, @@ -41,24 +36,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 NCollection_Vec2& TopLeft (const Standard_Integer theIndex) const + { + return myCorners.Value (theIndex); + } - //! Retrieve formatting results. - Standard_EXPORT void Result (const Handle(OpenGl_Context)& theCtx, - NCollection_Vector& theTextures, - NCollection_Vector& theVertsPerTexture, - NCollection_Vector& theTCrdsPerTexture) const; + //! Returns current rendering string. + inline const NCollection_String& String() const + { + return myString; + } + + //! Returns tab size. + inline Standard_Integer TabSize() const + { + return myTabSize; + } //! @return width of formatted text. inline Standard_ShortReal ResultWidth() const @@ -106,9 +107,10 @@ protected: //! @name configuration protected: //! @name input data NCollection_String myString; //!< currently rendered text - OpenGl_Vec2 myPen; //!< current pen position - NCollection_Vector - myRects; //!< glyphs rectangles + NCollection_Vec2 + myPen; //!< current pen position + NCollection_Vector < NCollection_Vec2 > + myCorners; //!< The top left corners of a formatted rectangles. Standard_Integer myRectsNb; //!< rectangles number NCollection_Vector myNewLines; //!< position at LF @@ -116,10 +118,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) @@ -128,18 +126,10 @@ protected: //! @name temporary variables for formatting routines Standard_Integer myNewLineNb; Standard_ShortReal myPenCurrLine; //!< current baseline position - Standard_ShortReal myLineLeft; //!< left x position of first glyph on line before formatting applied - Standard_ShortReal myLineTail; Standard_ShortReal myBndTop; Standard_ShortReal myBndWidth; - OpenGl_Vec2 myMoveVec; //!< local variable - -public: - - DEFINE_STANDARD_RTTI(OpenGl_TextFormatter, Standard_Transient) // Type definition - + NCollection_Vec2 + myMoveVec; //!< local variable }; -DEFINE_STANDARD_HANDLE(OpenGl_TextFormatter, Standard_Transient) - -#endif // _OpenGl_TextFormatter_H__ +#endif // Font_TextFormatter_Header diff --git a/src/OpenGl/FILES b/src/OpenGl/FILES index 26c048d062..9086560843 100755 --- a/src/OpenGl/FILES +++ b/src/OpenGl/FILES @@ -12,8 +12,58 @@ OpenGl_AspectMarker.cxx OpenGl_AspectMarker.hxx OpenGl_AspectText.cxx OpenGl_AspectText.hxx -OpenGl_AVIWriter.cxx +OpenGl_Group.hxx +OpenGl_Group.cxx +OpenGl_Structure.hxx +OpenGl_Structure.cxx +OpenGl_StructureShadow.hxx +OpenGl_StructureShadow.cxx +OpenGl_Element.hxx +OpenGl_Element.cxx +OpenGl_Text.hxx +OpenGl_Text.cxx +OpenGl_PointSprite.hxx +OpenGl_PointSprite.cxx +OpenGl_PrimitiveArray.hxx +OpenGl_PrimitiveArray.cxx +OpenGl_Workspace.hxx +OpenGl_Workspace.cxx +OpenGl_Workspace_2.cxx +OpenGl_Workspace_5.cxx +OpenGl_View.hxx +OpenGl_View.cxx +OpenGl_View_2.cxx +OpenGl_Light.hxx +OpenGl_Trihedron.hxx +OpenGl_Trihedron.cxx +OpenGl_GraduatedTrihedron.hxx +OpenGl_GraduatedTrihedron.cxx +OpenGl_Matrix.hxx +OpenGl_Matrix.cxx +OpenGl_CView.hxx +OpenGl_NamedStatus.hxx +OpenGl_TextParam.hxx +OpenGl_PrinterContext.hxx +OpenGl_PrinterContext.cxx +OpenGl_LineAttributes.hxx +OpenGl_LineAttributes.cxx +OpenGl_Window.hxx +OpenGl_Window.cxx +OpenGl_Window_1.mm OpenGl_AVIWriter.hxx +OpenGl_AVIWriter.cxx +OpenGl_FrameBuffer.hxx +OpenGl_FrameBuffer.cxx +OpenGl_Texture.cxx +OpenGl_Texture.hxx +OpenGl_Resource.hxx +OpenGl_Resource.cxx +OpenGl_telem_util.hxx +OpenGl_telem_util.cxx +OpenGl_transform_persistence.hxx +OpenGl_Font.hxx +OpenGl_Font.cxx +OpenGl_tgl_funcs.hxx OpenGl_BackgroundArray.cxx OpenGl_BackgroundArray.hxx OpenGl_BVHClipPrimitiveSet.cxx @@ -31,20 +81,14 @@ OpenGl_Clipping.hxx OpenGl_Context.cxx OpenGl_Context.hxx OpenGl_Context_1.mm -OpenGl_CView.hxx OpenGl_Cylinder.cxx OpenGl_Cylinder.hxx OpenGl_Disk.cxx OpenGl_Disk.hxx -OpenGl_Element.cxx -OpenGl_Element.hxx OpenGl_ExtGS.hxx +OpenGl_GlFunctions.hxx OpenGl_Flipper.cxx OpenGl_Flipper.hxx -OpenGl_Font.cxx -OpenGl_Font.hxx -OpenGl_FrameBuffer.cxx -OpenGl_FrameBuffer.hxx OpenGl_GlCore11.hxx OpenGl_GlCore11Fwd.hxx OpenGl_GlCore12.hxx @@ -62,9 +106,9 @@ OpenGl_GlCore41.hxx OpenGl_GlCore42.hxx OpenGl_GlCore43.hxx OpenGl_GlCore44.hxx -OpenGl_GlFunctions.hxx -OpenGl_GraduatedTrihedron.cxx -OpenGl_GraduatedTrihedron.hxx +OpenGl_LayerList.cxx +OpenGl_LayerList.hxx +OpenGl_LayerFilter.hxx OpenGl_GraphicDriver.cxx OpenGl_GraphicDriver.hxx OpenGl_GraphicDriver_4.cxx @@ -72,33 +116,14 @@ OpenGl_GraphicDriver_7.cxx OpenGl_GraphicDriver_713.cxx OpenGl_GraphicDriver_Export.cxx OpenGl_GraphicDriver_Layer.cxx -OpenGl_Group.cxx -OpenGl_Group.hxx OpenGl_IndexBuffer.cxx OpenGl_IndexBuffer.hxx OpenGl_Layer.cxx OpenGl_Layer.hxx -OpenGl_LayerFilter.hxx -OpenGl_LayerList.cxx -OpenGl_LayerList.hxx -OpenGl_Light.hxx -OpenGl_LineAttributes.cxx -OpenGl_LineAttributes.hxx -OpenGl_Matrix.cxx -OpenGl_Matrix.hxx -OpenGl_NamedStatus.hxx -OpenGl_PointSprite.cxx -OpenGl_PointSprite.hxx -OpenGl_PrimitiveArray.cxx -OpenGl_PrimitiveArray.hxx -OpenGl_PrinterContext.cxx -OpenGl_PrinterContext.hxx OpenGl_Quadric.cxx OpenGl_Quadric.hxx OpenGl_RenderFilter.cxx OpenGl_RenderFilter.hxx -OpenGl_Resource.cxx -OpenGl_Resource.hxx OpenGl_Sampler.cxx OpenGl_Sampler.hxx OpenGl_SceneGeometry.cxx @@ -116,25 +141,8 @@ OpenGl_Sphere.cxx OpenGl_Sphere.hxx OpenGl_StencilTest.cxx OpenGl_StencilTest.hxx -OpenGl_Structure.cxx -OpenGl_Structure.hxx -OpenGl_StructureShadow.cxx -OpenGl_StructureShadow.hxx -OpenGl_telem_util.cxx -OpenGl_telem_util.hxx -OpenGl_Text.cxx -OpenGl_Text.hxx -OpenGl_TextFormatter.cxx -OpenGl_TextFormatter.hxx -OpenGl_TextParam.hxx -OpenGl_Texture.cxx -OpenGl_Texture.hxx OpenGl_TextureBufferArb.cxx OpenGl_TextureBufferArb.hxx -OpenGl_tgl_funcs.hxx -OpenGl_transform_persistence.hxx -OpenGl_Trihedron.cxx -OpenGl_Trihedron.hxx OpenGl_Utils.hxx OpenGl_Vec.hxx OpenGl_VertexBuffer.cxx @@ -143,14 +151,6 @@ OpenGl_VertexBuffer.lxx OpenGl_VertexBufferCompat.cxx OpenGl_VertexBufferCompat.hxx OpenGl_VertexBufferEditor.hxx -OpenGl_View.cxx -OpenGl_View.hxx -OpenGl_View_2.cxx OpenGl_View_Raytrace.cxx -OpenGl_Window.cxx -OpenGl_Window.hxx -OpenGl_Window_1.mm -OpenGl_Workspace.cxx -OpenGl_Workspace.hxx -OpenGl_Workspace_2.cxx -OpenGl_Workspace_5.cxx +OpenGl_TextBuilder.hxx +OpenGl_TextBuilder.cxx \ No newline at end of file diff --git a/src/OpenGl/OpenGl_Font.cxx b/src/OpenGl/OpenGl_Font.cxx index 86866d2907..dec6cf1d19 100755 --- a/src/OpenGl/OpenGl_Font.cxx +++ b/src/OpenGl/OpenGl_Font.cxx @@ -214,14 +214,12 @@ bool OpenGl_Font::renderGlyph (const Handle(OpenGl_Context)& theCtx, // function : RenderGlyph // purpose : // ======================================================================= -void OpenGl_Font::RenderGlyph (const Handle(OpenGl_Context)& theCtx, +bool OpenGl_Font::RenderGlyph (const Handle(OpenGl_Context)& theCtx, const Standard_Utf32Char theUChar, - const Standard_Utf32Char theUCharNext, - OpenGl_Font::Tile& theGlyph, - OpenGl_Vec2& thePen) + Tile& theGlyph) { Standard_Integer aTileId = 0; - if (!myGlyphMap.Find (theUChar, aTileId)) + if (!myGlyphMap.Find (theUChar,aTileId)) { if (renderGlyph (theCtx, theUChar)) { @@ -229,19 +227,16 @@ void OpenGl_Font::RenderGlyph (const Handle(OpenGl_Context)& theCtx, } else { - thePen.x() += myFont->AdvanceX (theUChar, theUCharNext); - return; + return false; } + myGlyphMap.Bind (theUChar, aTileId); } const OpenGl_Font::Tile& aTile = myTiles.Value (aTileId); - theGlyph.px.Top = thePen.y() + aTile.px.Top; - theGlyph.px.Bottom = thePen.y() + aTile.px.Bottom; - theGlyph.px.Left = thePen.x() + aTile.px.Left; - theGlyph.px.Right = thePen.x() + aTile.px.Right; - theGlyph.uv = aTile.uv; - theGlyph.texture = aTile.texture; + theGlyph.px = aTile.px; + theGlyph.uv = aTile.uv; + theGlyph.texture = aTile.texture; - thePen.x() += myFont->AdvanceX (theUChar, theUCharNext); + return true; } diff --git a/src/OpenGl/OpenGl_Font.hxx b/src/OpenGl/OpenGl_Font.hxx index 317a84aa42..367ef8a4d1 100755 --- a/src/OpenGl/OpenGl_Font.hxx +++ b/src/OpenGl/OpenGl_Font.hxx @@ -71,6 +71,12 @@ public: return myFont; } + //! @return FreeType font instance specified on construction. + inline Handle(Font_FTFont)& FTFont() + { + return myFont; + } + //! @return true if font was loaded successfully. inline bool IsValid() const { @@ -115,18 +121,13 @@ public: return myLineSpacing; } - //! Compute glyph rectangle at specified pen position (on baseline) - //! and render it to texture if not already. + //! Render glyph to texture if not already. //! @param theCtx active context //! @param theUChar unicode symbol to render - //! @param theUCharNext next symbol to compute advance with kerning when available //! @param theGlyph computed glyph position rectangle, texture ID and UV coordinates - //! @param thePen pen position on baseline to place new glyph - Standard_EXPORT void RenderGlyph (const Handle(OpenGl_Context)& theCtx, + Standard_EXPORT bool RenderGlyph (const Handle(OpenGl_Context)& theCtx, const Standard_Utf32Char theUChar, - const Standard_Utf32Char theUCharNext, - Tile& theGlyph, - OpenGl_Vec2& thePen); + Tile& theGlyph); protected: diff --git a/src/OpenGl/OpenGl_Text.cxx b/src/OpenGl/OpenGl_Text.cxx index 6afcffefc4..ddc10273d7 100644 --- a/src/OpenGl/OpenGl_Text.cxx +++ b/src/OpenGl/OpenGl_Text.cxx @@ -466,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 @@ -582,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); @@ -658,13 +658,21 @@ 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 dc755cbc68..88c34de090 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..c814e24108 --- /dev/null +++ b/src/OpenGl/OpenGl_TextBuilder.cxx @@ -0,0 +1,221 @@ +// 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 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 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(aTile.px.TopRight (aVec))); + aVerts.Append (floor(aTile.px.TopLeft (aVec))); + aVerts.Append (floor(aTile.px.BottomLeft (aVec))); + aTCrds.Append (aRectUV.TopRight (aVec)); + aTCrds.Append (aRectUV.TopLeft (aVec)); + aTCrds.Append (aRectUV.BottomLeft (aVec)); + + aVerts.Append (floor(aTile.px.BottomRight (aVec))); + aVerts.Append (floor(aTile.px.TopRight (aVec))); + aVerts.Append (floor(aTile.px.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 diff --git a/src/OpenGl/OpenGl_TextFormatter.cxx b/src/OpenGl/OpenGl_TextFormatter.cxx deleted file mode 100755 index 9b60cac16d..0000000000 --- a/src/OpenGl/OpenGl_TextFormatter.cxx +++ /dev/null @@ -1,459 +0,0 @@ -// Created on: 2013-01-29 -// Created by: Kirill GAVRILOV -// Copyright (c) 2013-2014 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 - -#include - -namespace -{ - - //! Auxiliary function to translate rectangle by the vector. - inline void move (Font_FTFont::Rect& theRect, - const OpenGl_Vec2& theVec) - { - theRect.Left += theVec.x(); - theRect.Right += theVec.x(); - theRect.Top += theVec.y(); - theRect.Bottom += theVec.y(); - } - - //! 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) - { - for(; theCharLower <= theCharUpper; ++theCharLower) - { - Font_FTFont::Rect& aRect = theRects.ChangeValue (theCharLower).px; - 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, - const Standard_ShortReal theMoveVec, - Standard_Integer theCharLower, - const Standard_Integer theCharUpper) - { - for(; theCharLower <= theCharUpper; ++theCharLower) - { - Font_FTFont::Rect& aRect = theRects.ChangeValue (theCharLower).px; - aRect.Top += theMoveVec; - aRect.Bottom += theMoveVec; - } - } - - //! 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_TextFormatter -// purpose : -// ======================================================================= -OpenGl_TextFormatter::OpenGl_TextFormatter() -: myAlignX (Graphic3d_HTA_LEFT), - myAlignY (Graphic3d_VTA_TOP), - myTabSize (8), - // - 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), - myLineLeft (0.0f), - myLineTail (0.0f), - myBndTop (0.0f), - myBndWidth (0.0f), - myMoveVec (0.0f, 0.0f) -{ - // -} - -// ======================================================================= -// function : SetupAlignment -// purpose : -// ======================================================================= -void OpenGl_TextFormatter::SetupAlignment (const Graphic3d_HorizontalTextAlignment theAlignX, - const Graphic3d_VerticalTextAlignment theAlignY) -{ - myAlignX = theAlignX; - myAlignY = theAlignY; -} - -// ======================================================================= -// function : Reset -// purpose : -// ======================================================================= -void OpenGl_TextFormatter::Reset() -{ - myIsFormatted = false; - myString.Clear(); - myPen.x() = myPen.y() = 0.0f; - myRectsNb = 0; - myLineSpacing = myAscender = 0.0f; - myRects.Clear(); - 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) -{ - if (theString.IsEmpty()) - { - return; - } - - myAscender = Max (myAscender, theFont.Ascender()); - myLineSpacing = Max (myLineSpacing, theFont.LineSpacing()); - myString += theString; - - 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)); - for (NCollection_Utf8Iter anIter = theString.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; - myNewLines.Append (myPen.x()); - continue; // will be processed on second pass - } - else if (aCharThis == ' ') - { - ++aSymbolsCounter; - myPen.x() += theFont.AdvanceX (' ', aCharNext); - continue; - } - else if (aCharThis == '\t') - { - const Standard_Integer aSpacesNum = (myTabSize - (aSymbolsCounter - 1) % myTabSize); - myPen.x() += theFont.AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum); - aSymbolsCounter += aSpacesNum; - continue; - } - - ++aSymbolsCounter; - theFont.RenderGlyph (theCtx, - aCharThis, aCharNext, - aTile, myPen); - myRects.Append (aTile); - - ++myRectsNb; - } -} - -// ======================================================================= -// function : newLine -// purpose : -// ======================================================================= -void OpenGl_TextFormatter::newLine (const Standard_Integer theLastRect) -{ - if (myRectLineStart >= myRectsNb) - { - ++myLinesNb; - myPenCurrLine -= myLineSpacing; - return; - } - - 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; - } - } - - move (myRects, myMoveVec, myRectLineStart, theLastRect); - - ++myLinesNb; - myPenCurrLine -= myLineSpacing; - myRectLineStart = myRectWordStart = theLastRect + 1; - if (myRectLineStart < myRectsNb) - { - myLineLeft = myRects.Value (myRectLineStart).px.Left; - } -} - -// ======================================================================= -// function : Format -// purpose : -// ======================================================================= -void OpenGl_TextFormatter::Format() -{ - if (myRectsNb == 0 || myIsFormatted) - { - return; - } - - myIsFormatted = true; - myLinesNb = myRectLineStart = myRectWordStart = 0; - myLineLeft = 0.0f; - myLineTail = 0.0f; - myBndTop = 0.0f; - myBndWidth = 0.0f; - myMoveVec.x() = myMoveVec.y() = 0.0f; - - // split text into lines and apply horizontal alignment - myPenCurrLine = -myAscender; - Standard_Integer aRectIter = 0; - myNewLineNb = 0; - for (NCollection_Utf8Iter anIter = myString.Iterator(); *anIter != 0; ++anIter) - { - 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) - { - continue; // skip unsupported carriage control codes - } - else if (aCharThis == '\x0A') // LF (line feed, new line) - { - const Standard_Integer aLastRect = aRectIter - 1; // last rect on current line - newLine (aLastRect); - ++myNewLineNb; - continue; - } - else if (aCharThis == ' ' - || aCharThis == '\t') - { - myRectWordStart = aRectIter; - continue; - } - - Standard_ShortReal aWidth = myRects.Value (aRectIter).px.Right - myLineLeft; - myBndWidth = Max (myBndWidth, aWidth); - - ++aRectIter; - } - - // move last line - newLine (myRectsNb - 1); - - // apply vertical alignment style - if (myAlignY == Graphic3d_VTA_BOTTOM) - { - myBndTop = -myLineSpacing - myPenCurrLine; - moveY (myRects, myBndTop, 0, myRectsNb - 1); - } - else if (myAlignY == Graphic3d_VTA_CENTER) - { - myBndTop = 0.5f * (myLineSpacing * Standard_ShortReal(myLinesNb)); - moveY (myRects, myBndTop, 0, myRectsNb - 1); - } -}