Commit | Line | Data |
---|---|---|
b311480e | 1 | // Created on: 2011-07-13 |
2 | // Created by: Sergey ZERCHANINOV | |
a174a3c5 | 3 | // Copyright (c) 2011-2013 OPEN CASCADE SAS |
b311480e | 4 | // |
973c2be1 | 5 | // This file is part of Open CASCADE Technology software library. |
b311480e | 6 | // |
d5f74e42 | 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 | |
973c2be1 | 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. | |
b311480e | 12 | // |
973c2be1 | 13 | // Alternatively, this file may be used under the terms of Open CASCADE |
14 | // commercial license or contractual agreement. | |
b311480e | 15 | |
bf5f0ca2 | 16 | #include <OpenGl_Aspects.hxx> |
30f0ad28 | 17 | #include <OpenGl_GlCore11.hxx> |
a174a3c5 | 18 | #include <OpenGl_GraphicDriver.hxx> |
30f0ad28 | 19 | #include <OpenGl_ShaderManager.hxx> |
20 | #include <OpenGl_ShaderProgram.hxx> | |
21 | #include <OpenGl_ShaderStates.hxx> | |
22 | #include <OpenGl_Text.hxx> | |
bf75be98 | 23 | #include <OpenGl_Workspace.hxx> |
ce01ec26 | 24 | #include <OpenGl_View.hxx> |
048e1b3b | 25 | #include <OpenGl_VertexBufferCompat.hxx> |
2166f0fa | 26 | |
a174a3c5 | 27 | #include <Font_FontMgr.hxx> |
d2eddacc | 28 | #include <Font_FTFont.hxx> |
825aa485 | 29 | #include <Graphic3d_TransformUtils.hxx> |
a174a3c5 | 30 | #include <TCollection_HAsciiString.hxx> |
31 | ||
a174a3c5 | 32 | namespace |
2166f0fa | 33 | { |
c827ea3a | 34 | static const GLdouble THE_IDENTITY_MATRIX[16] = |
a174a3c5 | 35 | { |
c827ea3a | 36 | 1.0, 0.0, 0.0, 0.0, |
37 | 0.0, 1.0, 0.0, 0.0, | |
38 | 0.0, 0.0, 1.0, 0.0, | |
39 | 0.0, 0.0, 0.0, 1.0 | |
a174a3c5 | 40 | }; |
41 | ||
bf5f0ca2 | 42 | static const TCollection_AsciiString THE_DEFAULT_FONT (Font_NOF_ASCII_MONO); |
43 | ||
8d1a539c | 44 | //! Auxiliary tool for setting polygon offset temporarily. |
45 | struct BackPolygonOffsetSentry | |
46 | { | |
47 | BackPolygonOffsetSentry (const Handle(OpenGl_Context)& theCtx) | |
48 | : myCtx (theCtx), | |
49 | myOffsetBack (!theCtx.IsNull() ? theCtx->PolygonOffset() : Graphic3d_PolygonOffset()) | |
50 | { | |
51 | if (!theCtx.IsNull()) | |
52 | { | |
53 | Graphic3d_PolygonOffset aPolyOffset = myOffsetBack; | |
54 | aPolyOffset.Mode = Aspect_POM_Fill; | |
55 | aPolyOffset.Units += 1.0f; | |
56 | theCtx->SetPolygonOffset (aPolyOffset); | |
57 | } | |
58 | } | |
59 | ||
60 | ~BackPolygonOffsetSentry() | |
61 | { | |
62 | if (!myCtx.IsNull()) | |
63 | { | |
64 | myCtx->SetPolygonOffset (myOffsetBack); | |
65 | } | |
66 | } | |
67 | ||
68 | private: | |
69 | BackPolygonOffsetSentry (const BackPolygonOffsetSentry& ); | |
70 | BackPolygonOffsetSentry& operator= (const BackPolygonOffsetSentry& ); | |
71 | private: | |
72 | const Handle(OpenGl_Context)& myCtx; | |
73 | const Graphic3d_PolygonOffset myOffsetBack; | |
74 | }; | |
75 | ||
68858c7d | 76 | } // anonymous namespace |
a174a3c5 | 77 | |
78 | // ======================================================================= | |
79 | // function : OpenGl_Text | |
80 | // purpose : | |
81 | // ======================================================================= | |
82 | OpenGl_Text::OpenGl_Text() | |
83 | : myWinX (0.0f), | |
84 | myWinY (0.0f), | |
85 | myWinZ (0.0f), | |
86 | myScaleHeight (1.0f), | |
87 | myPoint (0.0f, 0.0f, 0.0f), | |
ce01ec26 | 88 | myIs2d (false), |
3f1eb0ab | 89 | myHasPlane (false), |
90 | myHasAnchorPoint (true) | |
a174a3c5 | 91 | { |
92 | myParams.Height = 10; | |
93 | myParams.HAlign = Graphic3d_HTA_LEFT; | |
94 | myParams.VAlign = Graphic3d_VTA_BOTTOM; | |
2166f0fa SK |
95 | } |
96 | ||
a174a3c5 | 97 | // ======================================================================= |
98 | // function : OpenGl_Text | |
99 | // purpose : | |
100 | // ======================================================================= | |
b64d84be | 101 | OpenGl_Text::OpenGl_Text (const Standard_Utf8Char* theText, |
102 | const OpenGl_Vec3& thePoint, | |
103 | const OpenGl_TextParam& theParams) | |
a174a3c5 | 104 | : myWinX (0.0f), |
105 | myWinY (0.0f), | |
106 | myWinZ (0.0f), | |
107 | myScaleHeight (1.0f), | |
108 | myExportHeight (1.0f), | |
109 | myParams (theParams), | |
b64d84be | 110 | myString (theText), |
a174a3c5 | 111 | myPoint (thePoint), |
ce01ec26 | 112 | myIs2d (false), |
3f1eb0ab | 113 | myHasPlane (false), |
114 | myHasAnchorPoint (true) | |
a174a3c5 | 115 | { |
116 | // | |
117 | } | |
2166f0fa | 118 | |
ce01ec26 | 119 | // ======================================================================= |
120 | // function : OpenGl_Text | |
121 | // purpose : | |
122 | // ======================================================================= | |
123 | OpenGl_Text::OpenGl_Text (const Standard_Utf8Char* theText, | |
124 | const gp_Ax2& theOrientation, | |
3f1eb0ab | 125 | const OpenGl_TextParam& theParams, |
126 | const bool theHasOwnAnchor) | |
ce01ec26 | 127 | : myWinX (0.0), |
128 | myWinY (0.0), | |
129 | myWinZ (0.0), | |
130 | myScaleHeight (1.0), | |
131 | myExportHeight (1.0), | |
132 | myParams (theParams), | |
133 | myString (theText), | |
134 | myIs2d (false), | |
135 | myOrientation (theOrientation), | |
3f1eb0ab | 136 | myHasPlane (true), |
137 | myHasAnchorPoint (theHasOwnAnchor) | |
ce01ec26 | 138 | { |
139 | const gp_Pnt& aPoint = theOrientation.Location(); | |
140 | myPoint = OpenGl_Vec3 (static_cast<Standard_ShortReal> (aPoint.X()), | |
141 | static_cast<Standard_ShortReal> (aPoint.Y()), | |
142 | static_cast<Standard_ShortReal> (aPoint.Z())); | |
143 | } | |
144 | ||
a174a3c5 | 145 | // ======================================================================= |
146 | // function : SetPosition | |
147 | // purpose : | |
148 | // ======================================================================= | |
149 | void OpenGl_Text::SetPosition (const OpenGl_Vec3& thePoint) | |
2166f0fa | 150 | { |
a174a3c5 | 151 | myPoint = thePoint; |
2166f0fa SK |
152 | } |
153 | ||
a174a3c5 | 154 | // ======================================================================= |
155 | // function : SetFontSize | |
156 | // purpose : | |
157 | // ======================================================================= | |
158 | void OpenGl_Text::SetFontSize (const Handle(OpenGl_Context)& theCtx, | |
159 | const Standard_Integer theFontSize) | |
160 | { | |
161 | if (myParams.Height != theFontSize) | |
162 | { | |
10b9c7df | 163 | Release (theCtx.operator->()); |
a174a3c5 | 164 | } |
165 | myParams.Height = theFontSize; | |
166 | } | |
167 | ||
168 | // ======================================================================= | |
169 | // function : Init | |
170 | // purpose : | |
171 | // ======================================================================= | |
172 | void OpenGl_Text::Init (const Handle(OpenGl_Context)& theCtx, | |
173 | const Standard_Utf8Char* theText, | |
174 | const OpenGl_Vec3& thePoint) | |
175 | { | |
10b9c7df | 176 | releaseVbos (theCtx.operator->()); |
a174a3c5 | 177 | myIs2d = false; |
178 | myPoint = thePoint; | |
179 | myString.FromUnicode (theText); | |
180 | } | |
181 | ||
182 | // ======================================================================= | |
183 | // function : Init | |
184 | // purpose : | |
185 | // ======================================================================= | |
186 | void OpenGl_Text::Init (const Handle(OpenGl_Context)& theCtx, | |
187 | const Standard_Utf8Char* theText, | |
188 | const OpenGl_Vec3& thePoint, | |
189 | const OpenGl_TextParam& theParams) | |
190 | { | |
191 | if (myParams.Height != theParams.Height) | |
192 | { | |
10b9c7df | 193 | Release (theCtx.operator->()); |
a174a3c5 | 194 | } |
195 | else | |
196 | { | |
10b9c7df | 197 | releaseVbos (theCtx.operator->()); |
a174a3c5 | 198 | } |
199 | myIs2d = false; | |
200 | myParams = theParams; | |
201 | myPoint = thePoint; | |
202 | myString.FromUnicode (theText); | |
203 | } | |
2166f0fa | 204 | |
a174a3c5 | 205 | // ======================================================================= |
206 | // function : Init | |
207 | // purpose : | |
208 | // ======================================================================= | |
209 | void OpenGl_Text::Init (const Handle(OpenGl_Context)& theCtx, | |
210 | const TCollection_ExtendedString& theText, | |
211 | const OpenGl_Vec2& thePoint, | |
212 | const OpenGl_TextParam& theParams) | |
2166f0fa | 213 | { |
a174a3c5 | 214 | if (myParams.Height != theParams.Height) |
215 | { | |
10b9c7df | 216 | Release (theCtx.operator->()); |
a174a3c5 | 217 | } |
218 | else | |
219 | { | |
10b9c7df | 220 | releaseVbos (theCtx.operator->()); |
a174a3c5 | 221 | } |
222 | myIs2d = true; | |
223 | myParams = theParams; | |
bc379358 | 224 | myPoint.SetValues (thePoint, 0.0f); |
fb0b0531 | 225 | myString.FromUnicode (theText.ToExtString()); |
a174a3c5 | 226 | } |
227 | ||
228 | // ======================================================================= | |
229 | // function : ~OpenGl_Text | |
230 | // purpose : | |
231 | // ======================================================================= | |
232 | OpenGl_Text::~OpenGl_Text() | |
233 | { | |
234 | // | |
235 | } | |
236 | ||
237 | // ======================================================================= | |
238 | // function : releaseVbos | |
239 | // purpose : | |
240 | // ======================================================================= | |
10b9c7df | 241 | void OpenGl_Text::releaseVbos (OpenGl_Context* theCtx) |
a174a3c5 | 242 | { |
243 | for (Standard_Integer anIter = 0; anIter < myVertsVbo.Length(); ++anIter) | |
244 | { | |
245 | Handle(OpenGl_VertexBuffer)& aVerts = myVertsVbo.ChangeValue (anIter); | |
246 | Handle(OpenGl_VertexBuffer)& aTCrds = myTCrdsVbo.ChangeValue (anIter); | |
247 | ||
6fe58c66 | 248 | if (theCtx != NULL) |
a174a3c5 | 249 | { |
250 | theCtx->DelayedRelease (aVerts); | |
251 | theCtx->DelayedRelease (aTCrds); | |
252 | } | |
253 | aVerts.Nullify(); | |
254 | aTCrds.Nullify(); | |
255 | } | |
6fe58c66 | 256 | if (theCtx != NULL |
257 | && !myBndVertsVbo.IsNull()) | |
258 | { | |
259 | theCtx->DelayedRelease (myBndVertsVbo); | |
260 | } | |
261 | ||
a174a3c5 | 262 | myTextures.Clear(); |
263 | myVertsVbo.Clear(); | |
264 | myTCrdsVbo.Clear(); | |
6fe58c66 | 265 | myBndVertsVbo.Nullify(); |
a174a3c5 | 266 | } |
267 | ||
268 | // ======================================================================= | |
269 | // function : Release | |
270 | // purpose : | |
271 | // ======================================================================= | |
10b9c7df | 272 | void OpenGl_Text::Release (OpenGl_Context* theCtx) |
a174a3c5 | 273 | { |
274 | releaseVbos (theCtx); | |
275 | if (!myFont.IsNull()) | |
276 | { | |
a174a3c5 | 277 | const TCollection_AsciiString aKey = myFont->ResourceKey(); |
278 | myFont.Nullify(); | |
6fe58c66 | 279 | if (theCtx != NULL) |
280 | { | |
281 | theCtx->ReleaseResource (aKey, Standard_True); | |
282 | } | |
a174a3c5 | 283 | } |
284 | } | |
285 | ||
286 | // ======================================================================= | |
287 | // function : StringSize | |
288 | // purpose : | |
289 | // ======================================================================= | |
290 | void OpenGl_Text::StringSize (const Handle(OpenGl_Context)& theCtx, | |
291 | const NCollection_String& theText, | |
bf5f0ca2 | 292 | const OpenGl_Aspects& theTextAspect, |
a174a3c5 | 293 | const OpenGl_TextParam& theParams, |
4b1c8733 | 294 | const unsigned int theResolution, |
a174a3c5 | 295 | Standard_ShortReal& theWidth, |
296 | Standard_ShortReal& theAscent, | |
297 | Standard_ShortReal& theDescent) | |
298 | { | |
299 | theWidth = 0.0f; | |
300 | theAscent = 0.0f; | |
301 | theDescent = 0.0f; | |
4b1c8733 | 302 | const TCollection_AsciiString aFontKey = FontKey (theTextAspect, theParams.Height, theResolution); |
303 | Handle(OpenGl_Font) aFont = FindFont (theCtx, theTextAspect, theParams.Height, theResolution, aFontKey); | |
a174a3c5 | 304 | if (aFont.IsNull() || !aFont->IsValid()) |
305 | { | |
2166f0fa | 306 | return; |
a174a3c5 | 307 | } |
308 | ||
309 | theAscent = aFont->Ascender(); | |
310 | theDescent = aFont->Descender(); | |
311 | ||
312 | GLfloat aWidth = 0.0f; | |
313 | for (NCollection_Utf8Iter anIter = theText.Iterator(); *anIter != 0;) | |
314 | { | |
315 | const Standard_Utf32Char aCharThis = *anIter; | |
316 | const Standard_Utf32Char aCharNext = *++anIter; | |
317 | ||
318 | if (aCharThis == '\x0D' // CR (carriage return) | |
319 | || aCharThis == '\a' // BEL (alarm) | |
320 | || aCharThis == '\f' // FF (form feed) NP (new page) | |
321 | || aCharThis == '\b' // BS (backspace) | |
322 | || aCharThis == '\v') // VT (vertical tab) | |
323 | { | |
324 | continue; // skip unsupported carriage control codes | |
325 | } | |
326 | else if (aCharThis == '\x0A') // LF (line feed, new line) | |
327 | { | |
328 | theWidth = Max (theWidth, aWidth); | |
329 | aWidth = 0.0f; | |
330 | continue; | |
331 | } | |
332 | else if (aCharThis == ' ') | |
333 | { | |
d2eddacc | 334 | aWidth += aFont->FTFont()->AdvanceX (aCharThis, aCharNext); |
a174a3c5 | 335 | continue; |
336 | } | |
337 | else if (aCharThis == '\t') | |
338 | { | |
d2eddacc | 339 | aWidth += aFont->FTFont()->AdvanceX (' ', aCharNext) * 8.0f; |
a174a3c5 | 340 | continue; |
341 | } | |
342 | ||
d2eddacc | 343 | aWidth += aFont->FTFont()->AdvanceX (aCharThis, aCharNext); |
a174a3c5 | 344 | } |
345 | theWidth = Max (theWidth, aWidth); | |
346 | ||
347 | Handle(OpenGl_Context) aCtx = theCtx; | |
348 | aFont.Nullify(); | |
349 | aCtx->ReleaseResource (aFontKey, Standard_True); | |
350 | } | |
351 | ||
352 | // ======================================================================= | |
353 | // function : Render | |
354 | // purpose : | |
355 | // ======================================================================= | |
356 | void OpenGl_Text::Render (const Handle(OpenGl_Workspace)& theWorkspace) const | |
357 | { | |
bf5f0ca2 | 358 | const OpenGl_Aspects* aTextAspect = theWorkspace->ApplyAspects(); |
359 | const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext(); | |
cc8cbabe | 360 | const Handle(OpenGl_TextureSet) aPrevTexture = aCtx->BindTextures (Handle(OpenGl_TextureSet)()); |
8d1a539c | 361 | |
b990e557 | 362 | // Bind custom shader program or generate default version |
8613985b | 363 | aCtx->ShaderManager()->BindFontProgram (aTextAspect->ShaderProgramRes (aCtx)); |
30f0ad28 | 364 | |
c357e426 | 365 | myOrientationMatrix = theWorkspace->View()->Camera()->OrientationMatrix(); |
ce01ec26 | 366 | myProjMatrix.Convert (aCtx->ProjectionState.Current()); |
367 | ||
a174a3c5 | 368 | // use highlight color or colors from aspect |
60273f77 | 369 | render (aCtx, |
f9ba5c4d | 370 | *aTextAspect, |
371 | theWorkspace->TextColor(), | |
372 | theWorkspace->TextSubtitleColor(), | |
56689b27 | 373 | aCtx->Resolution()); |
2166f0fa | 374 | |
a174a3c5 | 375 | // restore aspects |
376 | if (!aPrevTexture.IsNull()) | |
377 | { | |
cc8cbabe | 378 | aCtx->BindTextures (aPrevTexture); |
a174a3c5 | 379 | } |
b34efb62 | 380 | |
381 | // restore Z buffer settings | |
eae454e3 | 382 | if (theWorkspace->UseZBuffer()) |
b34efb62 | 383 | { |
384 | glEnable (GL_DEPTH_TEST); | |
385 | } | |
a174a3c5 | 386 | } |
2166f0fa | 387 | |
a174a3c5 | 388 | // ======================================================================= |
389 | // function : Render | |
390 | // purpose : | |
391 | // ======================================================================= | |
60273f77 | 392 | void OpenGl_Text::Render (const Handle(OpenGl_Context)& theCtx, |
bf5f0ca2 | 393 | const OpenGl_Aspects& theTextAspect, |
394 | unsigned int theResolution) const | |
a174a3c5 | 395 | { |
2a332745 | 396 | #if !defined(GL_ES_VERSION_2_0) |
397 | const Standard_Integer aPrevPolygonMode = theCtx->SetPolygonMode (GL_FILL); | |
398 | const bool aPrevHatchingMode = theCtx->SetPolygonHatchEnabled (false); | |
399 | #endif | |
400 | ||
60273f77 | 401 | render (theCtx, theTextAspect, |
b6472664 | 402 | theTextAspect.Aspect()->ColorRGBA(), |
403 | theTextAspect.Aspect()->ColorSubTitleRGBA(), | |
404 | theResolution); | |
2a332745 | 405 | |
406 | #if !defined(GL_ES_VERSION_2_0) | |
407 | theCtx->SetPolygonMode (aPrevPolygonMode); | |
408 | theCtx->SetPolygonHatchEnabled (aPrevHatchingMode); | |
409 | #endif | |
a174a3c5 | 410 | } |
2166f0fa | 411 | |
a174a3c5 | 412 | // ======================================================================= |
413 | // function : setupMatrix | |
414 | // purpose : | |
415 | // ======================================================================= | |
60273f77 | 416 | void OpenGl_Text::setupMatrix (const Handle(OpenGl_Context)& theCtx, |
bf5f0ca2 | 417 | const OpenGl_Aspects& theTextAspect, |
418 | const OpenGl_Vec3& theDVec) const | |
a174a3c5 | 419 | { |
c827ea3a | 420 | OpenGl_Mat4d aModViewMat; |
ce01ec26 | 421 | OpenGl_Mat4d aProjectMat; |
3f1eb0ab | 422 | if (myHasPlane && myHasAnchorPoint) |
ce01ec26 | 423 | { |
424 | aProjectMat = myProjMatrix * myOrientationMatrix; | |
425 | } | |
426 | else | |
427 | { | |
428 | aProjectMat = myProjMatrix; | |
429 | } | |
c827ea3a | 430 | |
a174a3c5 | 431 | if (myIs2d) |
bf75be98 | 432 | { |
825aa485 | 433 | Graphic3d_TransformUtils::Translate<GLdouble> (aModViewMat, myPoint.x() + theDVec.x(), myPoint.y() + theDVec.y(), 0.f); |
434 | Graphic3d_TransformUtils::Scale<GLdouble> (aModViewMat, 1.f, -1.f, 1.f); | |
bf5f0ca2 | 435 | Graphic3d_TransformUtils::Rotate<GLdouble> (aModViewMat, theTextAspect.Aspect()->TextAngle(), 0.f, 0.f, 1.f); |
2166f0fa SK |
436 | } |
437 | else | |
438 | { | |
a174a3c5 | 439 | // align coordinates to the nearest integer |
440 | // to avoid extra interpolation issues | |
441 | GLdouble anObjX, anObjY, anObjZ; | |
825aa485 | 442 | Graphic3d_TransformUtils::UnProject<Standard_Real> (std::floor (myWinX + theDVec.x()), |
443 | std::floor (myWinY + theDVec.y()), | |
444 | myWinZ + theDVec.z(), | |
445 | OpenGl_Mat4d::Map (THE_IDENTITY_MATRIX), | |
ce01ec26 | 446 | OpenGl_Mat4d::Map (aProjectMat), |
3bffef55 | 447 | theCtx->Viewport(), |
825aa485 | 448 | anObjX, |
449 | anObjY, | |
450 | anObjZ); | |
451 | ||
ce01ec26 | 452 | if (myHasPlane) |
453 | { | |
454 | const gp_Dir& aVectorDir = myOrientation.XDirection(); | |
455 | const gp_Dir& aVectorUp = myOrientation.Direction(); | |
456 | const gp_Dir& aVectorRight = myOrientation.YDirection(); | |
457 | ||
ce01ec26 | 458 | aModViewMat.SetColumn (2, OpenGl_Vec3d (aVectorUp.X(), aVectorUp.Y(), aVectorUp.Z())); |
459 | aModViewMat.SetColumn (1, OpenGl_Vec3d (aVectorRight.X(), aVectorRight.Y(), aVectorRight.Z())); | |
460 | aModViewMat.SetColumn (0, OpenGl_Vec3d (aVectorDir.X(), aVectorDir.Y(), aVectorDir.Z())); | |
3f1eb0ab | 461 | |
462 | if (!myHasAnchorPoint) | |
463 | { | |
464 | OpenGl_Mat4d aPosMat; | |
465 | aPosMat.SetColumn (3, OpenGl_Vec3d (myPoint.x(), myPoint.y(), myPoint.z())); | |
466 | aPosMat *= aModViewMat; | |
467 | aModViewMat.SetColumn (3, aPosMat.GetColumn (3)); | |
468 | } | |
469 | else | |
470 | { | |
471 | aModViewMat.SetColumn (3, OpenGl_Vec3d (anObjX, anObjY, anObjZ)); | |
472 | } | |
ce01ec26 | 473 | } |
474 | else | |
475 | { | |
476 | Graphic3d_TransformUtils::Translate<GLdouble> (aModViewMat, anObjX, anObjY, anObjZ); | |
bf5f0ca2 | 477 | Graphic3d_TransformUtils::Rotate<GLdouble> (aModViewMat, theTextAspect.Aspect()->TextAngle(), 0.0, 0.0, 1.0); |
ce01ec26 | 478 | } |
825aa485 | 479 | |
bf5f0ca2 | 480 | if (!theTextAspect.Aspect()->IsTextZoomable()) |
a174a3c5 | 481 | { |
825aa485 | 482 | Graphic3d_TransformUtils::Scale<GLdouble> (aModViewMat, myScaleHeight, myScaleHeight, myScaleHeight); |
a174a3c5 | 483 | } |
56689b27 | 484 | else if (theCtx->HasRenderScale()) |
485 | { | |
486 | Graphic3d_TransformUtils::Scale<GLdouble> (aModViewMat, theCtx->RenderScaleInv(), theCtx->RenderScaleInv(), theCtx->RenderScaleInv()); | |
487 | } | |
a174a3c5 | 488 | } |
c827ea3a | 489 | |
3f1eb0ab | 490 | if (myHasPlane && !myHasAnchorPoint) |
491 | { | |
492 | OpenGl_Mat4d aCurrentWorldViewMat; | |
493 | aCurrentWorldViewMat.Convert (theCtx->WorldViewState.Current()); | |
494 | theCtx->WorldViewState.SetCurrent<Standard_Real> (aCurrentWorldViewMat * aModViewMat); | |
495 | } | |
496 | else | |
497 | { | |
498 | theCtx->WorldViewState.SetCurrent<Standard_Real> (aModViewMat); | |
499 | } | |
c827ea3a | 500 | theCtx->ApplyWorldViewMatrix(); |
b990e557 | 501 | |
ce01ec26 | 502 | if (!myIs2d) |
503 | { | |
504 | theCtx->ProjectionState.SetCurrent<Standard_Real> (aProjectMat); | |
505 | theCtx->ApplyProjectionMatrix(); | |
506 | } | |
507 | ||
8613985b | 508 | // Upload updated state to shader program |
509 | theCtx->ShaderManager()->PushState (theCtx->ActiveProgram()); | |
a174a3c5 | 510 | } |
511 | ||
512 | // ======================================================================= | |
513 | // function : drawText | |
514 | // purpose : | |
515 | // ======================================================================= | |
60273f77 | 516 | void OpenGl_Text::drawText (const Handle(OpenGl_Context)& theCtx, |
bf5f0ca2 | 517 | const OpenGl_Aspects& theTextAspect) const |
a174a3c5 | 518 | { |
60273f77 | 519 | (void )theTextAspect; |
7d3e64ef | 520 | if (myVertsVbo.Length() != myTextures.Length() |
521 | || myTextures.IsEmpty()) | |
2166f0fa | 522 | { |
7d3e64ef | 523 | return; |
2166f0fa | 524 | } |
7d3e64ef | 525 | |
526 | for (Standard_Integer anIter = 0; anIter < myTextures.Length(); ++anIter) | |
a174a3c5 | 527 | { |
7d3e64ef | 528 | const GLuint aTexId = myTextures.Value (anIter); |
529 | glBindTexture (GL_TEXTURE_2D, aTexId); | |
a174a3c5 | 530 | |
7d3e64ef | 531 | const Handle(OpenGl_VertexBuffer)& aVerts = myVertsVbo.Value (anIter); |
532 | const Handle(OpenGl_VertexBuffer)& aTCrds = myTCrdsVbo.Value (anIter); | |
533 | aVerts->BindAttribute (theCtx, Graphic3d_TOA_POS); | |
534 | aTCrds->BindAttribute (theCtx, Graphic3d_TOA_UV); | |
2166f0fa | 535 | |
7d3e64ef | 536 | glDrawArrays (GL_TRIANGLES, 0, GLsizei(aVerts->GetElemsNb())); |
2166f0fa | 537 | |
b990e557 | 538 | aTCrds->UnbindAttribute (theCtx, Graphic3d_TOA_UV); |
7d3e64ef | 539 | aVerts->UnbindAttribute (theCtx, Graphic3d_TOA_POS); |
a174a3c5 | 540 | } |
7d3e64ef | 541 | glBindTexture (GL_TEXTURE_2D, 0); |
a174a3c5 | 542 | } |
2166f0fa | 543 | |
a174a3c5 | 544 | // ======================================================================= |
545 | // function : FontKey | |
546 | // purpose : | |
547 | // ======================================================================= | |
bf5f0ca2 | 548 | TCollection_AsciiString OpenGl_Text::FontKey (const OpenGl_Aspects& theAspect, |
549 | Standard_Integer theHeight, | |
550 | unsigned int theResolution) | |
a174a3c5 | 551 | { |
bf5f0ca2 | 552 | const Font_FontAspect anAspect = theAspect.Aspect()->TextFontAspect() != Font_FA_Undefined |
553 | ? theAspect.Aspect()->TextFontAspect() | |
b6472664 | 554 | : Font_FA_Regular; |
bf5f0ca2 | 555 | const TCollection_AsciiString& aFont = !theAspect.Aspect()->TextFont().IsNull() ? theAspect.Aspect()->TextFont()->String() : THE_DEFAULT_FONT; |
556 | return aFont | |
a174a3c5 | 557 | + TCollection_AsciiString(":") + Standard_Integer(anAspect) |
4b1c8733 | 558 | + TCollection_AsciiString(":") + Standard_Integer(theResolution) |
a174a3c5 | 559 | + TCollection_AsciiString(":") + theHeight; |
560 | } | |
561 | ||
562 | // ======================================================================= | |
563 | // function : FindFont | |
564 | // purpose : | |
565 | // ======================================================================= | |
566 | Handle(OpenGl_Font) OpenGl_Text::FindFont (const Handle(OpenGl_Context)& theCtx, | |
bf5f0ca2 | 567 | const OpenGl_Aspects& theAspect, |
568 | Standard_Integer theHeight, | |
569 | unsigned int theResolution, | |
570 | const TCollection_AsciiString& theKey) | |
a174a3c5 | 571 | { |
572 | Handle(OpenGl_Font) aFont; | |
573 | if (theHeight < 2) | |
2166f0fa | 574 | { |
a174a3c5 | 575 | return aFont; // invalid parameters |
576 | } | |
2166f0fa | 577 | |
a174a3c5 | 578 | if (!theCtx->GetResource (theKey, aFont)) |
579 | { | |
580 | Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance(); | |
bf5f0ca2 | 581 | const TCollection_AsciiString& aFontName = !theAspect.Aspect()->TextFont().IsNull() |
582 | ? theAspect.Aspect()->TextFont()->String() | |
583 | : THE_DEFAULT_FONT; | |
584 | Font_FontAspect anAspect = theAspect.Aspect()->TextFontAspect() != Font_FA_Undefined | |
585 | ? theAspect.Aspect()->TextFontAspect() | |
5b377041 | 586 | : Font_FA_Regular; |
1bbd7c79 | 587 | Font_FTFontParams aParams; |
588 | aParams.PointSize = theHeight; | |
589 | aParams.Resolution = theResolution; | |
590 | if (Handle(Font_FTFont) aFontFt = Font_FTFont::FindAndCreate (aFontName, anAspect, aParams, Font_StrictLevel_Any)) | |
2166f0fa | 591 | { |
1bbd7c79 | 592 | aFont = new OpenGl_Font (aFontFt, theKey); |
593 | if (!aFont->Init (theCtx)) | |
65360da3 | 594 | { |
1bbd7c79 | 595 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
596 | TCollection_AsciiString ("Font '") + aFontName + "' - initialization of GL resources has failed!"); | |
65360da3 | 597 | aFontFt.Nullify(); |
1bbd7c79 | 598 | aFont->Release (theCtx.get()); |
65360da3 | 599 | aFont = new OpenGl_Font (aFontFt, theKey); |
600 | } | |
a174a3c5 | 601 | } |
65360da3 | 602 | else |
a174a3c5 | 603 | { |
1bbd7c79 | 604 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
605 | TCollection_AsciiString ("Font '") + aFontName + "' is not found in the system!"); | |
65360da3 | 606 | aFont = new OpenGl_Font (aFontFt, theKey); |
a174a3c5 | 607 | } |
a174a3c5 | 608 | |
b34efb62 | 609 | theCtx->ShareResource (theKey, aFont); |
a174a3c5 | 610 | } |
611 | return aFont; | |
612 | } | |
613 | ||
6fe58c66 | 614 | // ======================================================================= |
615 | // function : drawRect | |
616 | // purpose : | |
617 | // ======================================================================= | |
618 | void OpenGl_Text::drawRect (const Handle(OpenGl_Context)& theCtx, | |
bf5f0ca2 | 619 | const OpenGl_Aspects& theTextAspect, |
620 | const OpenGl_Vec4& theColorSubs) const | |
6fe58c66 | 621 | { |
622 | Handle(OpenGl_ShaderProgram) aPrevProgram = theCtx->ActiveProgram(); | |
623 | if (myBndVertsVbo.IsNull()) | |
624 | { | |
625 | OpenGl_Vec2 aQuad[4] = | |
626 | { | |
627 | OpenGl_Vec2(myBndBox.Right, myBndBox.Bottom), | |
628 | OpenGl_Vec2(myBndBox.Right, myBndBox.Top), | |
629 | OpenGl_Vec2(myBndBox.Left, myBndBox.Bottom), | |
630 | OpenGl_Vec2(myBndBox.Left, myBndBox.Top) | |
631 | }; | |
048e1b3b | 632 | if (theCtx->ToUseVbo()) |
633 | { | |
634 | myBndVertsVbo = new OpenGl_VertexBuffer(); | |
635 | } | |
636 | else | |
637 | { | |
638 | myBndVertsVbo = new OpenGl_VertexBufferCompat(); | |
639 | } | |
6fe58c66 | 640 | myBndVertsVbo->Init (theCtx, 2, 4, aQuad[0].GetData()); |
641 | } | |
642 | ||
c40eb6b9 | 643 | // bind unlit program |
644 | theCtx->ShaderManager()->BindFaceProgram (Handle(OpenGl_TextureSet)(), Graphic3d_TOSM_UNLIT, | |
645 | Graphic3d_AlphaMode_Opaque, Standard_False, Standard_False, | |
646 | Handle(OpenGl_ShaderProgram)()); | |
8613985b | 647 | |
6fe58c66 | 648 | #if !defined(GL_ES_VERSION_2_0) |
649 | if (theCtx->core11 != NULL | |
650 | && theCtx->ActiveProgram().IsNull()) | |
651 | { | |
652 | glBindTexture (GL_TEXTURE_2D, 0); | |
653 | } | |
654 | #endif | |
655 | theCtx->SetColor4fv (theColorSubs); | |
8d1a539c | 656 | setupMatrix (theCtx, theTextAspect, OpenGl_Vec3 (0.0f, 0.0f, 0.0f)); |
6fe58c66 | 657 | myBndVertsVbo->BindAttribute (theCtx, Graphic3d_TOA_POS); |
658 | ||
659 | theCtx->core20fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); | |
660 | ||
661 | myBndVertsVbo->UnbindAttribute (theCtx, Graphic3d_TOA_POS); | |
662 | theCtx->BindProgram (aPrevProgram); | |
663 | } | |
664 | ||
a174a3c5 | 665 | // ======================================================================= |
666 | // function : render | |
667 | // purpose : | |
668 | // ======================================================================= | |
60273f77 | 669 | void OpenGl_Text::render (const Handle(OpenGl_Context)& theCtx, |
bf5f0ca2 | 670 | const OpenGl_Aspects& theTextAspect, |
671 | const OpenGl_Vec4& theColorText, | |
672 | const OpenGl_Vec4& theColorSubs, | |
673 | unsigned int theResolution) const | |
a174a3c5 | 674 | { |
675 | if (myString.IsEmpty()) | |
676 | { | |
677 | return; | |
678 | } | |
679 | ||
4b1c8733 | 680 | // Note that using difference resolution in different Views in same Viewer |
681 | // will lead to performance regression (for example, text will be recreated every time). | |
682 | const TCollection_AsciiString aFontKey = FontKey (theTextAspect, myParams.Height, theResolution); | |
a174a3c5 | 683 | if (!myFont.IsNull() |
684 | && !myFont->ResourceKey().IsEqual (aFontKey)) | |
685 | { | |
686 | // font changed | |
10b9c7df | 687 | const_cast<OpenGl_Text* > (this)->Release (theCtx.operator->()); |
a174a3c5 | 688 | } |
689 | ||
690 | if (myFont.IsNull()) | |
691 | { | |
4b1c8733 | 692 | myFont = FindFont (theCtx, theTextAspect, myParams.Height, theResolution, aFontKey); |
65360da3 | 693 | } |
694 | if (!myFont->WasInitialized()) | |
695 | { | |
696 | return; | |
a174a3c5 | 697 | } |
698 | ||
699 | if (myTextures.IsEmpty()) | |
700 | { | |
317d68c9 | 701 | Font_TextFormatter aFormatter; |
a174a3c5 | 702 | aFormatter.SetupAlignment (myParams.HAlign, myParams.VAlign); |
703 | aFormatter.Reset(); | |
317d68c9 | 704 | |
d2eddacc | 705 | aFormatter.Append (myString, *myFont->FTFont().operator->()); |
a174a3c5 | 706 | aFormatter.Format(); |
707 | ||
317d68c9 | 708 | OpenGl_TextBuilder aBuilder; |
709 | aBuilder.Perform (aFormatter, | |
710 | theCtx, | |
711 | *myFont.operator->(), | |
712 | myTextures, | |
713 | myVertsVbo, | |
714 | myTCrdsVbo); | |
715 | ||
a174a3c5 | 716 | aFormatter.BndBox (myBndBox); |
6fe58c66 | 717 | if (!myBndVertsVbo.IsNull()) |
718 | { | |
719 | myBndVertsVbo->Release (theCtx.get()); | |
720 | myBndVertsVbo.Nullify(); | |
721 | } | |
a174a3c5 | 722 | } |
723 | ||
724 | if (myTextures.IsEmpty()) | |
725 | { | |
726 | return; | |
727 | } | |
728 | ||
729 | myExportHeight = 1.0f; | |
730 | myScaleHeight = 1.0f; | |
731 | ||
56689b27 | 732 | theCtx->WorldViewState.Push(); |
c827ea3a | 733 | myModelMatrix.Convert (theCtx->WorldViewState.Current() * theCtx->ModelWorldState.Current()); |
734 | ||
56689b27 | 735 | const GLdouble aPointSize = (GLdouble )myFont->FTFont()->PointSize(); |
a174a3c5 | 736 | if (!myIs2d) |
737 | { | |
56689b27 | 738 | Graphic3d_TransformUtils::Project<Standard_Real> (myPoint.x(), myPoint.y(), myPoint.z(), |
739 | myModelMatrix, myProjMatrix, theCtx->Viewport(), | |
740 | myWinX, myWinY, myWinZ); | |
a174a3c5 | 741 | |
742 | // compute scale factor for constant text height | |
bf5f0ca2 | 743 | if (theTextAspect.Aspect()->IsTextZoomable()) |
a174a3c5 | 744 | { |
56689b27 | 745 | myExportHeight = aPointSize; |
746 | } | |
747 | else | |
748 | { | |
749 | Graphic3d_Vec3d aPnt1, aPnt2; | |
750 | Graphic3d_TransformUtils::UnProject<Standard_Real> (myWinX, myWinY, myWinZ, | |
751 | OpenGl_Mat4d::Map (THE_IDENTITY_MATRIX), myProjMatrix, theCtx->Viewport(), | |
752 | aPnt1.x(), aPnt1.y(), aPnt1.z()); | |
753 | Graphic3d_TransformUtils::UnProject<Standard_Real> (myWinX, myWinY + aPointSize, myWinZ, | |
754 | OpenGl_Mat4d::Map (THE_IDENTITY_MATRIX), myProjMatrix, theCtx->Viewport(), | |
755 | aPnt2.x(), aPnt2.y(), aPnt2.z()); | |
756 | myScaleHeight = (aPnt2.y() - aPnt1.y()) / aPointSize; | |
a174a3c5 | 757 | } |
758 | } | |
56689b27 | 759 | myExportHeight = aPointSize / myExportHeight; |
a174a3c5 | 760 | |
b990e557 | 761 | #if !defined(GL_ES_VERSION_2_0) |
dd1ae9df | 762 | if (theCtx->core11 != NULL |
763 | && theCtx->caps->ffpEnable) | |
65360da3 | 764 | { |
765 | glDisable (GL_LIGHTING); | |
766 | } | |
767 | #endif | |
a174a3c5 | 768 | |
769 | // setup depth test | |
8d1a539c | 770 | const bool hasDepthTest = !myIs2d |
bf5f0ca2 | 771 | && theTextAspect.Aspect()->TextStyle() != Aspect_TOST_ANNOTATION; |
8d1a539c | 772 | if (!hasDepthTest) |
a174a3c5 | 773 | { |
774 | glDisable (GL_DEPTH_TEST); | |
775 | } | |
776 | ||
65360da3 | 777 | if (theCtx->core15fwd != NULL) |
a174a3c5 | 778 | { |
65360da3 | 779 | theCtx->core15fwd->glActiveTexture (GL_TEXTURE0); |
a174a3c5 | 780 | } |
65360da3 | 781 | #if !defined(GL_ES_VERSION_2_0) |
a174a3c5 | 782 | // activate texture unit |
65360da3 | 783 | GLint aTexEnvParam = GL_REPLACE; |
784 | if (theCtx->core11 != NULL) | |
a174a3c5 | 785 | { |
65360da3 | 786 | glDisable (GL_TEXTURE_1D); |
787 | glEnable (GL_TEXTURE_2D); | |
788 | glGetTexEnviv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &aTexEnvParam); | |
789 | if (aTexEnvParam != GL_REPLACE) | |
790 | { | |
791 | glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | |
792 | } | |
a174a3c5 | 793 | } |
65360da3 | 794 | #endif |
795 | ||
796 | // setup blending | |
797 | glEnable (GL_BLEND); | |
798 | glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
a174a3c5 | 799 | |
bf5f0ca2 | 800 | // alpha to coverage makes text too thin |
801 | theCtx->SetSampleAlphaToCoverage (false); | |
802 | ||
a174a3c5 | 803 | // extra drawings |
bf5f0ca2 | 804 | switch (theTextAspect.Aspect()->TextDisplayType()) |
a174a3c5 | 805 | { |
2166f0fa | 806 | case Aspect_TODT_BLEND: |
a174a3c5 | 807 | { |
65360da3 | 808 | #if !defined(GL_ES_VERSION_2_0) |
a174a3c5 | 809 | glEnable (GL_COLOR_LOGIC_OP); |
810 | glLogicOp (GL_XOR); | |
65360da3 | 811 | #endif |
2166f0fa | 812 | break; |
a174a3c5 | 813 | } |
2166f0fa SK |
814 | case Aspect_TODT_SUBTITLE: |
815 | { | |
8d1a539c | 816 | BackPolygonOffsetSentry aPolygonOffsetTmp (hasDepthTest ? theCtx : Handle(OpenGl_Context)()); |
6fe58c66 | 817 | drawRect (theCtx, theTextAspect, theColorSubs); |
2166f0fa SK |
818 | break; |
819 | } | |
2166f0fa | 820 | case Aspect_TODT_DEKALE: |
a174a3c5 | 821 | { |
8d1a539c | 822 | BackPolygonOffsetSentry aPolygonOffsetTmp (hasDepthTest ? theCtx : Handle(OpenGl_Context)()); |
b6472664 | 823 | theCtx->SetColor4fv (theColorSubs); |
8d1a539c | 824 | setupMatrix (theCtx, theTextAspect, OpenGl_Vec3 (+1.0f, +1.0f, 0.0f)); |
60273f77 | 825 | drawText (theCtx, theTextAspect); |
8d1a539c | 826 | setupMatrix (theCtx, theTextAspect, OpenGl_Vec3 (-1.0f, -1.0f, 0.0f)); |
60273f77 | 827 | drawText (theCtx, theTextAspect); |
8d1a539c | 828 | setupMatrix (theCtx, theTextAspect, OpenGl_Vec3 (-1.0f, +1.0f, 0.0f)); |
60273f77 | 829 | drawText (theCtx, theTextAspect); |
8d1a539c | 830 | setupMatrix (theCtx, theTextAspect, OpenGl_Vec3 (+1.0f, -1.0f, 0.0f)); |
60273f77 | 831 | drawText (theCtx, theTextAspect); |
a174a3c5 | 832 | break; |
833 | } | |
3cbd0a8e | 834 | case Aspect_TODT_SHADOW: |
835 | { | |
8d1a539c | 836 | BackPolygonOffsetSentry aPolygonOffsetTmp (hasDepthTest ? theCtx : Handle(OpenGl_Context)()); |
3cbd0a8e | 837 | theCtx->SetColor4fv (theColorSubs); |
8d1a539c | 838 | setupMatrix (theCtx, theTextAspect, OpenGl_Vec3 (+1.0f, -1.0f, 0.0f)); |
3cbd0a8e | 839 | drawText (theCtx, theTextAspect); |
840 | break; | |
841 | } | |
a6eb515f | 842 | case Aspect_TODT_DIMENSION: |
a174a3c5 | 843 | case Aspect_TODT_NORMAL: |
844 | { | |
2166f0fa SK |
845 | break; |
846 | } | |
847 | } | |
848 | ||
a174a3c5 | 849 | // main draw call |
b6472664 | 850 | theCtx->SetColor4fv (theColorText); |
60273f77 | 851 | setupMatrix (theCtx, theTextAspect, OpenGl_Vec3 (0.0f, 0.0f, 0.0f)); |
852 | drawText (theCtx, theTextAspect); | |
2166f0fa | 853 | |
ce01ec26 | 854 | if (!myIs2d) |
855 | { | |
856 | theCtx->ProjectionState.SetCurrent<Standard_Real> (myProjMatrix); | |
857 | theCtx->ApplyProjectionMatrix(); | |
858 | } | |
859 | ||
65360da3 | 860 | #if !defined(GL_ES_VERSION_2_0) |
861 | if (theCtx->core11 != NULL) | |
862 | { | |
863 | glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, aTexEnvParam); | |
864 | } | |
865 | #endif | |
543f0db0 | 866 | |
bf5f0ca2 | 867 | if (theTextAspect.Aspect()->TextDisplayType() == Aspect_TODT_DIMENSION) |
543f0db0 | 868 | { |
543f0db0 | 869 | glDisable (GL_BLEND); |
543f0db0 | 870 | if (!myIs2d) |
871 | { | |
872 | glDisable (GL_DEPTH_TEST); | |
873 | } | |
65360da3 | 874 | #if !defined(GL_ES_VERSION_2_0) |
875 | if (theCtx->core11 != NULL) | |
876 | { | |
877 | glDisable (GL_TEXTURE_2D); | |
65360da3 | 878 | } |
879 | #endif | |
f88457e6 | 880 | const bool aColorMaskBack = theCtx->SetColorMask (false); |
543f0db0 | 881 | |
882 | glClear (GL_STENCIL_BUFFER_BIT); | |
883 | glEnable (GL_STENCIL_TEST); | |
884 | glStencilFunc (GL_ALWAYS, 1, 0xFF); | |
885 | glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); | |
886 | ||
6fe58c66 | 887 | drawRect (theCtx, theTextAspect, OpenGl_Vec4 (1.0f, 1.0f, 1.0f, 1.0f)); |
543f0db0 | 888 | |
889 | glStencilFunc (GL_ALWAYS, 0, 0xFF); | |
543f0db0 | 890 | |
f88457e6 | 891 | theCtx->SetColorMask (aColorMaskBack); |
543f0db0 | 892 | } |
893 | ||
b34efb62 | 894 | // reset OpenGL state |
895 | glDisable (GL_BLEND); | |
b34efb62 | 896 | glDisable (GL_STENCIL_TEST); |
65360da3 | 897 | #if !defined(GL_ES_VERSION_2_0) |
b34efb62 | 898 | glDisable (GL_COLOR_LOGIC_OP); |
65360da3 | 899 | #endif |
c827ea3a | 900 | |
901 | // model view matrix was modified | |
902 | theCtx->WorldViewState.Pop(); | |
903 | theCtx->ApplyModelViewMatrix(); | |
5e27df78 | 904 | } |