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