1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-05 18:16:23 +03:00

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.
This commit is contained in:
isk 2015-07-29 13:28:49 +03:00 committed by bugmaster
parent 8a755387b6
commit 317d68c924
13 changed files with 767 additions and 590 deletions

View File

@ -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

View File

@ -15,6 +15,8 @@
#include <Font_FTFont.hxx>
#include <Font_FontMgr.hxx>
#include <Font_TextFormatter.hxx>
#include <TCollection_AsciiString.hxx>
#include <TCollection_HAsciiString.hxx>
@ -255,3 +257,25 @@ float Font_FTFont::AdvanceY (const Standard_Utf32Char theUCharNext)
}
return fromFTPoints<float> (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;
}

View File

@ -16,11 +16,13 @@
#ifndef _Font_FTFont_H__
#define _Font_FTFont_H__
#include <NCollection_Vec2.hxx>
#include <NCollection_String.hxx>
#include <Font_FTLibrary.hxx>
#include <Image_PixMap.hxx>
#include <Font_FontAspect.hxx>
#include <Font_FTLibrary.hxx>
#include <Graphic3d_HorizontalTextAlignment.hxx>
#include <Graphic3d_VerticalTextAlignment.hxx>
#include <Image_PixMap.hxx>
#include <NCollection_String.hxx>
#include <NCollection_Vec2.hxx>
//! 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<float> TopLeft() const
{
return NCollection_Vec2<float> (Left, Top);
}
NCollection_Vec2<float>& TopLeft (NCollection_Vec2<float>& 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.

View File

@ -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 <Font_TextFormatter.hxx>
namespace
{
typedef NCollection_Vec2<Standard_ShortReal> 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<Vec2f>& 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);
}
}

View File

@ -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 <OpenGl_Font.hxx>
#include <OpenGl_VertexBufferEditor.hxx>
#include <Graphic3d_HorizontalTextAlignment.hxx>
#include <Graphic3d_VerticalTextAlignment.hxx>
#include <NCollection_String.hxx>
#include <Font_FTFont.hxx>
#include <NCollection_DataMap.hxx>
#include <NCollection_Vector.hxx>
//! 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<GLuint>& theTextures,
NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > >& theVertsPerTexture,
NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > >& theTCrdsPerTexture) const;
//! Returns specific glyph rectangle.
inline const NCollection_Vec2<Standard_ShortReal>& TopLeft (const Standard_Integer theIndex) const
{
return myCorners.Value (theIndex);
}
//! Retrieve formatting results.
Standard_EXPORT void Result (const Handle(OpenGl_Context)& theCtx,
NCollection_Vector<GLuint>& theTextures,
NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theVertsPerTexture,
NCollection_Vector<Handle(OpenGl_VertexBuffer)>& 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<OpenGl_Font::Tile>
myRects; //!< glyphs rectangles
NCollection_Vec2<Standard_ShortReal>
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
@ -116,10 +118,6 @@ protected: //! @name input data
Standard_ShortReal myAscender; //!<
bool myIsFormatted; //!< formatting state
protected:
mutable OpenGl_VertexBufferEditor<OpenGl_Vec2> 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<Standard_ShortReal>
myMoveVec; //!< local variable
};
DEFINE_STANDARD_HANDLE(OpenGl_TextFormatter, Standard_Transient)
#endif // _OpenGl_TextFormatter_H__
#endif // Font_TextFormatter_Header

View File

@ -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

View File

@ -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;
}

View File

@ -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:

View File

@ -466,8 +466,7 @@ void OpenGl_Text::setupMatrix (const Handle(OpenGl_PrinterContext)& thePrintCtx,
anObjZ);
OpenGl_Utils::Translate<GLdouble> (aModViewMat, anObjX, anObjY, anObjZ);
OpenGl_Utils::Rotate<GLdouble> (aModViewMat, theTextAspect.Angle(), 0.0, 0.0, 1.0);
OpenGl_Utils::Rotate<GLdouble> (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);
}

View File

@ -20,7 +20,7 @@
#include <OpenGl_AspectText.hxx>
#include <OpenGl_TextParam.hxx>
#include <OpenGl_TextFormatter.hxx>
#include <OpenGl_TextBuilder.hxx>
#include <TCollection_ExtendedString.hxx>
#include <Graphic3d_Vertex.hxx>

View File

@ -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 <OpenGl_TextBuilder.hxx>
#include <OpenGl_VertexBufferCompat.hxx>
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<GLuint>& theTextures,
NCollection_Vector<NCollection_Handle<NCollection_Vector<OpenGl_Vec2> > >& theVertsPerTexture,
NCollection_Vector<NCollection_Handle<NCollection_Vector<OpenGl_Vec2> > >& 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<OpenGl_Vec2>());
theTCrdsPerTexture.Append (new NCollection_Vector<OpenGl_Vec2>());
}
NCollection_Vector<OpenGl_Vec2>& aVerts = *theVertsPerTexture.ChangeValue (aListId);
NCollection_Vector<OpenGl_Vec2>& 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<GLuint>& theTextures,
NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theVertsPerTexture,
NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theTCrdsPerTexture)
{
NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aVertsPerTexture;
NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > 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<OpenGl_Vec2>& 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<OpenGl_Vec2>& 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);
}

View File

@ -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 <Font_TextFormatter.hxx>
#include <OpenGl_Context.hxx>
#include <OpenGl_Font.hxx>
#include <OpenGl_VertexBuffer.hxx>
#include <OpenGl_VertexBufferEditor.hxx>
#include <OpenGl_Vec.hxx>
#include <NCollection_Vector.hxx>
#include <NCollection_Handle.hxx>
//! 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<GLuint>& theTextures,
NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theVertsPerTexture,
NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theTCrdsPerTexture);
protected: //! @name class auxillary methods
Standard_EXPORT void createGlyphs (const Font_TextFormatter& theFormatter,
const Handle(OpenGl_Context)& theCtx,
OpenGl_Font& theFont,
NCollection_Vector<GLuint>& theTextures,
NCollection_Vector< NCollection_Handle < NCollection_Vector <OpenGl_Vec2> > >& theVertsPerTexture,
NCollection_Vector< NCollection_Handle < NCollection_Vector <OpenGl_Vec2> > >& theTCrdsPerTexture);
protected: //! @name class auxillary fields
NCollection_Vector<OpenGl_Font::Tile> myTileRects;
OpenGl_VertexBufferEditor<OpenGl_Vec2> myVboEditor;
};
#endif // OpenGl_TextBuilder_Header

View File

@ -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 <OpenGl_TextFormatter.hxx>
#include <OpenGl_VertexBufferCompat.hxx>
#include <cmath>
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<OpenGl_Font::Tile>& 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<OpenGl_Font::Tile>& 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<OpenGl_Font::Tile>& 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<GLuint>& theTextures,
NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > >& theVertsPerTexture,
NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > >& 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<OpenGl_Vec2>());
theTCrdsPerTexture.Append (new NCollection_Vector<OpenGl_Vec2>());
}
NCollection_Vector<OpenGl_Vec2>& aVerts = *theVertsPerTexture.ChangeValue (aListId);
NCollection_Vector<OpenGl_Vec2>& 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<GLuint>& theTextures,
NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theVertsPerTexture,
NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theTCrdsPerTexture) const
{
NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aVertsPerTexture;
NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > 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<OpenGl_Vec2>& 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<OpenGl_Vec2>& 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);
}
}