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_VertexBuffer.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());
88 IMPLEMENT_STANDARD_HANDLE (OpenGl_TextFormatter, Standard_Transient)
89 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_TextFormatter, Standard_Transient)
91 // =======================================================================
92 // function : OpenGl_TextFormatter
94 // =======================================================================
95 OpenGl_TextFormatter::OpenGl_TextFormatter()
96 : myAlignX (Graphic3d_HTA_LEFT),
97 myAlignY (Graphic3d_VTA_TOP),
102 myLineSpacing (0.0f),
104 myIsFormatted (false),
110 myPenCurrLine (0.0f),
115 myMoveVec (0.0f, 0.0f)
120 // =======================================================================
121 // function : SetupAlignment
123 // =======================================================================
124 void OpenGl_TextFormatter::SetupAlignment (const Graphic3d_HorizontalTextAlignment theAlignX,
125 const Graphic3d_VerticalTextAlignment theAlignY)
127 myAlignX = theAlignX;
128 myAlignY = theAlignY;
131 // =======================================================================
134 // =======================================================================
135 void OpenGl_TextFormatter::Reset()
137 myIsFormatted = false;
139 myPen.x() = myPen.y() = 0.0f;
141 myLineSpacing = myAscender = 0.0f;
146 // =======================================================================
149 // =======================================================================
150 void OpenGl_TextFormatter::Result (NCollection_Vector<GLuint>& theTextures,
151 NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > >& theVertsPerTexture,
152 NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > >& theTCrdsPerTexture) const
154 OpenGl_Vec2 aVec (0.0f, 0.0f);
156 theVertsPerTexture.Clear();
157 theTCrdsPerTexture.Clear();
158 for (Standard_Integer aRectIter = 0; aRectIter < myRectsNb; ++aRectIter)
160 const Font_FTFont::Rect& aRect = myRects.Value (aRectIter).px;
161 const Font_FTFont::Rect& aRectUV = myRects.Value (aRectIter).uv;
162 const GLuint aTexture = myRects.Value (aRectIter).texture;
164 Standard_Integer aListId = 0;
165 for (aListId = 0; aListId < theTextures.Length(); ++aListId)
167 if (theTextures.Value (aListId) == aTexture)
172 if (aListId >= theTextures.Length())
174 theTextures.Append (aTexture);
175 theVertsPerTexture.Append (new NCollection_Vector<OpenGl_Vec2>());
176 theTCrdsPerTexture.Append (new NCollection_Vector<OpenGl_Vec2>());
179 NCollection_Vector<OpenGl_Vec2>& aVerts = *theVertsPerTexture.ChangeValue (aListId);
180 NCollection_Vector<OpenGl_Vec2>& aTCrds = *theTCrdsPerTexture.ChangeValue (aListId);
182 // apply floor on position to avoid blurring issues
183 // due to cross-pixel coordinates
184 aVerts.Append (floor(aRect.BottomLeft (aVec)));
185 aVerts.Append (floor(aRect.TopLeft (aVec)));
186 aVerts.Append (floor(aRect.TopRight (aVec)));
187 aTCrds.Append (aRectUV.BottomLeft (aVec));
188 aTCrds.Append (aRectUV.TopLeft (aVec));
189 aTCrds.Append (aRectUV.TopRight (aVec));
191 aVerts.Append (floor(aRect.BottomLeft (aVec)));
192 aVerts.Append (floor(aRect.TopRight (aVec)));
193 aVerts.Append (floor(aRect.BottomRight (aVec)));
194 aTCrds.Append (aRectUV.BottomLeft (aVec));
195 aTCrds.Append (aRectUV.TopRight (aVec));
196 aTCrds.Append (aRectUV.BottomRight (aVec));
200 // =======================================================================
203 // =======================================================================
204 void OpenGl_TextFormatter::Result (const Handle(OpenGl_Context)& theCtx,
205 NCollection_Vector<GLuint>& theTextures,
206 NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theVertsPerTexture,
207 NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theTCrdsPerTexture) const
209 NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aVertsPerTexture;
210 NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aTCrdsPerTexture;
211 Result (theTextures, aVertsPerTexture, aTCrdsPerTexture);
213 if (theVertsPerTexture.Length() != theTextures.Length())
215 for (Standard_Integer aTextureIter = 0; aTextureIter < theVertsPerTexture.Length(); ++aTextureIter)
217 theVertsPerTexture.Value (aTextureIter)->Release (theCtx.operator->());
218 theTCrdsPerTexture.Value (aTextureIter)->Release (theCtx.operator->());
220 theVertsPerTexture.Clear();
221 theTCrdsPerTexture.Clear();
223 while (theVertsPerTexture.Length() < theTextures.Length())
225 Handle(OpenGl_VertexBuffer) aVertsVbo = new OpenGl_VertexBuffer();
226 Handle(OpenGl_VertexBuffer) aTcrdsVbo = new OpenGl_VertexBuffer();
227 theVertsPerTexture.Append (aVertsVbo);
228 theTCrdsPerTexture.Append (aTcrdsVbo);
229 aVertsVbo->Create (theCtx);
230 aTcrdsVbo->Create (theCtx);
234 for (Standard_Integer aTextureIter = 0; aTextureIter < theTextures.Length(); ++aTextureIter)
236 const NCollection_Vector<OpenGl_Vec2>& aVerts = *aVertsPerTexture.Value (aTextureIter);
237 Handle(OpenGl_VertexBuffer)& aVertsVbo = theVertsPerTexture.ChangeValue (aTextureIter);
238 if (!aVertsVbo->Init (theCtx, 2, aVerts.Length(), (GLfloat* )NULL)
239 || !myVboEditor.Init (theCtx, aVertsVbo))
243 for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter, myVboEditor.Next())
245 myVboEditor.Value() = aVerts.Value (aVertIter);
249 const NCollection_Vector<OpenGl_Vec2>& aTCrds = *aTCrdsPerTexture.Value (aTextureIter);
250 Handle(OpenGl_VertexBuffer)& aTCrdsVbo = theTCrdsPerTexture.ChangeValue (aTextureIter);
251 if (!aTCrdsVbo->Init (theCtx, 2, aVerts.Length(), (GLfloat* )NULL)
252 || !myVboEditor.Init (theCtx, aTCrdsVbo))
256 for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter, myVboEditor.Next())
258 myVboEditor.Value() = aTCrds.Value (aVertIter);
262 myVboEditor.Init (NULL, NULL);
265 // =======================================================================
268 // =======================================================================
269 void OpenGl_TextFormatter::Result (const Handle(OpenGl_Context)& /*theCtx*/,
270 NCollection_Vector<GLuint>& theTextures,
271 NCollection_Vector<Handle(OpenGl_Vec2Array)>& theVertsPerTexture,
272 NCollection_Vector<Handle(OpenGl_Vec2Array)>& theTCrdsPerTexture) const
274 NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aVertsPerTexture;
275 NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aTCrdsPerTexture;
276 Result (theTextures, aVertsPerTexture, aTCrdsPerTexture);
278 theVertsPerTexture.Clear();
279 theTCrdsPerTexture.Clear();
281 for (Standard_Integer aTextureIter = 0; aTextureIter < theTextures.Length(); ++aTextureIter)
283 const NCollection_Vector<OpenGl_Vec2>& aVerts = *aVertsPerTexture.Value (aTextureIter);
284 const NCollection_Vector<OpenGl_Vec2>& aTCrds = *aTCrdsPerTexture.Value (aTextureIter);
285 Handle(OpenGl_Vec2Array) aVertsArray = new OpenGl_Vec2Array (1, aVerts.Length());
286 Handle(OpenGl_Vec2Array) aTCrdsArray = new OpenGl_Vec2Array (1, aVerts.Length());
287 theVertsPerTexture.Append (aVertsArray);
288 theTCrdsPerTexture.Append (aTCrdsArray);
290 for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter)
292 aVertsArray->ChangeValue (aVertIter + 1) = aVerts.Value (aVertIter);
294 for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter)
296 aTCrdsArray->ChangeValue (aVertIter + 1) = aTCrds.Value (aVertIter);
301 // =======================================================================
304 // =======================================================================
305 void OpenGl_TextFormatter::Append (const Handle(OpenGl_Context)& theCtx,
306 const NCollection_String& theString,
307 OpenGl_Font& theFont)
309 if (theString.IsEmpty())
314 myAscender = Max (myAscender, theFont.Ascender());
315 myLineSpacing = Max (myLineSpacing, theFont.LineSpacing());
316 myString += theString;
318 int aSymbolsCounter = 0; // special counter to process tabulation symbols
320 // first pass - render all symbols using associated font on single ZERO baseline
321 OpenGl_Font::Tile aTile;
322 memset (&aTile, 0, sizeof(aTile));
323 for (NCollection_Utf8Iter anIter = theString.Iterator(); *anIter != 0;)
325 const Standard_Utf32Char aCharThis = *anIter;
326 const Standard_Utf32Char aCharNext = *++anIter;
328 if (aCharThis == '\x0D' // CR (carriage return)
329 || aCharThis == '\a' // BEL (alarm)
330 || aCharThis == '\f' // FF (form feed) NP (new page)
331 || aCharThis == '\b' // BS (backspace)
332 || aCharThis == '\v') // VT (vertical tab)
334 continue; // skip unsupported carriage control codes
336 else if (aCharThis == '\x0A') // LF (line feed, new line)
339 myNewLines.Append (myPen.x());
340 continue; // will be processed on second pass
342 else if (aCharThis == ' ')
345 myPen.x() += theFont.AdvanceX (' ', aCharNext);
348 else if (aCharThis == '\t')
350 const Standard_Integer aSpacesNum = (myTabSize - (aSymbolsCounter - 1) % myTabSize);
351 myPen.x() += theFont.AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum);
352 aSymbolsCounter += aSpacesNum;
357 theFont.RenderGlyph (theCtx,
358 aCharThis, aCharNext,
360 myRects.Append (aTile);
366 // =======================================================================
367 // function : newLine
369 // =======================================================================
370 void OpenGl_TextFormatter::newLine (const Standard_Integer theLastRect)
372 if (myRectLineStart >= myRectsNb)
375 myPenCurrLine -= myLineSpacing;
379 myMoveVec.y() = myPenCurrLine;
383 case Graphic3d_HTA_LEFT:
385 myMoveVec.x() = (myNewLineNb > 0) ? -myNewLines.Value (myNewLineNb - 1) : 0.0f;
388 case Graphic3d_HTA_RIGHT:
390 myMoveVec.x() = (myNewLineNb < myNewLines.Length())
391 ? -myNewLines.Value (myNewLineNb)
395 case Graphic3d_HTA_CENTER:
397 const Standard_ShortReal aFrom = (myNewLineNb > 0)
398 ? myNewLines.Value (myNewLineNb - 1)
400 const Standard_ShortReal aTo = (myNewLineNb < myNewLines.Length())
401 ? myNewLines.Value (myNewLineNb)
403 myMoveVec.x() = -0.5f * (aFrom + aTo);
408 move (myRects, myMoveVec, myRectLineStart, theLastRect);
411 myPenCurrLine -= myLineSpacing;
412 myRectLineStart = myRectWordStart = theLastRect + 1;
413 if (myRectLineStart < myRectsNb)
415 myLineLeft = myRects.Value (myRectLineStart).px.Left;
419 // =======================================================================
422 // =======================================================================
423 void OpenGl_TextFormatter::Format()
425 if (myRectsNb == 0 || myIsFormatted)
430 myIsFormatted = true;
431 myLinesNb = myRectLineStart = myRectWordStart = 0;
436 myMoveVec.x() = myMoveVec.y() = 0.0f;
438 // split text into lines and apply horizontal alignment
439 myPenCurrLine = -myAscender;
440 Standard_Integer aRectIter = 0;
442 for (NCollection_Utf8Iter anIter = myString.Iterator(); *anIter != 0; ++anIter)
444 const Standard_Utf32Char aCharThis = *anIter;
445 if (aCharThis == '\x0D' // CR (carriage return)
446 || aCharThis == '\a' // BEL (alarm)
447 || aCharThis == '\f' // FF (form feed) NP (new page)
448 || aCharThis == '\b' // BS (backspace)
449 || aCharThis == '\v') // VT (vertical tab)
451 continue; // skip unsupported carriage control codes
453 else if (aCharThis == '\x0A') // LF (line feed, new line)
455 const Standard_Integer aLastRect = aRectIter - 1; // last rect on current line
460 else if (aCharThis == ' '
461 || aCharThis == '\t')
463 myRectWordStart = aRectIter;
467 Standard_ShortReal aWidth = myRects.Value (aRectIter).px.Right - myLineLeft;
468 myBndWidth = Max (myBndWidth, aWidth);
474 newLine (myRectsNb - 1);
476 // apply vertical alignment style
477 if (myAlignY == Graphic3d_VTA_BOTTOM)
479 myBndTop = -myLineSpacing - myPenCurrLine;
480 moveY (myRects, myBndTop, 0, myRectsNb - 1);
482 else if (myAlignY == Graphic3d_VTA_CENTER)
484 myBndTop = 0.5f * (myLineSpacing * Standard_ShortReal(myLinesNb));
485 moveY (myRects, myBndTop, 0, myRectsNb - 1);