317d68c9 |
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 | |
d2eddacc |
19 | #include <Font_FTFont.hxx> |
20 | |
317d68c9 |
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 | |
20aeeb7b |
60 | OpenGl_Font::Tile aTile = {Font_Rect(), Font_Rect(), 0u}; |
317d68c9 |
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; |
d2eddacc |
86 | aPen.x() += theFont.FTFont()->AdvanceX (' ', aCharNext); |
317d68c9 |
87 | continue; |
88 | } |
89 | else if (aCharThis == '\t') |
90 | { |
91 | const Standard_Integer aSpacesNum = (theFormatter.TabSize() - (aSymbolsCounter - 1) % theFormatter.TabSize()); |
d2eddacc |
92 | aPen.x() += theFont.FTFont()->AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum); |
317d68c9 |
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(); |
d2eddacc |
106 | const Font_Rect& aRectUV = aTile.uv; |
107 | const GLuint aTexture = aTile.texture; |
317d68c9 |
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 | } |