0026361: Visualization - move OpenGl_TextFormatter to Font_TextFormatter
[occt.git] / src / OpenGl / OpenGl_TextBuilder.cxx
1 // Created on: 2015-06-18
2 // Created by: Ilya SEVRIKOV
3 // Copyright (c) 2015 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <OpenGl_TextBuilder.hxx>
17 #include <OpenGl_VertexBufferCompat.hxx>
18
19 namespace
20 {
21   //! Apply floor to vector components.
22   //! @param  theVec - vector to change (by reference!)
23   //! @return modified vector
24   inline OpenGl_Vec2& floor (OpenGl_Vec2& theVec)
25   {
26     theVec.x() = std::floor (theVec.x());
27     theVec.y() = std::floor (theVec.y());
28     return theVec;
29   }
30 }
31
32 // =======================================================================
33 // function : OpenGl_TextBuilder
34 // purpose  :
35 // =======================================================================
36 OpenGl_TextBuilder::OpenGl_TextBuilder()
37 {
38   //
39 }
40
41 // =======================================================================
42 // function : createGlyphs
43 // purpose  :
44 // =======================================================================
45 void OpenGl_TextBuilder::createGlyphs (const Font_TextFormatter&                                                  theFormatter,
46                                        const Handle(OpenGl_Context)&                                              theCtx,
47                                        OpenGl_Font&                                                               theFont,
48                                        NCollection_Vector<GLuint>&                                                theTextures,
49                                        NCollection_Vector<NCollection_Handle<NCollection_Vector<OpenGl_Vec2> > >& theVertsPerTexture,
50                                        NCollection_Vector<NCollection_Handle<NCollection_Vector<OpenGl_Vec2> > >& theTCrdsPerTexture)
51 {
52   OpenGl_Vec2 aVec (0.0f, 0.0f);
53
54   theTextures.Clear();
55   theVertsPerTexture.Clear();
56   theTCrdsPerTexture.Clear();
57
58   OpenGl_Font::Tile aTile = {};
59   OpenGl_Vec2       aPen (0.0f, 0.0f);
60   Standard_Integer  aRectsNb = 0;
61   Standard_Integer  aSymbolsCounter = 0;
62
63   for (NCollection_Utf8Iter anIter = theFormatter.String().Iterator(); *anIter != 0;)
64   {
65     const Standard_Utf32Char aCharThis =   *anIter;
66     const Standard_Utf32Char aCharNext = *++anIter;
67
68     if (aCharThis == '\x0D' // CR  (carriage return)
69      || aCharThis == '\a'   // BEL (alarm)
70      || aCharThis == '\f'   // FF  (form feed) NP (new page)
71      || aCharThis == '\b'   // BS  (backspace)
72      || aCharThis == '\v')  // VT  (vertical tab)
73     {
74       continue; // skip unsupported carriage control codes
75     }
76     else if (aCharThis == '\x0A') // LF (line feed, new line)
77     {
78       aSymbolsCounter = 0;
79       continue; // will be processed on second pass
80     }
81     else if (aCharThis == ' ')
82     {
83       ++aSymbolsCounter;
84       aPen.x() += theFont.AdvanceX (' ', aCharNext);
85       continue;
86     }
87     else if (aCharThis == '\t')
88     {
89       const Standard_Integer aSpacesNum = (theFormatter.TabSize() - (aSymbolsCounter - 1) % theFormatter.TabSize());
90       aPen.x() += theFont.AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum);
91       aSymbolsCounter += aSpacesNum;
92       continue;
93     }
94
95     ++aSymbolsCounter;
96
97     theFont.RenderGlyph (theCtx, aCharThis, aTile);
98
99     const OpenGl_Vec2& aTopLeft = theFormatter.TopLeft (aRectsNb);
100     aTile.px.Right  += aTopLeft.x();
101     aTile.px.Left   += aTopLeft.x();
102     aTile.px.Bottom += aTopLeft.y();
103     aTile.px.Top    += aTopLeft.y();
104     const Font_FTFont::Rect& aRectUV  = aTile.uv;
105     const GLuint             aTexture = aTile.texture;
106
107     Standard_Integer aListId = 0;
108     for (aListId = 0; aListId < theTextures.Length(); ++aListId)
109     {
110       if (theTextures.Value (aListId) == aTexture)
111       {
112         break;
113       }
114     }
115     if (aListId >= theTextures.Length())
116     {
117       theTextures.Append (aTexture);
118       theVertsPerTexture.Append (new NCollection_Vector<OpenGl_Vec2>());
119       theTCrdsPerTexture.Append (new NCollection_Vector<OpenGl_Vec2>());
120     }
121
122     NCollection_Vector<OpenGl_Vec2>& aVerts = *theVertsPerTexture.ChangeValue (aListId);
123     NCollection_Vector<OpenGl_Vec2>& aTCrds = *theTCrdsPerTexture.ChangeValue (aListId);
124
125     // apply floor on position to avoid blurring issues
126     // due to cross-pixel coordinates
127     aVerts.Append (floor(aTile.px.TopRight   (aVec)));
128     aVerts.Append (floor(aTile.px.TopLeft    (aVec)));
129     aVerts.Append (floor(aTile.px.BottomLeft (aVec)));
130     aTCrds.Append (aRectUV.TopRight   (aVec));
131     aTCrds.Append (aRectUV.TopLeft    (aVec));
132     aTCrds.Append (aRectUV.BottomLeft (aVec));
133
134     aVerts.Append (floor(aTile.px.BottomRight (aVec)));
135     aVerts.Append (floor(aTile.px.TopRight    (aVec)));
136     aVerts.Append (floor(aTile.px.BottomLeft  (aVec)));
137     aTCrds.Append (aRectUV.BottomRight (aVec));
138     aTCrds.Append (aRectUV.TopRight    (aVec));
139     aTCrds.Append (aRectUV.BottomLeft  (aVec));
140
141     ++aRectsNb;
142   }
143 }
144
145 // =======================================================================
146 // function : CreateTextures
147 // purpose  :
148 // =======================================================================
149 void OpenGl_TextBuilder::Perform (const Font_TextFormatter&                        theFormatter,
150                                   const Handle(OpenGl_Context)&                    theCtx,
151                                   OpenGl_Font&                                     theFont,
152                                   NCollection_Vector<GLuint>&                      theTextures,
153                                   NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theVertsPerTexture,
154                                   NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theTCrdsPerTexture)
155 {
156   NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aVertsPerTexture;
157   NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aTCrdsPerTexture;
158
159   createGlyphs (theFormatter, theCtx, theFont, theTextures, aVertsPerTexture, aTCrdsPerTexture);
160
161   if (theVertsPerTexture.Length() != theTextures.Length())
162   {
163     for (Standard_Integer aTextureIter = 0; aTextureIter < theVertsPerTexture.Length(); ++aTextureIter)
164     {
165       theVertsPerTexture.Value (aTextureIter)->Release (theCtx.operator->());
166       theTCrdsPerTexture.Value (aTextureIter)->Release (theCtx.operator->());
167     }
168     theVertsPerTexture.Clear();
169     theTCrdsPerTexture.Clear();
170
171     const bool isNormalMode = theCtx->ToUseVbo();
172     Handle(OpenGl_VertexBuffer) aVertsVbo, aTcrdsVbo;
173     while (theVertsPerTexture.Length() < theTextures.Length())
174     {
175       if (isNormalMode)
176       {
177         aVertsVbo = new OpenGl_VertexBuffer();
178         aTcrdsVbo = new OpenGl_VertexBuffer();
179       }
180       else
181       {
182         aVertsVbo = new OpenGl_VertexBufferCompat();
183         aTcrdsVbo = new OpenGl_VertexBufferCompat();
184       }
185       theVertsPerTexture.Append (aVertsVbo);
186       theTCrdsPerTexture.Append (aTcrdsVbo);
187       aVertsVbo->Create (theCtx);
188       aTcrdsVbo->Create (theCtx);
189     }
190   }
191
192   for (Standard_Integer aTextureIter = 0; aTextureIter < theTextures.Length(); ++aTextureIter)
193   {
194     const NCollection_Vector<OpenGl_Vec2>& aVerts = *aVertsPerTexture.Value (aTextureIter);
195     Handle(OpenGl_VertexBuffer)& aVertsVbo = theVertsPerTexture.ChangeValue (aTextureIter);
196     if (!aVertsVbo->Init (theCtx, 2, aVerts.Length(), (GLfloat* )NULL)
197      || !myVboEditor.Init (theCtx, aVertsVbo))
198     {
199       continue;
200     }
201     for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter, myVboEditor.Next())
202     {
203       myVboEditor.Value() = aVerts.Value (aVertIter);
204     }
205     myVboEditor.Flush();
206
207     const NCollection_Vector<OpenGl_Vec2>& aTCrds = *aTCrdsPerTexture.Value (aTextureIter);
208     Handle(OpenGl_VertexBuffer)& aTCrdsVbo = theTCrdsPerTexture.ChangeValue (aTextureIter);
209     if (!aTCrdsVbo->Init (theCtx, 2, aVerts.Length(), (GLfloat* )NULL)
210      || !myVboEditor.Init (theCtx, aTCrdsVbo))
211     {
212       continue;
213     }
214     for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter, myVboEditor.Next())
215     {
216       myVboEditor.Value() = aTCrds.Value (aVertIter);
217     }
218     myVboEditor.Flush();
219   }
220   myVboEditor.Init (NULL, NULL);
221 }