0024275: Cppcheck warnings on uninitialized class members
[occt.git] / src / OpenGl / OpenGl_TextFormatter.cxx
1 // Created on: 2013-01-29
2 // Created by: Kirill GAVRILOV
3 // Copyright (c) 2013 OPEN CASCADE SAS
4 //
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
9 //
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12 //
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
19
20 #include <OpenGl_TextFormatter.hxx>
21
22 #include <OpenGl_VertexBuffer.hxx>
23
24 #include <cmath>
25
26 namespace
27 {
28
29   //! Auxiliary function to translate rectangle by the vector.
30   inline void move (Font_FTFont::Rect& theRect,
31                     const OpenGl_Vec2& theVec)
32   {
33     theRect.Left   += theVec.x();
34     theRect.Right  += theVec.x();
35     theRect.Top    += theVec.y();
36     theRect.Bottom += theVec.y();
37   }
38
39   //! Auxiliary function to translate rectangles by the vector.
40   inline void move (NCollection_Vector<OpenGl_Font::Tile>& theRects,
41                     const OpenGl_Vec2&                     theMoveVec,
42                     Standard_Integer                       theCharLower,
43                     const Standard_Integer                 theCharUpper)
44   {
45     for(; theCharLower <= theCharUpper; ++theCharLower)
46     {
47       Font_FTFont::Rect& aRect = theRects.ChangeValue (theCharLower).px;
48       move (aRect, theMoveVec);
49     }
50   }
51
52   //! Auxiliary function to translate rectangles in horizontal direction.
53   /*inline void moveX (NCollection_Vector<OpenGl_Font::Tile>& theRects,
54                      const Standard_ShortReal               theMoveVec,
55                      Standard_Integer                       theCharLower,
56                      const Standard_Integer                 theCharUpper)
57   {
58     for (; theCharLower <= theCharUpper; ++theCharLower)
59     {
60       Font_FTFont::Rect& aRect = theRects.ChangeValue (theCharLower).px;
61       aRect.Left  += theMoveVec;
62       aRect.Right += theMoveVec;
63     }
64   }*/
65
66   //! Auxiliary function to translate rectangles in vertical direction.
67   inline void moveY (NCollection_Vector<OpenGl_Font::Tile>& theRects,
68                      const Standard_ShortReal               theMoveVec,
69                      Standard_Integer                       theCharLower,
70                      const Standard_Integer                 theCharUpper)
71   {
72     for(; theCharLower <= theCharUpper; ++theCharLower)
73     {
74       Font_FTFont::Rect& aRect = theRects.ChangeValue (theCharLower).px;
75       aRect.Top    += theMoveVec;
76       aRect.Bottom += theMoveVec;
77     }
78   }
79
80   //! Apply floor to vector components.
81   //! @param  theVec - vector to change (by reference!)
82   //! @return modified vector
83   inline OpenGl_Vec2& floor (OpenGl_Vec2& theVec)
84   {
85     theVec.x() = std::floor (theVec.x());
86     theVec.y() = std::floor (theVec.y());
87     return theVec;
88   }
89
90 };
91
92 IMPLEMENT_STANDARD_HANDLE (OpenGl_TextFormatter, Standard_Transient)
93 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_TextFormatter, Standard_Transient)
94
95 // =======================================================================
96 // function : OpenGl_TextFormatter
97 // purpose  :
98 // =======================================================================
99 OpenGl_TextFormatter::OpenGl_TextFormatter()
100 : myAlignX (Graphic3d_HTA_LEFT),
101   myAlignY (Graphic3d_VTA_TOP),
102   myTabSize (8),
103   //
104   myPen (0.0f, 0.0f),
105   myRectsNb (0),
106   myLineSpacing (0.0f),
107   myAscender (0.0f),
108   myIsFormatted (false),
109   //
110   myLinesNb (0),
111   myRectLineStart (0),
112   myRectWordStart (0),
113   myNewLineNb(0),
114   myPenCurrLine (0.0f),
115   myLineLeft (0.0f),
116   myLineTail (0.0f),
117   myBndTop   (0.0f),
118   myBndWidth (0.0f),
119   myMoveVec (0.0f, 0.0f)
120 {
121   //
122 }
123
124 // =======================================================================
125 // function : SetupAlignment
126 // purpose  :
127 // =======================================================================
128 void OpenGl_TextFormatter::SetupAlignment (const Graphic3d_HorizontalTextAlignment theAlignX,
129                                            const Graphic3d_VerticalTextAlignment   theAlignY)
130 {
131   myAlignX = theAlignX;
132   myAlignY = theAlignY;
133 }
134
135 // =======================================================================
136 // function : Reset
137 // purpose  :
138 // =======================================================================
139 void OpenGl_TextFormatter::Reset()
140 {
141   myIsFormatted = false;
142   myString.Clear();
143   myPen.x() = myPen.y() = 0.0f;
144   myRectsNb = 0;
145   myLineSpacing = myAscender = 0.0f;
146   myRects.Clear();
147   myNewLines.Clear();
148 }
149
150 // =======================================================================
151 // function : Result
152 // purpose  :
153 // =======================================================================
154 void OpenGl_TextFormatter::Result (NCollection_Vector<GLuint>& theTextures,
155                                    NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > >& theVertsPerTexture,
156                                    NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > >& theTCrdsPerTexture) const
157 {
158   OpenGl_Vec2 aVec (0.0f, 0.0f);
159   theTextures.Clear();
160   theVertsPerTexture.Clear();
161   theTCrdsPerTexture.Clear();
162   for (Standard_Integer aRectIter = 0; aRectIter < myRectsNb; ++aRectIter)
163   {
164     const Font_FTFont::Rect& aRect    = myRects.Value (aRectIter).px;
165     const Font_FTFont::Rect& aRectUV  = myRects.Value (aRectIter).uv;
166     const GLuint             aTexture = myRects.Value (aRectIter).texture;
167
168     Standard_Integer aListId = 0;
169     for (aListId = 0; aListId < theTextures.Length(); ++aListId)
170     {
171       if (theTextures.Value (aListId) == aTexture)
172       {
173         break;
174       }
175     }
176     if (aListId >= theTextures.Length())
177     {
178       theTextures.Append (aTexture);
179       theVertsPerTexture.Append (new NCollection_Vector<OpenGl_Vec2>());
180       theTCrdsPerTexture.Append (new NCollection_Vector<OpenGl_Vec2>());
181     }
182
183     NCollection_Vector<OpenGl_Vec2>& aVerts = *theVertsPerTexture.ChangeValue (aListId);
184     NCollection_Vector<OpenGl_Vec2>& aTCrds = *theTCrdsPerTexture.ChangeValue (aListId);
185
186     // apply floor on position to avoid blurring issues
187     // due to cross-pixel coordinates
188     aVerts.Append (floor(aRect.BottomLeft (aVec)));
189     aVerts.Append (floor(aRect.TopLeft    (aVec)));
190     aVerts.Append (floor(aRect.TopRight   (aVec)));
191     aTCrds.Append (aRectUV.BottomLeft (aVec));
192     aTCrds.Append (aRectUV.TopLeft    (aVec));
193     aTCrds.Append (aRectUV.TopRight   (aVec));
194
195     aVerts.Append (floor(aRect.BottomLeft  (aVec)));
196     aVerts.Append (floor(aRect.TopRight    (aVec)));
197     aVerts.Append (floor(aRect.BottomRight (aVec)));
198     aTCrds.Append (aRectUV.BottomLeft  (aVec));
199     aTCrds.Append (aRectUV.TopRight    (aVec));
200     aTCrds.Append (aRectUV.BottomRight (aVec));
201   }
202 }
203
204 // =======================================================================
205 // function : Result
206 // purpose  :
207 // =======================================================================
208 void OpenGl_TextFormatter::Result (const Handle(OpenGl_Context)&                    theCtx,
209                                    NCollection_Vector<GLuint>&                      theTextures,
210                                    NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theVertsPerTexture,
211                                    NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theTCrdsPerTexture) const
212 {
213   NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aVertsPerTexture;
214   NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aTCrdsPerTexture;
215   Result (theTextures, aVertsPerTexture, aTCrdsPerTexture);
216
217   if (theVertsPerTexture.Length() != theTextures.Length())
218   {
219     for (Standard_Integer aTextureIter = 0; aTextureIter < theVertsPerTexture.Length(); ++aTextureIter)
220     {
221       theVertsPerTexture.Value (aTextureIter)->Release (theCtx.operator->());
222       theTCrdsPerTexture.Value (aTextureIter)->Release (theCtx.operator->());
223     }
224     theVertsPerTexture.Clear();
225     theTCrdsPerTexture.Clear();
226
227     while (theVertsPerTexture.Length() < theTextures.Length())
228     {
229       Handle(OpenGl_VertexBuffer) aVertsVbo = new OpenGl_VertexBuffer();
230       Handle(OpenGl_VertexBuffer) aTcrdsVbo = new OpenGl_VertexBuffer();
231       theVertsPerTexture.Append (aVertsVbo);
232       theTCrdsPerTexture.Append (aTcrdsVbo);
233       aVertsVbo->Create (theCtx);
234       aTcrdsVbo->Create (theCtx);
235     }
236   }
237
238   for (Standard_Integer aTextureIter = 0; aTextureIter < theTextures.Length(); ++aTextureIter)
239   {
240     const NCollection_Vector<OpenGl_Vec2>& aVerts = *aVertsPerTexture.Value (aTextureIter);
241     Handle(OpenGl_VertexBuffer)& aVertsVbo = theVertsPerTexture.ChangeValue (aTextureIter);
242     if (!aVertsVbo->Init (theCtx, 2, aVerts.Length(), (GLfloat* )NULL)
243      || !myVboEditor.Init (theCtx, aVertsVbo))
244     {
245       continue;
246     }
247     for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter, myVboEditor.Next())
248     {
249       myVboEditor.Value() = aVerts.Value (aVertIter);
250     }
251     myVboEditor.Flush();
252
253     const NCollection_Vector<OpenGl_Vec2>& aTCrds = *aTCrdsPerTexture.Value (aTextureIter);
254     Handle(OpenGl_VertexBuffer)& aTCrdsVbo = theTCrdsPerTexture.ChangeValue (aTextureIter);
255     if (!aTCrdsVbo->Init (theCtx, 2, aVerts.Length(), (GLfloat* )NULL)
256      || !myVboEditor.Init (theCtx, aTCrdsVbo))
257     {
258       continue;
259     }
260     for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter, myVboEditor.Next())
261     {
262       myVboEditor.Value() = aTCrds.Value (aVertIter);
263     }
264     myVboEditor.Flush();
265   }
266   myVboEditor.Init (NULL, NULL);
267 }
268
269 // =======================================================================
270 // function : Result
271 // purpose  :
272 // =======================================================================
273 void OpenGl_TextFormatter::Result (const Handle(OpenGl_Context)&                 /*theCtx*/,
274                                    NCollection_Vector<GLuint>&                   theTextures,
275                                    NCollection_Vector<Handle(OpenGl_Vec2Array)>& theVertsPerTexture,
276                                    NCollection_Vector<Handle(OpenGl_Vec2Array)>& theTCrdsPerTexture) const
277 {
278   NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aVertsPerTexture;
279   NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aTCrdsPerTexture;
280   Result (theTextures, aVertsPerTexture, aTCrdsPerTexture);
281
282   theVertsPerTexture.Clear();
283   theTCrdsPerTexture.Clear();
284
285   for (Standard_Integer aTextureIter = 0; aTextureIter < theTextures.Length(); ++aTextureIter)
286   {
287     const NCollection_Vector<OpenGl_Vec2>& aVerts = *aVertsPerTexture.Value (aTextureIter);
288     const NCollection_Vector<OpenGl_Vec2>& aTCrds = *aTCrdsPerTexture.Value (aTextureIter);
289     Handle(OpenGl_Vec2Array) aVertsArray = new OpenGl_Vec2Array (1, aVerts.Length());
290     Handle(OpenGl_Vec2Array) aTCrdsArray = new OpenGl_Vec2Array (1, aVerts.Length());
291     theVertsPerTexture.Append (aVertsArray);
292     theTCrdsPerTexture.Append (aTCrdsArray);
293
294     for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter)
295     {
296       aVertsArray->ChangeValue (aVertIter + 1) = aVerts.Value (aVertIter);
297     }
298     for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter)
299     {
300       aTCrdsArray->ChangeValue (aVertIter + 1) = aTCrds.Value (aVertIter);
301     }
302   }
303 }
304
305 // =======================================================================
306 // function : Append
307 // purpose  :
308 // =======================================================================
309 void OpenGl_TextFormatter::Append (const Handle(OpenGl_Context)& theCtx,
310                                    const NCollection_String&     theString,
311                                    OpenGl_Font&                  theFont)
312 {
313   if (theString.IsEmpty())
314   {
315     return;
316   }
317
318   myAscender    = Max (myAscender,    theFont.Ascender());
319   myLineSpacing = Max (myLineSpacing, theFont.LineSpacing());
320   myString     += theString;
321
322   int aSymbolsCounter = 0; // special counter to process tabulation symbols
323
324   // first pass - render all symbols using associated font on single ZERO baseline
325   OpenGl_Font::Tile aTile;
326   memset (&aTile, 0, sizeof(aTile));
327   for (NCollection_Utf8Iter anIter = theString.Iterator(); *anIter != 0;)
328   {
329     const Standard_Utf32Char aCharThis =   *anIter;
330     const Standard_Utf32Char aCharNext = *++anIter;
331
332     if (aCharThis == '\x0D' // CR  (carriage return)
333      || aCharThis == '\a'   // BEL (alarm)
334      || aCharThis == '\f'   // FF  (form feed) NP (new page)
335      || aCharThis == '\b'   // BS  (backspace)
336      || aCharThis == '\v')  // VT  (vertical tab)
337     {
338       continue; // skip unsupported carriage control codes
339     }
340     else if (aCharThis == '\x0A') // LF (line feed, new line)
341     {
342       aSymbolsCounter = 0;
343       myNewLines.Append (myPen.x());
344       continue; // will be processed on second pass
345     }
346     else if (aCharThis == ' ')
347     {
348       ++aSymbolsCounter;
349       myPen.x() += theFont.AdvanceX (' ', aCharNext);
350       continue;
351     }
352     else if (aCharThis == '\t')
353     {
354       const Standard_Integer aSpacesNum = (myTabSize - (aSymbolsCounter - 1) % myTabSize);
355       myPen.x() += theFont.AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum);
356       aSymbolsCounter += aSpacesNum;
357       continue;
358     }
359
360     ++aSymbolsCounter;
361     theFont.RenderGlyph (theCtx,
362                          aCharThis, aCharNext,
363                          aTile, myPen);
364     myRects.Append (aTile);
365
366     ++myRectsNb;
367   }
368 }
369
370 // =======================================================================
371 // function : newLine
372 // purpose  :
373 // =======================================================================
374 void OpenGl_TextFormatter::newLine (const Standard_Integer theLastRect)
375 {
376   if (myRectLineStart >= myRectsNb)
377   {
378     ++myLinesNb;
379     myPenCurrLine -= myLineSpacing;
380     return;
381   }
382
383   myMoveVec.y() = myPenCurrLine;
384   switch (myAlignX)
385   {
386     default:
387     case Graphic3d_HTA_LEFT:
388     {
389       myMoveVec.x() = (myNewLineNb > 0) ? -myNewLines.Value (myNewLineNb - 1) : 0.0f;
390       break;
391     }
392     case Graphic3d_HTA_RIGHT:
393     {
394       myMoveVec.x() = (myNewLineNb < myNewLines.Length())
395                     ? -myNewLines.Value (myNewLineNb)
396                     : -myPen.x();
397       break;
398     }
399     case Graphic3d_HTA_CENTER:
400     {
401       const Standard_ShortReal aFrom = (myNewLineNb > 0)
402                                      ? myNewLines.Value (myNewLineNb - 1)
403                                      : 0.0f;
404       const Standard_ShortReal aTo   = (myNewLineNb < myNewLines.Length())
405                                      ? myNewLines.Value (myNewLineNb)
406                                      : myPen.x();
407       myMoveVec.x() = -0.5f * (aFrom + aTo);
408       break;
409     }
410   }
411
412   move (myRects, myMoveVec, myRectLineStart, theLastRect);
413
414   ++myLinesNb;
415   myPenCurrLine -= myLineSpacing;
416   myRectLineStart = myRectWordStart = theLastRect + 1;
417   if (myRectLineStart < myRectsNb)
418   {
419     myLineLeft = myRects.Value (myRectLineStart).px.Left;
420   }
421 }
422
423 // =======================================================================
424 // function : Format
425 // purpose  :
426 // =======================================================================
427 void OpenGl_TextFormatter::Format()
428 {
429   if (myRectsNb == 0 || myIsFormatted)
430   {
431     return;
432   }
433
434   myIsFormatted = true;
435   myLinesNb = myRectLineStart = myRectWordStart = 0;
436   myLineLeft   = 0.0f;
437   myLineTail   = 0.0f;
438   myBndTop     = 0.0f;
439   myBndWidth   = 0.0f;
440   myMoveVec.x() = myMoveVec.y() = 0.0f;
441
442   // split text into lines and apply horizontal alignment
443   myPenCurrLine = -myAscender;
444   Standard_Integer aRectIter = 0;
445   myNewLineNb = 0;
446   for (NCollection_Utf8Iter anIter = myString.Iterator(); *anIter != 0; ++anIter)
447   {
448     const Standard_Utf32Char aCharThis = *anIter;
449     if (aCharThis == '\x0D' // CR  (carriage return)
450      || aCharThis == '\a'   // BEL (alarm)
451      || aCharThis == '\f'   // FF  (form feed) NP (new page)
452      || aCharThis == '\b'   // BS  (backspace)
453      || aCharThis == '\v')  // VT  (vertical tab)
454     {
455       continue; // skip unsupported carriage control codes
456     }
457     else if (aCharThis == '\x0A') // LF (line feed, new line)
458     {
459       const Standard_Integer aLastRect = aRectIter - 1; // last rect on current line
460       newLine (aLastRect);
461       ++myNewLineNb;
462       continue;
463     }
464     else if (aCharThis == ' '
465           || aCharThis == '\t')
466     {
467       myRectWordStart = aRectIter;
468       continue;
469     }
470
471     Standard_ShortReal aWidth = myRects.Value (aRectIter).px.Right - myLineLeft;
472     myBndWidth = Max (myBndWidth, aWidth);
473
474     ++aRectIter;
475   }
476
477   // move last line
478   newLine (myRectsNb - 1);
479
480   // apply vertical alignment style
481   if (myAlignY == Graphic3d_VTA_BOTTOM)
482   {
483     myBndTop = -myLineSpacing - myPenCurrLine;
484     moveY (myRects, myBndTop, 0, myRectsNb - 1);
485   }
486   else if (myAlignY == Graphic3d_VTA_CENTER)
487   {
488     myBndTop = 0.5f * (myLineSpacing * Standard_ShortReal(myLinesNb));
489     moveY (myRects, myBndTop, 0, myRectsNb - 1);
490   }
491 }