0030537: Visualization - wrapping text in font text formatter
[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 #include <Font_TextFormatter.hxx>
21
22 namespace
23 {
24   //! Apply floor to vector components.
25   //! @param  theVec - vector to change (by reference!)
26   //! @return modified vector
27   inline OpenGl_Vec2& floor (OpenGl_Vec2& theVec)
28   {
29     theVec.x() = std::floor (theVec.x());
30     theVec.y() = std::floor (theVec.y());
31     return theVec;
32   }
33 }
34
35 // =======================================================================
36 // function : OpenGl_TextBuilder
37 // purpose  :
38 // =======================================================================
39 OpenGl_TextBuilder::OpenGl_TextBuilder()
40 {
41   //
42 }
43
44 // =======================================================================
45 // function : createGlyphs
46 // purpose  :
47 // =======================================================================
48 void OpenGl_TextBuilder::createGlyphs (const Handle(Font_TextFormatter)&                                          theFormatter,
49                                        const Handle(OpenGl_Context)&                                              theCtx,
50                                        OpenGl_Font&                                                               theFont,
51                                        NCollection_Vector<GLuint>&                                                theTextures,
52                                        NCollection_Vector<NCollection_Handle<NCollection_Vector<OpenGl_Vec2> > >& theVertsPerTexture,
53                                        NCollection_Vector<NCollection_Handle<NCollection_Vector<OpenGl_Vec2> > >& theTCrdsPerTexture)
54 {
55   OpenGl_Vec2 aVec (0.0f, 0.0f);
56
57   theTextures.Clear();
58   theVertsPerTexture.Clear();
59   theTCrdsPerTexture.Clear();
60
61   OpenGl_Font::Tile aTile = {Font_Rect(), Font_Rect(), 0u};
62   for (Font_TextFormatter::Iterator aFormatterIt (*theFormatter, Font_TextFormatter::IterationFilter_ExcludeInvisible);
63        aFormatterIt.More(); aFormatterIt.Next())
64   {
65     theFont.RenderGlyph (theCtx, aFormatterIt.Symbol(), aTile);
66
67     const OpenGl_Vec2& aBottomLeft = theFormatter->BottomLeft (aFormatterIt.SymbolPosition());
68     aTile.px.Right  += aBottomLeft.x();
69     aTile.px.Left   += aBottomLeft.x();
70     aTile.px.Bottom += aBottomLeft.y();
71     aTile.px.Top    += aBottomLeft.y();
72     const Font_Rect& aRectUV  = aTile.uv;
73     const GLuint     aTexture = aTile.texture;
74
75     Standard_Integer aListId = 0;
76     for (aListId = 0; aListId < theTextures.Length(); ++aListId)
77     {
78       if (theTextures.Value (aListId) == aTexture)
79       {
80         break;
81       }
82     }
83     if (aListId >= theTextures.Length())
84     {
85       theTextures.Append (aTexture);
86       theVertsPerTexture.Append (new NCollection_Vector<OpenGl_Vec2>());
87       theTCrdsPerTexture.Append (new NCollection_Vector<OpenGl_Vec2>());
88     }
89
90     NCollection_Vector<OpenGl_Vec2>& aVerts = *theVertsPerTexture.ChangeValue (aListId);
91     NCollection_Vector<OpenGl_Vec2>& aTCrds = *theTCrdsPerTexture.ChangeValue (aListId);
92
93     // apply floor on position to avoid blurring issues
94     // due to cross-pixel coordinates
95     aVerts.Append (floor(aTile.px.TopRight   (aVec)));
96     aVerts.Append (floor(aTile.px.TopLeft    (aVec)));
97     aVerts.Append (floor(aTile.px.BottomLeft (aVec)));
98     aTCrds.Append (aRectUV.TopRight   (aVec));
99     aTCrds.Append (aRectUV.TopLeft    (aVec));
100     aTCrds.Append (aRectUV.BottomLeft (aVec));
101
102     aVerts.Append (floor(aTile.px.BottomRight (aVec)));
103     aVerts.Append (floor(aTile.px.TopRight    (aVec)));
104     aVerts.Append (floor(aTile.px.BottomLeft  (aVec)));
105     aTCrds.Append (aRectUV.BottomRight (aVec));
106     aTCrds.Append (aRectUV.TopRight    (aVec));
107     aTCrds.Append (aRectUV.BottomLeft  (aVec));
108   }
109 }
110
111 // =======================================================================
112 // function : CreateTextures
113 // purpose  :
114 // =======================================================================
115 void OpenGl_TextBuilder::Perform (const Handle(Font_TextFormatter)&                theFormatter,
116                                   const Handle(OpenGl_Context)&                    theCtx,
117                                   OpenGl_Font&                                     theFont,
118                                   NCollection_Vector<GLuint>&                      theTextures,
119                                   NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theVertsPerTexture,
120                                   NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theTCrdsPerTexture)
121 {
122   NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aVertsPerTexture;
123   NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aTCrdsPerTexture;
124
125   createGlyphs (theFormatter, theCtx, theFont, theTextures, aVertsPerTexture, aTCrdsPerTexture);
126
127   if (theVertsPerTexture.Length() != theTextures.Length())
128   {
129     for (Standard_Integer aTextureIter = 0; aTextureIter < theVertsPerTexture.Length(); ++aTextureIter)
130     {
131       theVertsPerTexture.Value (aTextureIter)->Release (theCtx.operator->());
132       theTCrdsPerTexture.Value (aTextureIter)->Release (theCtx.operator->());
133     }
134     theVertsPerTexture.Clear();
135     theTCrdsPerTexture.Clear();
136
137     const bool isNormalMode = theCtx->ToUseVbo();
138     Handle(OpenGl_VertexBuffer) aVertsVbo, aTcrdsVbo;
139     while (theVertsPerTexture.Length() < theTextures.Length())
140     {
141       if (isNormalMode)
142       {
143         aVertsVbo = new OpenGl_VertexBuffer();
144         aTcrdsVbo = new OpenGl_VertexBuffer();
145       }
146       else
147       {
148         aVertsVbo = new OpenGl_VertexBufferCompat();
149         aTcrdsVbo = new OpenGl_VertexBufferCompat();
150       }
151       theVertsPerTexture.Append (aVertsVbo);
152       theTCrdsPerTexture.Append (aTcrdsVbo);
153       aVertsVbo->Create (theCtx);
154       aTcrdsVbo->Create (theCtx);
155     }
156   }
157
158   for (Standard_Integer aTextureIter = 0; aTextureIter < theTextures.Length(); ++aTextureIter)
159   {
160     const NCollection_Vector<OpenGl_Vec2>& aVerts = *aVertsPerTexture.Value (aTextureIter);
161     Handle(OpenGl_VertexBuffer)& aVertsVbo = theVertsPerTexture.ChangeValue (aTextureIter);
162     if (!aVertsVbo->Init (theCtx, 2, aVerts.Length(), (GLfloat* )NULL)
163      || !myVboEditor.Init (theCtx, aVertsVbo))
164     {
165       continue;
166     }
167     for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter, myVboEditor.Next())
168     {
169       myVboEditor.Value() = aVerts.Value (aVertIter);
170     }
171     myVboEditor.Flush();
172
173     const NCollection_Vector<OpenGl_Vec2>& aTCrds = *aTCrdsPerTexture.Value (aTextureIter);
174     Handle(OpenGl_VertexBuffer)& aTCrdsVbo = theTCrdsPerTexture.ChangeValue (aTextureIter);
175     if (!aTCrdsVbo->Init (theCtx, 2, aVerts.Length(), (GLfloat* )NULL)
176      || !myVboEditor.Init (theCtx, aTCrdsVbo))
177     {
178       continue;
179     }
180     for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter, myVboEditor.Next())
181     {
182       myVboEditor.Value() = aTCrds.Value (aVertIter);
183     }
184     myVboEditor.Flush();
185   }
186   myVboEditor.Init (NULL, NULL);
187 }