1 // Created on: 2013-01-29
2 // Created by: Kirill GAVRILOV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <OpenGl_TextFormatter.hxx>
18 #include <OpenGl_VertexBufferCompat.hxx>
25 //! Auxiliary function to translate rectangle by the vector.
26 inline void move (Font_FTFont::Rect& theRect,
27 const OpenGl_Vec2& theVec)
29 theRect.Left += theVec.x();
30 theRect.Right += theVec.x();
31 theRect.Top += theVec.y();
32 theRect.Bottom += theVec.y();
35 //! Auxiliary function to translate rectangles by the vector.
36 inline void move (NCollection_Vector<OpenGl_Font::Tile>& theRects,
37 const OpenGl_Vec2& theMoveVec,
38 Standard_Integer theCharLower,
39 const Standard_Integer theCharUpper)
41 for(; theCharLower <= theCharUpper; ++theCharLower)
43 Font_FTFont::Rect& aRect = theRects.ChangeValue (theCharLower).px;
44 move (aRect, theMoveVec);
48 //! Auxiliary function to translate rectangles in horizontal direction.
49 /*inline void moveX (NCollection_Vector<OpenGl_Font::Tile>& theRects,
50 const Standard_ShortReal theMoveVec,
51 Standard_Integer theCharLower,
52 const Standard_Integer theCharUpper)
54 for (; theCharLower <= theCharUpper; ++theCharLower)
56 Font_FTFont::Rect& aRect = theRects.ChangeValue (theCharLower).px;
57 aRect.Left += theMoveVec;
58 aRect.Right += theMoveVec;
62 //! Auxiliary function to translate rectangles in vertical direction.
63 inline void moveY (NCollection_Vector<OpenGl_Font::Tile>& theRects,
64 const Standard_ShortReal theMoveVec,
65 Standard_Integer theCharLower,
66 const Standard_Integer theCharUpper)
68 for(; theCharLower <= theCharUpper; ++theCharLower)
70 Font_FTFont::Rect& aRect = theRects.ChangeValue (theCharLower).px;
71 aRect.Top += theMoveVec;
72 aRect.Bottom += theMoveVec;
76 //! Apply floor to vector components.
77 //! @param theVec - vector to change (by reference!)
78 //! @return modified vector
79 inline OpenGl_Vec2& floor (OpenGl_Vec2& theVec)
81 theVec.x() = std::floor (theVec.x());
82 theVec.y() = std::floor (theVec.y());
89 // =======================================================================
90 // function : OpenGl_TextFormatter
92 // =======================================================================
93 OpenGl_TextFormatter::OpenGl_TextFormatter()
94 : myAlignX (Graphic3d_HTA_LEFT),
95 myAlignY (Graphic3d_VTA_TOP),
100 myLineSpacing (0.0f),
102 myIsFormatted (false),
108 myPenCurrLine (0.0f),
113 myMoveVec (0.0f, 0.0f)
118 // =======================================================================
119 // function : SetupAlignment
121 // =======================================================================
122 void OpenGl_TextFormatter::SetupAlignment (const Graphic3d_HorizontalTextAlignment theAlignX,
123 const Graphic3d_VerticalTextAlignment theAlignY)
125 myAlignX = theAlignX;
126 myAlignY = theAlignY;
129 // =======================================================================
132 // =======================================================================
133 void OpenGl_TextFormatter::Reset()
135 myIsFormatted = false;
137 myPen.x() = myPen.y() = 0.0f;
139 myLineSpacing = myAscender = 0.0f;
144 // =======================================================================
147 // =======================================================================
148 void OpenGl_TextFormatter::Result (NCollection_Vector<GLuint>& theTextures,
149 NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > >& theVertsPerTexture,
150 NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > >& theTCrdsPerTexture) const
152 OpenGl_Vec2 aVec (0.0f, 0.0f);
154 theVertsPerTexture.Clear();
155 theTCrdsPerTexture.Clear();
156 for (Standard_Integer aRectIter = 0; aRectIter < myRectsNb; ++aRectIter)
158 const Font_FTFont::Rect& aRect = myRects.Value (aRectIter).px;
159 const Font_FTFont::Rect& aRectUV = myRects.Value (aRectIter).uv;
160 const GLuint aTexture = myRects.Value (aRectIter).texture;
162 Standard_Integer aListId = 0;
163 for (aListId = 0; aListId < theTextures.Length(); ++aListId)
165 if (theTextures.Value (aListId) == aTexture)
170 if (aListId >= theTextures.Length())
172 theTextures.Append (aTexture);
173 theVertsPerTexture.Append (new NCollection_Vector<OpenGl_Vec2>());
174 theTCrdsPerTexture.Append (new NCollection_Vector<OpenGl_Vec2>());
177 NCollection_Vector<OpenGl_Vec2>& aVerts = *theVertsPerTexture.ChangeValue (aListId);
178 NCollection_Vector<OpenGl_Vec2>& aTCrds = *theTCrdsPerTexture.ChangeValue (aListId);
180 // apply floor on position to avoid blurring issues
181 // due to cross-pixel coordinates
182 aVerts.Append (floor(aRect.TopRight (aVec)));
183 aVerts.Append (floor(aRect.TopLeft (aVec)));
184 aVerts.Append (floor(aRect.BottomLeft (aVec)));
185 aTCrds.Append (aRectUV.TopRight (aVec));
186 aTCrds.Append (aRectUV.TopLeft (aVec));
187 aTCrds.Append (aRectUV.BottomLeft (aVec));
189 aVerts.Append (floor(aRect.BottomRight (aVec)));
190 aVerts.Append (floor(aRect.TopRight (aVec)));
191 aVerts.Append (floor(aRect.BottomLeft (aVec)));
192 aTCrds.Append (aRectUV.BottomRight (aVec));
193 aTCrds.Append (aRectUV.TopRight (aVec));
194 aTCrds.Append (aRectUV.BottomLeft (aVec));
198 // =======================================================================
201 // =======================================================================
202 void OpenGl_TextFormatter::Result (const Handle(OpenGl_Context)& theCtx,
203 NCollection_Vector<GLuint>& theTextures,
204 NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theVertsPerTexture,
205 NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theTCrdsPerTexture) const
207 NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aVertsPerTexture;
208 NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aTCrdsPerTexture;
209 Result (theTextures, aVertsPerTexture, aTCrdsPerTexture);
211 if (theVertsPerTexture.Length() != theTextures.Length())
213 for (Standard_Integer aTextureIter = 0; aTextureIter < theVertsPerTexture.Length(); ++aTextureIter)
215 theVertsPerTexture.Value (aTextureIter)->Release (theCtx.operator->());
216 theTCrdsPerTexture.Value (aTextureIter)->Release (theCtx.operator->());
218 theVertsPerTexture.Clear();
219 theTCrdsPerTexture.Clear();
221 const bool isNormalMode = theCtx->ToUseVbo();
222 Handle(OpenGl_VertexBuffer) aVertsVbo, aTcrdsVbo;
223 while (theVertsPerTexture.Length() < theTextures.Length())
227 aVertsVbo = new OpenGl_VertexBuffer();
228 aTcrdsVbo = new OpenGl_VertexBuffer();
232 aVertsVbo = new OpenGl_VertexBufferCompat();
233 aTcrdsVbo = new OpenGl_VertexBufferCompat();
235 theVertsPerTexture.Append (aVertsVbo);
236 theTCrdsPerTexture.Append (aTcrdsVbo);
237 aVertsVbo->Create (theCtx);
238 aTcrdsVbo->Create (theCtx);
242 for (Standard_Integer aTextureIter = 0; aTextureIter < theTextures.Length(); ++aTextureIter)
244 const NCollection_Vector<OpenGl_Vec2>& aVerts = *aVertsPerTexture.Value (aTextureIter);
245 Handle(OpenGl_VertexBuffer)& aVertsVbo = theVertsPerTexture.ChangeValue (aTextureIter);
246 if (!aVertsVbo->Init (theCtx, 2, aVerts.Length(), (GLfloat* )NULL)
247 || !myVboEditor.Init (theCtx, aVertsVbo))
251 for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter, myVboEditor.Next())
253 myVboEditor.Value() = aVerts.Value (aVertIter);
257 const NCollection_Vector<OpenGl_Vec2>& aTCrds = *aTCrdsPerTexture.Value (aTextureIter);
258 Handle(OpenGl_VertexBuffer)& aTCrdsVbo = theTCrdsPerTexture.ChangeValue (aTextureIter);
259 if (!aTCrdsVbo->Init (theCtx, 2, aVerts.Length(), (GLfloat* )NULL)
260 || !myVboEditor.Init (theCtx, aTCrdsVbo))
264 for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter, myVboEditor.Next())
266 myVboEditor.Value() = aTCrds.Value (aVertIter);
270 myVboEditor.Init (NULL, NULL);
273 // =======================================================================
276 // =======================================================================
277 void OpenGl_TextFormatter::Append (const Handle(OpenGl_Context)& theCtx,
278 const NCollection_String& theString,
279 OpenGl_Font& theFont)
281 if (theString.IsEmpty())
286 myAscender = Max (myAscender, theFont.Ascender());
287 myLineSpacing = Max (myLineSpacing, theFont.LineSpacing());
288 myString += theString;
290 int aSymbolsCounter = 0; // special counter to process tabulation symbols
292 // first pass - render all symbols using associated font on single ZERO baseline
293 OpenGl_Font::Tile aTile;
294 memset (&aTile, 0, sizeof(aTile));
295 for (NCollection_Utf8Iter anIter = theString.Iterator(); *anIter != 0;)
297 const Standard_Utf32Char aCharThis = *anIter;
298 const Standard_Utf32Char aCharNext = *++anIter;
300 if (aCharThis == '\x0D' // CR (carriage return)
301 || aCharThis == '\a' // BEL (alarm)
302 || aCharThis == '\f' // FF (form feed) NP (new page)
303 || aCharThis == '\b' // BS (backspace)
304 || aCharThis == '\v') // VT (vertical tab)
306 continue; // skip unsupported carriage control codes
308 else if (aCharThis == '\x0A') // LF (line feed, new line)
311 myNewLines.Append (myPen.x());
312 continue; // will be processed on second pass
314 else if (aCharThis == ' ')
317 myPen.x() += theFont.AdvanceX (' ', aCharNext);
320 else if (aCharThis == '\t')
322 const Standard_Integer aSpacesNum = (myTabSize - (aSymbolsCounter - 1) % myTabSize);
323 myPen.x() += theFont.AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum);
324 aSymbolsCounter += aSpacesNum;
329 theFont.RenderGlyph (theCtx,
330 aCharThis, aCharNext,
332 myRects.Append (aTile);
338 // =======================================================================
339 // function : newLine
341 // =======================================================================
342 void OpenGl_TextFormatter::newLine (const Standard_Integer theLastRect)
344 if (myRectLineStart >= myRectsNb)
347 myPenCurrLine -= myLineSpacing;
351 myMoveVec.y() = myPenCurrLine;
355 case Graphic3d_HTA_LEFT:
357 myMoveVec.x() = (myNewLineNb > 0) ? -myNewLines.Value (myNewLineNb - 1) : 0.0f;
360 case Graphic3d_HTA_RIGHT:
362 myMoveVec.x() = (myNewLineNb < myNewLines.Length())
363 ? -myNewLines.Value (myNewLineNb)
367 case Graphic3d_HTA_CENTER:
369 const Standard_ShortReal aFrom = (myNewLineNb > 0)
370 ? myNewLines.Value (myNewLineNb - 1)
372 const Standard_ShortReal aTo = (myNewLineNb < myNewLines.Length())
373 ? myNewLines.Value (myNewLineNb)
375 myMoveVec.x() = -0.5f * (aFrom + aTo);
380 move (myRects, myMoveVec, myRectLineStart, theLastRect);
383 myPenCurrLine -= myLineSpacing;
384 myRectLineStart = myRectWordStart = theLastRect + 1;
385 if (myRectLineStart < myRectsNb)
387 myLineLeft = myRects.Value (myRectLineStart).px.Left;
391 // =======================================================================
394 // =======================================================================
395 void OpenGl_TextFormatter::Format()
397 if (myRectsNb == 0 || myIsFormatted)
402 myIsFormatted = true;
403 myLinesNb = myRectLineStart = myRectWordStart = 0;
408 myMoveVec.x() = myMoveVec.y() = 0.0f;
410 // split text into lines and apply horizontal alignment
411 myPenCurrLine = -myAscender;
412 Standard_Integer aRectIter = 0;
414 for (NCollection_Utf8Iter anIter = myString.Iterator(); *anIter != 0; ++anIter)
416 const Standard_Utf32Char aCharThis = *anIter;
417 if (aCharThis == '\x0D' // CR (carriage return)
418 || aCharThis == '\a' // BEL (alarm)
419 || aCharThis == '\f' // FF (form feed) NP (new page)
420 || aCharThis == '\b' // BS (backspace)
421 || aCharThis == '\v') // VT (vertical tab)
423 continue; // skip unsupported carriage control codes
425 else if (aCharThis == '\x0A') // LF (line feed, new line)
427 const Standard_Integer aLastRect = aRectIter - 1; // last rect on current line
432 else if (aCharThis == ' '
433 || aCharThis == '\t')
435 myRectWordStart = aRectIter;
439 Standard_ShortReal aWidth = myRects.Value (aRectIter).px.Right - myLineLeft;
440 myBndWidth = Max (myBndWidth, aWidth);
446 newLine (myRectsNb - 1);
448 // apply vertical alignment style
449 if (myAlignY == Graphic3d_VTA_BOTTOM)
451 myBndTop = -myLineSpacing - myPenCurrLine;
452 moveY (myRects, myBndTop, 0, myRectsNb - 1);
454 else if (myAlignY == Graphic3d_VTA_CENTER)
456 myBndTop = 0.5f * (myLineSpacing * Standard_ShortReal(myLinesNb));
457 moveY (myRects, myBndTop, 0, myRectsNb - 1);