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