0030748: Visualization - Marker displayed in immediate layer ruins QT Quick view...
[occt.git] / src / OpenGl / OpenGl_Text.cxx
CommitLineData
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 32namespace
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// =======================================================================
82OpenGl_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 101OpenGl_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
a174a3c5 119// =======================================================================
ce01ec26 120// function : OpenGl_Text
121// purpose :
122// =======================================================================
123OpenGl_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
145// =======================================================================
a174a3c5 146// function : SetPosition
147// purpose :
148// =======================================================================
149void 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// =======================================================================
158void 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// =======================================================================
172void 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// =======================================================================
186void 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// =======================================================================
209void 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// =======================================================================
232OpenGl_Text::~OpenGl_Text()
233{
234 //
235}
236
237// =======================================================================
238// function : releaseVbos
239// purpose :
240// =======================================================================
10b9c7df 241void 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 272void 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// =======================================================================
290void 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// =======================================================================
356void 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 392void 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 416void 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 516void 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 548TCollection_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// =======================================================================
566Handle(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
614// =======================================================================
6fe58c66 615// function : drawRect
616// purpose :
617// =======================================================================
618void 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
665// =======================================================================
a174a3c5 666// function : render
667// purpose :
668// =======================================================================
60273f77 669void 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}