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