0027670: Visualization - avoid duplication of structures defining primitive array...
[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>
2166f0fa 25
a174a3c5 26#include <Font_FontMgr.hxx>
d2eddacc 27#include <Font_FTFont.hxx>
825aa485 28#include <Graphic3d_TransformUtils.hxx>
a174a3c5 29#include <TCollection_HAsciiString.hxx>
30
a174a3c5 31#ifdef HAVE_GL2PS
32 #include <gl2ps.h>
33#endif
34
35namespace
2166f0fa 36{
c827ea3a 37 static const GLdouble THE_IDENTITY_MATRIX[16] =
a174a3c5 38 {
c827ea3a 39 1.0, 0.0, 0.0, 0.0,
40 0.0, 1.0, 0.0, 0.0,
41 0.0, 0.0, 1.0, 0.0,
42 0.0, 0.0, 0.0, 1.0
a174a3c5 43 };
44
45#ifdef HAVE_GL2PS
46 static char const* TheFamily[] = {"Helvetica", "Courier", "Times"};
47 static char const* TheItalic[] = {"Oblique", "Oblique", "Italic"};
48 static char const* TheBase[] = {"", "", "-Roman"};
49
50 //! Convert font name used for rendering to some "good" font names
51 //! that produce good vector text.
52 static void getGL2PSFontName (const char* theSrcFont,
53 char* thePsFont)
54 {
55 if (strstr (theSrcFont, "Symbol"))
56 {
57 sprintf (thePsFont, "%s", "Symbol");
58 return;
59 }
60 else if (strstr (theSrcFont, "ZapfDingbats"))
61 {
62 sprintf (thePsFont, "%s", "WingDings");
63 return;
64 }
2166f0fa 65
a174a3c5 66 int aFontId = 0;
67 bool isBold = false;
68 bool isItalic = false;
69 if (strstr (theSrcFont, "Courier"))
70 {
71 aFontId = 1;
72 }
73 else if (strstr (theSrcFont, "Times"))
74 {
75 aFontId = 2;
76 }
2166f0fa 77
a174a3c5 78 if (strstr (theSrcFont, "Bold"))
79 {
80 isBold = true;
81 }
82 if (strstr (theSrcFont, "Italic")
83 || strstr (theSrcFont, "Oblique"))
84 {
85 isItalic = true;
86 }
2166f0fa 87
a174a3c5 88 if (isBold)
89 {
a174a3c5 90 if (isItalic)
91 {
8b224a09 92 sprintf (thePsFont, "%s-Bold%s", TheFamily[aFontId], TheItalic[aFontId]);
93 }
94 else
95 {
96 sprintf (thePsFont, "%s-Bold", TheFamily[aFontId]);
a174a3c5 97 }
98 }
99 else if (isItalic)
100 {
101 sprintf (thePsFont, "%s-%s", TheFamily[aFontId], TheItalic[aFontId]);
102 }
103 else
104 {
105 sprintf (thePsFont, "%s%s", TheFamily[aFontId], TheBase[aFontId]);
106 }
107 }
2166f0fa 108
a174a3c5 109 static void exportText (const NCollection_String& theText,
110 const Standard_Boolean theIs2d,
111 const OpenGl_AspectText& theAspect,
112 const Standard_Integer theHeight)
113 {
2166f0fa 114
a174a3c5 115 char aPsFont[64];
b6472664 116 getGL2PSFontName (theAspect.Aspect()->Font().ToCString(), aPsFont);
2166f0fa 117
ca3c13d1 118 #if !defined(GL_ES_VERSION_2_0)
a174a3c5 119 if (theIs2d)
120 {
121 glRasterPos2f (0.0f, 0.0f);
122 }
123 else
124 {
125 glRasterPos3f (0.0f, 0.0f, 0.0f);
126 }
127
128 GLubyte aZero = 0;
129 glBitmap (1, 1, 0, 0, 0, 0, &aZero);
ca3c13d1 130 #endif
a174a3c5 131
132 // Standard GL2PS's alignment isn't used, because it doesn't work correctly
133 // for all formats, therefore alignment is calculated manually relative
134 // to the bottom-left corner, which corresponds to the GL2PS_TEXT_BL value
b6472664 135 gl2psTextOpt (theText.ToCString(), aPsFont, (GLshort)theHeight, GL2PS_TEXT_BL, (float )theAspect.Aspect()->GetTextAngle());
a174a3c5 136 }
137#endif
138
68858c7d 139} // anonymous namespace
a174a3c5 140
141// =======================================================================
142// function : OpenGl_Text
143// purpose :
144// =======================================================================
145OpenGl_Text::OpenGl_Text()
146: myWinX (0.0f),
147 myWinY (0.0f),
148 myWinZ (0.0f),
149 myScaleHeight (1.0f),
150 myPoint (0.0f, 0.0f, 0.0f),
ce01ec26 151 myIs2d (false),
3f1eb0ab 152 myHasPlane (false),
153 myHasAnchorPoint (true)
a174a3c5 154{
155 myParams.Height = 10;
156 myParams.HAlign = Graphic3d_HTA_LEFT;
157 myParams.VAlign = Graphic3d_VTA_BOTTOM;
2166f0fa
SK
158}
159
a174a3c5 160// =======================================================================
161// function : OpenGl_Text
162// purpose :
163// =======================================================================
b64d84be 164OpenGl_Text::OpenGl_Text (const Standard_Utf8Char* theText,
165 const OpenGl_Vec3& thePoint,
166 const OpenGl_TextParam& theParams)
a174a3c5 167: myWinX (0.0f),
168 myWinY (0.0f),
169 myWinZ (0.0f),
170 myScaleHeight (1.0f),
171 myExportHeight (1.0f),
172 myParams (theParams),
b64d84be 173 myString (theText),
a174a3c5 174 myPoint (thePoint),
ce01ec26 175 myIs2d (false),
3f1eb0ab 176 myHasPlane (false),
177 myHasAnchorPoint (true)
a174a3c5 178{
179 //
180}
2166f0fa 181
ce01ec26 182// =======================================================================
183// function : OpenGl_Text
184// purpose :
185// =======================================================================
186OpenGl_Text::OpenGl_Text (const Standard_Utf8Char* theText,
187 const gp_Ax2& theOrientation,
3f1eb0ab 188 const OpenGl_TextParam& theParams,
189 const bool theHasOwnAnchor)
ce01ec26 190: myWinX (0.0),
191 myWinY (0.0),
192 myWinZ (0.0),
193 myScaleHeight (1.0),
194 myExportHeight (1.0),
195 myParams (theParams),
196 myString (theText),
197 myIs2d (false),
198 myOrientation (theOrientation),
3f1eb0ab 199 myHasPlane (true),
200 myHasAnchorPoint (theHasOwnAnchor)
ce01ec26 201{
202 const gp_Pnt& aPoint = theOrientation.Location();
203 myPoint = OpenGl_Vec3 (static_cast<Standard_ShortReal> (aPoint.X()),
204 static_cast<Standard_ShortReal> (aPoint.Y()),
205 static_cast<Standard_ShortReal> (aPoint.Z()));
206}
207
a174a3c5 208// =======================================================================
209// function : SetPosition
210// purpose :
211// =======================================================================
212void OpenGl_Text::SetPosition (const OpenGl_Vec3& thePoint)
2166f0fa 213{
a174a3c5 214 myPoint = thePoint;
2166f0fa
SK
215}
216
a174a3c5 217// =======================================================================
218// function : SetFontSize
219// purpose :
220// =======================================================================
221void OpenGl_Text::SetFontSize (const Handle(OpenGl_Context)& theCtx,
222 const Standard_Integer theFontSize)
223{
224 if (myParams.Height != theFontSize)
225 {
10b9c7df 226 Release (theCtx.operator->());
a174a3c5 227 }
228 myParams.Height = theFontSize;
229}
230
231// =======================================================================
232// function : Init
233// purpose :
234// =======================================================================
235void OpenGl_Text::Init (const Handle(OpenGl_Context)& theCtx,
236 const Standard_Utf8Char* theText,
237 const OpenGl_Vec3& thePoint)
238{
10b9c7df 239 releaseVbos (theCtx.operator->());
a174a3c5 240 myIs2d = false;
241 myPoint = thePoint;
242 myString.FromUnicode (theText);
243}
244
245// =======================================================================
246// function : Init
247// purpose :
248// =======================================================================
249void OpenGl_Text::Init (const Handle(OpenGl_Context)& theCtx,
250 const Standard_Utf8Char* theText,
251 const OpenGl_Vec3& thePoint,
252 const OpenGl_TextParam& theParams)
253{
254 if (myParams.Height != theParams.Height)
255 {
10b9c7df 256 Release (theCtx.operator->());
a174a3c5 257 }
258 else
259 {
10b9c7df 260 releaseVbos (theCtx.operator->());
a174a3c5 261 }
262 myIs2d = false;
263 myParams = theParams;
264 myPoint = thePoint;
265 myString.FromUnicode (theText);
266}
2166f0fa 267
a174a3c5 268// =======================================================================
269// function : Init
270// purpose :
271// =======================================================================
272void OpenGl_Text::Init (const Handle(OpenGl_Context)& theCtx,
273 const TCollection_ExtendedString& theText,
274 const OpenGl_Vec2& thePoint,
275 const OpenGl_TextParam& theParams)
2166f0fa 276{
a174a3c5 277 if (myParams.Height != theParams.Height)
278 {
10b9c7df 279 Release (theCtx.operator->());
a174a3c5 280 }
281 else
282 {
10b9c7df 283 releaseVbos (theCtx.operator->());
a174a3c5 284 }
285 myIs2d = true;
286 myParams = theParams;
287 myPoint.xy() = thePoint;
288 myPoint.z() = 0.0f;
289 myString.FromUnicode ((Standard_Utf16Char* )theText.ToExtString());
290}
291
292// =======================================================================
293// function : ~OpenGl_Text
294// purpose :
295// =======================================================================
296OpenGl_Text::~OpenGl_Text()
297{
298 //
299}
300
301// =======================================================================
302// function : releaseVbos
303// purpose :
304// =======================================================================
10b9c7df 305void OpenGl_Text::releaseVbos (OpenGl_Context* theCtx)
a174a3c5 306{
307 for (Standard_Integer anIter = 0; anIter < myVertsVbo.Length(); ++anIter)
308 {
309 Handle(OpenGl_VertexBuffer)& aVerts = myVertsVbo.ChangeValue (anIter);
310 Handle(OpenGl_VertexBuffer)& aTCrds = myTCrdsVbo.ChangeValue (anIter);
311
10b9c7df 312 if (theCtx)
a174a3c5 313 {
314 theCtx->DelayedRelease (aVerts);
315 theCtx->DelayedRelease (aTCrds);
316 }
317 aVerts.Nullify();
318 aTCrds.Nullify();
319 }
320 myTextures.Clear();
321 myVertsVbo.Clear();
322 myTCrdsVbo.Clear();
a174a3c5 323}
324
325// =======================================================================
326// function : Release
327// purpose :
328// =======================================================================
10b9c7df 329void OpenGl_Text::Release (OpenGl_Context* theCtx)
a174a3c5 330{
331 releaseVbos (theCtx);
332 if (!myFont.IsNull())
333 {
334 Handle(OpenGl_Context) aCtx = theCtx;
335 const TCollection_AsciiString aKey = myFont->ResourceKey();
336 myFont.Nullify();
c04c30b3 337 if (! aCtx.IsNull())
10b9c7df 338 aCtx->ReleaseResource (aKey, Standard_True);
a174a3c5 339 }
340}
341
342// =======================================================================
343// function : StringSize
344// purpose :
345// =======================================================================
346void OpenGl_Text::StringSize (const Handle(OpenGl_Context)& theCtx,
347 const NCollection_String& theText,
348 const OpenGl_AspectText& theTextAspect,
349 const OpenGl_TextParam& theParams,
4b1c8733 350 const unsigned int theResolution,
a174a3c5 351 Standard_ShortReal& theWidth,
352 Standard_ShortReal& theAscent,
353 Standard_ShortReal& theDescent)
354{
355 theWidth = 0.0f;
356 theAscent = 0.0f;
357 theDescent = 0.0f;
4b1c8733 358 const TCollection_AsciiString aFontKey = FontKey (theTextAspect, theParams.Height, theResolution);
359 Handle(OpenGl_Font) aFont = FindFont (theCtx, theTextAspect, theParams.Height, theResolution, aFontKey);
a174a3c5 360 if (aFont.IsNull() || !aFont->IsValid())
361 {
2166f0fa 362 return;
a174a3c5 363 }
364
365 theAscent = aFont->Ascender();
366 theDescent = aFont->Descender();
367
368 GLfloat aWidth = 0.0f;
369 for (NCollection_Utf8Iter anIter = theText.Iterator(); *anIter != 0;)
370 {
371 const Standard_Utf32Char aCharThis = *anIter;
372 const Standard_Utf32Char aCharNext = *++anIter;
373
374 if (aCharThis == '\x0D' // CR (carriage return)
375 || aCharThis == '\a' // BEL (alarm)
376 || aCharThis == '\f' // FF (form feed) NP (new page)
377 || aCharThis == '\b' // BS (backspace)
378 || aCharThis == '\v') // VT (vertical tab)
379 {
380 continue; // skip unsupported carriage control codes
381 }
382 else if (aCharThis == '\x0A') // LF (line feed, new line)
383 {
384 theWidth = Max (theWidth, aWidth);
385 aWidth = 0.0f;
386 continue;
387 }
388 else if (aCharThis == ' ')
389 {
d2eddacc 390 aWidth += aFont->FTFont()->AdvanceX (aCharThis, aCharNext);
a174a3c5 391 continue;
392 }
393 else if (aCharThis == '\t')
394 {
d2eddacc 395 aWidth += aFont->FTFont()->AdvanceX (' ', aCharNext) * 8.0f;
a174a3c5 396 continue;
397 }
398
d2eddacc 399 aWidth += aFont->FTFont()->AdvanceX (aCharThis, aCharNext);
a174a3c5 400 }
401 theWidth = Max (theWidth, aWidth);
402
403 Handle(OpenGl_Context) aCtx = theCtx;
404 aFont.Nullify();
405 aCtx->ReleaseResource (aFontKey, Standard_True);
406}
407
408// =======================================================================
409// function : Render
410// purpose :
411// =======================================================================
412void OpenGl_Text::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
413{
f9ba5c4d 414 const OpenGl_AspectText* aTextAspect = theWorkspace->ApplyAspectText();
25ef750e 415 const Handle(OpenGl_Texture) aPrevTexture = theWorkspace->DisableTexture();
416 const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
30f0ad28 417
b990e557 418 // Bind custom shader program or generate default version
4e1523ef 419 if (aCtx->core20fwd != NULL)
30f0ad28 420 {
299e0ab9 421 aCtx->ShaderManager()->BindFontProgram (aTextAspect->ShaderProgramRes (aCtx));
30f0ad28 422 }
423
c357e426 424 myOrientationMatrix = theWorkspace->View()->Camera()->OrientationMatrix();
ce01ec26 425 myProjMatrix.Convert (aCtx->ProjectionState.Current());
426
a174a3c5 427 // use highlight color or colors from aspect
f9ba5c4d 428 render (theWorkspace->PrinterContext(),
429 aCtx,
430 *aTextAspect,
431 theWorkspace->TextColor(),
432 theWorkspace->TextSubtitleColor(),
433 theWorkspace->View()->RenderingParams().Resolution);
2166f0fa 434
c6ad5e5f 435 aCtx->BindProgram (NULL);
436
a174a3c5 437 // restore aspects
438 if (!aPrevTexture.IsNull())
439 {
440 theWorkspace->EnableTexture (aPrevTexture);
441 }
b34efb62 442
443 // restore Z buffer settings
eae454e3 444 if (theWorkspace->UseZBuffer())
b34efb62 445 {
446 glEnable (GL_DEPTH_TEST);
447 }
a174a3c5 448}
2166f0fa 449
a174a3c5 450// =======================================================================
451// function : Render
452// purpose :
453// =======================================================================
454void OpenGl_Text::Render (const Handle(OpenGl_PrinterContext)& thePrintCtx,
455 const Handle(OpenGl_Context)& theCtx,
4b1c8733 456 const OpenGl_AspectText& theTextAspect,
457 const unsigned int theResolution) const
a174a3c5 458{
b6472664 459 render (thePrintCtx, theCtx, theTextAspect,
460 theTextAspect.Aspect()->ColorRGBA(),
461 theTextAspect.Aspect()->ColorSubTitleRGBA(),
462 theResolution);
a174a3c5 463}
2166f0fa 464
a174a3c5 465// =======================================================================
466// function : setupMatrix
467// purpose :
468// =======================================================================
469void OpenGl_Text::setupMatrix (const Handle(OpenGl_PrinterContext)& thePrintCtx,
ca3c13d1 470 const Handle(OpenGl_Context)& theCtx,
a174a3c5 471 const OpenGl_AspectText& theTextAspect,
472 const OpenGl_Vec3 theDVec) const
473{
c827ea3a 474 OpenGl_Mat4d aModViewMat;
ce01ec26 475 OpenGl_Mat4d aProjectMat;
3f1eb0ab 476 if (myHasPlane && myHasAnchorPoint)
ce01ec26 477 {
478 aProjectMat = myProjMatrix * myOrientationMatrix;
479 }
480 else
481 {
482 aProjectMat = myProjMatrix;
483 }
c827ea3a 484
a174a3c5 485 if (myIs2d)
bf75be98 486 {
825aa485 487 Graphic3d_TransformUtils::Translate<GLdouble> (aModViewMat, myPoint.x() + theDVec.x(), myPoint.y() + theDVec.y(), 0.f);
488 Graphic3d_TransformUtils::Scale<GLdouble> (aModViewMat, 1.f, -1.f, 1.f);
b6472664 489 Graphic3d_TransformUtils::Rotate<GLdouble> (aModViewMat, theTextAspect.Aspect()->GetTextAngle(), 0.f, 0.f, 1.f);
2166f0fa
SK
490 }
491 else
492 {
a174a3c5 493 // align coordinates to the nearest integer
494 // to avoid extra interpolation issues
495 GLdouble anObjX, anObjY, anObjZ;
825aa485 496 Graphic3d_TransformUtils::UnProject<Standard_Real> (std::floor (myWinX + theDVec.x()),
497 std::floor (myWinY + theDVec.y()),
498 myWinZ + theDVec.z(),
499 OpenGl_Mat4d::Map (THE_IDENTITY_MATRIX),
ce01ec26 500 OpenGl_Mat4d::Map (aProjectMat),
825aa485 501 myViewport,
502 anObjX,
503 anObjY,
504 anObjZ);
505
ce01ec26 506 if (myHasPlane)
507 {
508 const gp_Dir& aVectorDir = myOrientation.XDirection();
509 const gp_Dir& aVectorUp = myOrientation.Direction();
510 const gp_Dir& aVectorRight = myOrientation.YDirection();
511
ce01ec26 512 aModViewMat.SetColumn (2, OpenGl_Vec3d (aVectorUp.X(), aVectorUp.Y(), aVectorUp.Z()));
513 aModViewMat.SetColumn (1, OpenGl_Vec3d (aVectorRight.X(), aVectorRight.Y(), aVectorRight.Z()));
514 aModViewMat.SetColumn (0, OpenGl_Vec3d (aVectorDir.X(), aVectorDir.Y(), aVectorDir.Z()));
3f1eb0ab 515
516 if (!myHasAnchorPoint)
517 {
518 OpenGl_Mat4d aPosMat;
519 aPosMat.SetColumn (3, OpenGl_Vec3d (myPoint.x(), myPoint.y(), myPoint.z()));
520 aPosMat *= aModViewMat;
521 aModViewMat.SetColumn (3, aPosMat.GetColumn (3));
522 }
523 else
524 {
525 aModViewMat.SetColumn (3, OpenGl_Vec3d (anObjX, anObjY, anObjZ));
526 }
ce01ec26 527 }
528 else
529 {
530 Graphic3d_TransformUtils::Translate<GLdouble> (aModViewMat, anObjX, anObjY, anObjZ);
b6472664 531 Graphic3d_TransformUtils::Rotate<GLdouble> (aModViewMat, theTextAspect.Aspect()->GetTextAngle(), 0.0, 0.0, 1.0);
ce01ec26 532 }
825aa485 533
b6472664 534 if (!theTextAspect.Aspect()->GetTextZoomable())
a174a3c5 535 {
536 #ifdef _WIN32
537 // if the context has assigned printer context, use it's parameters
538 if (!thePrintCtx.IsNull())
539 {
540 // get printing scaling in x and y dimensions
541 GLfloat aTextScalex = 1.0f, aTextScaley = 1.0f;
542 thePrintCtx->GetScale (aTextScalex, aTextScaley);
543
544 // text should be scaled in all directions with same
545 // factor to save its proportions, so use height (y) scaling
546 // as it is better for keeping text/3d graphics proportions
825aa485 547 Graphic3d_TransformUtils::Scale<GLdouble> (aModViewMat, aTextScaley, aTextScaley, aTextScaley);
a174a3c5 548 }
c85385c0 549 #else
550 (void )thePrintCtx;
a174a3c5 551 #endif
825aa485 552 Graphic3d_TransformUtils::Scale<GLdouble> (aModViewMat, myScaleHeight, myScaleHeight, myScaleHeight);
a174a3c5 553 }
554 }
c827ea3a 555
3f1eb0ab 556 if (myHasPlane && !myHasAnchorPoint)
557 {
558 OpenGl_Mat4d aCurrentWorldViewMat;
559 aCurrentWorldViewMat.Convert (theCtx->WorldViewState.Current());
560 theCtx->WorldViewState.SetCurrent<Standard_Real> (aCurrentWorldViewMat * aModViewMat);
561 }
562 else
563 {
564 theCtx->WorldViewState.SetCurrent<Standard_Real> (aModViewMat);
565 }
c827ea3a 566 theCtx->ApplyWorldViewMatrix();
b990e557 567
ce01ec26 568 if (!myIs2d)
569 {
570 theCtx->ProjectionState.SetCurrent<Standard_Real> (aProjectMat);
571 theCtx->ApplyProjectionMatrix();
572 }
573
b990e557 574 if (!theCtx->ActiveProgram().IsNull())
575 {
576 // Upload updated state to shader program
577 theCtx->ShaderManager()->PushState (theCtx->ActiveProgram());
578 }
a174a3c5 579}
580
581// =======================================================================
582// function : drawText
583// purpose :
584// =======================================================================
35e08fe8 585
586void OpenGl_Text::drawText (const Handle(OpenGl_PrinterContext)& ,
a174a3c5 587 const Handle(OpenGl_Context)& theCtx,
35e08fe8 588 #ifdef HAVE_GL2PS
a174a3c5 589 const OpenGl_AspectText& theTextAspect) const
35e08fe8 590 #else
591 const OpenGl_AspectText& ) const
592 #endif
a174a3c5 593{
594#ifdef HAVE_GL2PS
595 if (theCtx->IsFeedback())
596 {
597 // position of the text and alignment is calculated by transformation matrix
598 exportText (myString, myIs2d, theTextAspect, (Standard_Integer )myExportHeight);
599 return;
2166f0fa 600 }
a174a3c5 601#endif
2166f0fa 602
7d3e64ef 603 if (myVertsVbo.Length() != myTextures.Length()
604 || myTextures.IsEmpty())
2166f0fa 605 {
7d3e64ef 606 return;
2166f0fa 607 }
7d3e64ef 608
609 for (Standard_Integer anIter = 0; anIter < myTextures.Length(); ++anIter)
a174a3c5 610 {
7d3e64ef 611 const GLuint aTexId = myTextures.Value (anIter);
612 glBindTexture (GL_TEXTURE_2D, aTexId);
a174a3c5 613
7d3e64ef 614 const Handle(OpenGl_VertexBuffer)& aVerts = myVertsVbo.Value (anIter);
615 const Handle(OpenGl_VertexBuffer)& aTCrds = myTCrdsVbo.Value (anIter);
616 aVerts->BindAttribute (theCtx, Graphic3d_TOA_POS);
617 aTCrds->BindAttribute (theCtx, Graphic3d_TOA_UV);
2166f0fa 618
7d3e64ef 619 glDrawArrays (GL_TRIANGLES, 0, GLsizei(aVerts->GetElemsNb()));
2166f0fa 620
b990e557 621 aTCrds->UnbindAttribute (theCtx, Graphic3d_TOA_UV);
7d3e64ef 622 aVerts->UnbindAttribute (theCtx, Graphic3d_TOA_POS);
a174a3c5 623 }
7d3e64ef 624 glBindTexture (GL_TEXTURE_2D, 0);
a174a3c5 625}
2166f0fa 626
a174a3c5 627// =======================================================================
628// function : FontKey
629// purpose :
630// =======================================================================
631TCollection_AsciiString OpenGl_Text::FontKey (const OpenGl_AspectText& theAspect,
4b1c8733 632 const Standard_Integer theHeight,
633 const unsigned int theResolution)
a174a3c5 634{
b6472664 635 const Font_FontAspect anAspect = theAspect.Aspect()->GetTextFontAspect() != Font_FA_Undefined
636 ? theAspect.Aspect()->GetTextFontAspect()
637 : Font_FA_Regular;
638 return theAspect.Aspect()->Font()
a174a3c5 639 + TCollection_AsciiString(":") + Standard_Integer(anAspect)
4b1c8733 640 + TCollection_AsciiString(":") + Standard_Integer(theResolution)
a174a3c5 641 + TCollection_AsciiString(":") + theHeight;
642}
643
644// =======================================================================
645// function : FindFont
646// purpose :
647// =======================================================================
648Handle(OpenGl_Font) OpenGl_Text::FindFont (const Handle(OpenGl_Context)& theCtx,
649 const OpenGl_AspectText& theAspect,
650 const Standard_Integer theHeight,
4b1c8733 651 const unsigned int theResolution,
a174a3c5 652 const TCollection_AsciiString theKey)
653{
654 Handle(OpenGl_Font) aFont;
655 if (theHeight < 2)
2166f0fa 656 {
a174a3c5 657 return aFont; // invalid parameters
658 }
2166f0fa 659
a174a3c5 660 if (!theCtx->GetResource (theKey, aFont))
661 {
662 Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
b6472664 663 const Handle(TCollection_HAsciiString) aFontName = new TCollection_HAsciiString (theAspect.Aspect()->Font());
664 const Font_FontAspect anAspect = theAspect.Aspect()->GetTextFontAspect() != Font_FA_Undefined
665 ? theAspect.Aspect()->GetTextFontAspect()
666 : Font_FA_Regular;
a174a3c5 667 Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (aFontName, anAspect, theHeight);
65360da3 668 Handle(Font_FTFont) aFontFt;
669 if (!aRequestedFont.IsNull())
2166f0fa 670 {
65360da3 671 aFontFt = new Font_FTFont (NULL);
317d68c9 672
4b1c8733 673 if (aFontFt->Init (aRequestedFont->FontPath()->ToCString(), theHeight, theResolution))
65360da3 674 {
675 aFont = new OpenGl_Font (aFontFt, theKey);
676 if (!aFont->Init (theCtx))
677 {
678 TCollection_ExtendedString aMsg;
679 aMsg += "Font '";
b6472664 680 aMsg += theAspect.Aspect()->Font();
65360da3 681 aMsg += "' - initialization of GL resources has failed!";
3b523c4c 682 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
65360da3 683 aFontFt.Nullify();
c6ad5e5f 684 aFont->Release (theCtx.operator->());
65360da3 685 aFont = new OpenGl_Font (aFontFt, theKey);
686 }
687 }
688 else
689 {
690 TCollection_ExtendedString aMsg;
691 aMsg += "Font '";
b6472664 692 aMsg += theAspect.Aspect()->Font();
65360da3 693 aMsg += "' is broken or has incompatible format! File path: ";
694 aMsg += aRequestedFont->FontPath()->ToCString();
3b523c4c 695 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
65360da3 696 aFontFt.Nullify();
697 aFont = new OpenGl_Font (aFontFt, theKey);
698 }
a174a3c5 699 }
65360da3 700 else
a174a3c5 701 {
65360da3 702 TCollection_ExtendedString aMsg;
703 aMsg += "Font '";
b6472664 704 aMsg += theAspect.Aspect()->Font();
65360da3 705 aMsg += "' is not found in the system!";
3b523c4c 706 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
65360da3 707 aFont = new OpenGl_Font (aFontFt, theKey);
a174a3c5 708 }
a174a3c5 709
b34efb62 710 theCtx->ShareResource (theKey, aFont);
a174a3c5 711 }
712 return aFont;
713}
714
715// =======================================================================
716// function : render
717// purpose :
718// =======================================================================
719void OpenGl_Text::render (const Handle(OpenGl_PrinterContext)& thePrintCtx,
720 const Handle(OpenGl_Context)& theCtx,
721 const OpenGl_AspectText& theTextAspect,
b6472664 722 const OpenGl_Vec4& theColorText,
723 const OpenGl_Vec4& theColorSubs,
4b1c8733 724 const unsigned int theResolution) const
a174a3c5 725{
726 if (myString.IsEmpty())
727 {
728 return;
729 }
730
4b1c8733 731 // Note that using difference resolution in different Views in same Viewer
732 // will lead to performance regression (for example, text will be recreated every time).
733 const TCollection_AsciiString aFontKey = FontKey (theTextAspect, myParams.Height, theResolution);
a174a3c5 734 if (!myFont.IsNull()
735 && !myFont->ResourceKey().IsEqual (aFontKey))
736 {
737 // font changed
10b9c7df 738 const_cast<OpenGl_Text* > (this)->Release (theCtx.operator->());
a174a3c5 739 }
740
741 if (myFont.IsNull())
742 {
4b1c8733 743 myFont = FindFont (theCtx, theTextAspect, myParams.Height, theResolution, aFontKey);
65360da3 744 }
745 if (!myFont->WasInitialized())
746 {
747 return;
a174a3c5 748 }
749
750 if (myTextures.IsEmpty())
751 {
317d68c9 752 Font_TextFormatter aFormatter;
a174a3c5 753 aFormatter.SetupAlignment (myParams.HAlign, myParams.VAlign);
754 aFormatter.Reset();
317d68c9 755
d2eddacc 756 aFormatter.Append (myString, *myFont->FTFont().operator->());
a174a3c5 757 aFormatter.Format();
758
317d68c9 759 OpenGl_TextBuilder aBuilder;
760 aBuilder.Perform (aFormatter,
761 theCtx,
762 *myFont.operator->(),
763 myTextures,
764 myVertsVbo,
765 myTCrdsVbo);
766
a174a3c5 767 aFormatter.BndBox (myBndBox);
768 }
769
770 if (myTextures.IsEmpty())
771 {
772 return;
773 }
774
775 myExportHeight = 1.0f;
776 myScaleHeight = 1.0f;
777
3f1eb0ab 778 if (myHasPlane && !myHasAnchorPoint)
779 {
780 OpenGl_Mat4d aWorldViewMat;
781 aWorldViewMat.Convert (theCtx->WorldViewState.Current());
782 theCtx->WorldViewState.Push();
783 theCtx->WorldViewState.SetCurrent<Standard_Real> (aWorldViewMat);
784 theCtx->ApplyWorldViewMatrix();
785 }
786 else
787 {
788 theCtx->WorldViewState.Push();
789 }
c827ea3a 790
c827ea3a 791 myModelMatrix.Convert (theCtx->WorldViewState.Current() * theCtx->ModelWorldState.Current());
792
a174a3c5 793 if (!myIs2d)
794 {
a174a3c5 795 glGetIntegerv (GL_VIEWPORT, myViewport);
c827ea3a 796
825aa485 797 Graphic3d_TransformUtils::Project<Standard_Real> (myPoint.x(),
798 myPoint.y(),
799 myPoint.z(),
800 myModelMatrix,
801 myProjMatrix,
802 myViewport,
803 myWinX,
804 myWinY,
805 myWinZ);
a174a3c5 806
807 // compute scale factor for constant text height
808 GLdouble x1, y1, z1;
825aa485 809 Graphic3d_TransformUtils::UnProject<Standard_Real> (myWinX,
810 myWinY,
811 myWinZ,
812 OpenGl_Mat4d::Map (THE_IDENTITY_MATRIX),
813 myProjMatrix,
814 myViewport,
815 x1,
816 y1,
817 z1);
a174a3c5 818
819 GLdouble x2, y2, z2;
820 const GLdouble h = (GLdouble )myFont->FTFont()->PointSize();
825aa485 821 Graphic3d_TransformUtils::UnProject<Standard_Real> (myWinX,
822 myWinY + h,
823 myWinZ,
824 OpenGl_Mat4d::Map (THE_IDENTITY_MATRIX),
825 myProjMatrix,
826 myViewport,
827 x2,
828 y2,
829 z2);
a174a3c5 830
831 myScaleHeight = (y2 - y1) / h;
b6472664 832 if (theTextAspect.Aspect()->GetTextZoomable())
a174a3c5 833 {
834 myExportHeight = (float )h;
835 }
836 }
837 myExportHeight = (float )myFont->FTFont()->PointSize() / myExportHeight;
838
b990e557 839#if !defined(GL_ES_VERSION_2_0)
65360da3 840 if (theCtx->core11 != NULL)
841 {
842 glDisable (GL_LIGHTING);
843 }
844#endif
a174a3c5 845
846 // setup depth test
eae454e3 847 if (myIs2d
b6472664 848 || theTextAspect.Aspect()->Style() == Aspect_TOST_ANNOTATION)
a174a3c5 849 {
850 glDisable (GL_DEPTH_TEST);
851 }
852
65360da3 853 if (theCtx->core15fwd != NULL)
a174a3c5 854 {
65360da3 855 theCtx->core15fwd->glActiveTexture (GL_TEXTURE0);
a174a3c5 856 }
65360da3 857#if !defined(GL_ES_VERSION_2_0)
a174a3c5 858 // activate texture unit
65360da3 859 GLint aTexEnvParam = GL_REPLACE;
860 if (theCtx->core11 != NULL)
a174a3c5 861 {
c6ad5e5f 862 // setup alpha test
863 glAlphaFunc (GL_GEQUAL, 0.285f);
864 glEnable (GL_ALPHA_TEST);
865
65360da3 866 glDisable (GL_TEXTURE_1D);
867 glEnable (GL_TEXTURE_2D);
868 glGetTexEnviv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &aTexEnvParam);
869 if (aTexEnvParam != GL_REPLACE)
870 {
871 glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
872 }
a174a3c5 873 }
65360da3 874#endif
875
876 // setup blending
877 glEnable (GL_BLEND);
878 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
a174a3c5 879
880 // extra drawings
b6472664 881 switch (theTextAspect.Aspect()->DisplayType())
a174a3c5 882 {
2166f0fa 883 case Aspect_TODT_BLEND:
a174a3c5 884 {
65360da3 885 #if !defined(GL_ES_VERSION_2_0)
a174a3c5 886 glEnable (GL_COLOR_LOGIC_OP);
887 glLogicOp (GL_XOR);
65360da3 888 #endif
2166f0fa 889 break;
a174a3c5 890 }
2166f0fa
SK
891 case Aspect_TODT_SUBTITLE:
892 {
65360da3 893 #if !defined(GL_ES_VERSION_2_0)
894 if (theCtx->core11 != NULL)
895 {
b6472664 896 theCtx->SetColor4fv (theColorSubs);
65360da3 897 setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (0.0f, 0.0f, 0.00001f));
898
899 glBindTexture (GL_TEXTURE_2D, 0);
900 glBegin (GL_QUADS);
901 glVertex2f (myBndBox.Left, myBndBox.Top);
902 glVertex2f (myBndBox.Right, myBndBox.Top);
903 glVertex2f (myBndBox.Right, myBndBox.Bottom);
904 glVertex2f (myBndBox.Left, myBndBox.Bottom);
905 glEnd();
906 }
907 #endif
2166f0fa
SK
908 break;
909 }
2166f0fa 910 case Aspect_TODT_DEKALE:
a174a3c5 911 {
b6472664 912 theCtx->SetColor4fv (theColorSubs);
a174a3c5 913 setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (+1.0f, +1.0f, 0.00001f));
914 drawText (thePrintCtx, theCtx, theTextAspect);
915 setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (-1.0f, -1.0f, 0.00001f));
916 drawText (thePrintCtx, theCtx, theTextAspect);
917 setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (-1.0f, +1.0f, 0.00001f));
918 drawText (thePrintCtx, theCtx, theTextAspect);
919 setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (+1.0f, -1.0f, 0.00001f));
920 drawText (thePrintCtx, theCtx, theTextAspect);
921 break;
922 }
a6eb515f 923 case Aspect_TODT_DIMENSION:
a174a3c5 924 case Aspect_TODT_NORMAL:
925 {
2166f0fa
SK
926 break;
927 }
928 }
929
a174a3c5 930 // main draw call
b6472664 931 theCtx->SetColor4fv (theColorText);
a174a3c5 932 setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (0.0f, 0.0f, 0.0f));
933 drawText (thePrintCtx, theCtx, theTextAspect);
2166f0fa 934
ce01ec26 935 if (!myIs2d)
936 {
937 theCtx->ProjectionState.SetCurrent<Standard_Real> (myProjMatrix);
938 theCtx->ApplyProjectionMatrix();
939 }
940
65360da3 941#if !defined(GL_ES_VERSION_2_0)
942 if (theCtx->core11 != NULL)
943 {
944 glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, aTexEnvParam);
945 }
946#endif
543f0db0 947
b6472664 948 if (theTextAspect.Aspect()->DisplayType() == Aspect_TODT_DIMENSION)
543f0db0 949 {
950 setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (0.0f, 0.0f, 0.00001f));
951
952 glDisable (GL_BLEND);
543f0db0 953 if (!myIs2d)
954 {
955 glDisable (GL_DEPTH_TEST);
956 }
65360da3 957 #if !defined(GL_ES_VERSION_2_0)
958 if (theCtx->core11 != NULL)
959 {
960 glDisable (GL_TEXTURE_2D);
961 glDisable (GL_ALPHA_TEST);
962 }
963 #endif
543f0db0 964 glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
965
966 glClear (GL_STENCIL_BUFFER_BIT);
967 glEnable (GL_STENCIL_TEST);
968 glStencilFunc (GL_ALWAYS, 1, 0xFF);
969 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);
970
65360da3 971 #if !defined(GL_ES_VERSION_2_0)
972 if (theCtx->core11 != NULL)
973 {
974 glBegin (GL_QUADS);
975 glVertex2f (myBndBox.Left, myBndBox.Top);
976 glVertex2f (myBndBox.Right, myBndBox.Top);
977 glVertex2f (myBndBox.Right, myBndBox.Bottom);
978 glVertex2f (myBndBox.Left, myBndBox.Bottom);
979 glEnd();
980 }
981 #endif
543f0db0 982
983 glStencilFunc (GL_ALWAYS, 0, 0xFF);
543f0db0 984
985 glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
986 }
987
b34efb62 988 // reset OpenGL state
989 glDisable (GL_BLEND);
b34efb62 990 glDisable (GL_STENCIL_TEST);
65360da3 991#if !defined(GL_ES_VERSION_2_0)
c6ad5e5f 992 if (theCtx->core11 != NULL)
993 {
994 glDisable (GL_ALPHA_TEST);
995 }
b34efb62 996 glDisable (GL_COLOR_LOGIC_OP);
65360da3 997#endif
c827ea3a 998
999 // model view matrix was modified
1000 theCtx->WorldViewState.Pop();
1001 theCtx->ApplyModelViewMatrix();
5e27df78 1002}