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