0027670: Visualization - avoid duplication of structures defining primitive array...
[occt.git] / src / OpenGl / OpenGl_Text.cxx
1 // Created on: 2011-07-13
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-2013 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <OpenGl_AspectText.hxx>
17 #include <OpenGl_GlCore11.hxx>
18 #include <OpenGl_GraphicDriver.hxx>
19 #include <OpenGl_ShaderManager.hxx>
20 #include <OpenGl_ShaderProgram.hxx>
21 #include <OpenGl_ShaderStates.hxx>
22 #include <OpenGl_Text.hxx>
23 #include <OpenGl_Workspace.hxx>
24 #include <OpenGl_View.hxx>
25
26 #include <Font_FontMgr.hxx>
27 #include <Font_FTFont.hxx>
28 #include <Graphic3d_TransformUtils.hxx>
29 #include <TCollection_HAsciiString.hxx>
30
31 #ifdef HAVE_GL2PS
32   #include <gl2ps.h>
33 #endif
34
35 namespace
36 {
37   static const GLdouble THE_IDENTITY_MATRIX[16] =
38   {
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
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     }
65
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     }
77
78     if (strstr (theSrcFont, "Bold"))
79     {
80       isBold = true;
81     }
82     if (strstr (theSrcFont, "Italic")
83      || strstr (theSrcFont, "Oblique"))
84     {
85       isItalic = true;
86     }
87
88     if (isBold)
89     {
90       if (isItalic)
91       {
92         sprintf (thePsFont, "%s-Bold%s", TheFamily[aFontId], TheItalic[aFontId]);
93       }
94       else
95       {
96         sprintf (thePsFont, "%s-Bold", TheFamily[aFontId]);
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   }
108
109   static void exportText (const NCollection_String& theText,
110                           const Standard_Boolean    theIs2d,
111                           const OpenGl_AspectText&  theAspect,
112                           const Standard_Integer    theHeight)
113   {
114
115     char aPsFont[64];
116     getGL2PSFontName (theAspect.Aspect()->Font().ToCString(), aPsFont);
117
118   #if !defined(GL_ES_VERSION_2_0)
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);
130   #endif
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
135     gl2psTextOpt (theText.ToCString(), aPsFont, (GLshort)theHeight, GL2PS_TEXT_BL, (float )theAspect.Aspect()->GetTextAngle());
136   }
137 #endif
138
139 } // anonymous namespace
140
141 // =======================================================================
142 // function : OpenGl_Text
143 // purpose  :
144 // =======================================================================
145 OpenGl_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),
151   myIs2d   (false),
152   myHasPlane (false),
153   myHasAnchorPoint (true)
154 {
155   myParams.Height = 10;
156   myParams.HAlign = Graphic3d_HTA_LEFT;
157   myParams.VAlign = Graphic3d_VTA_BOTTOM;
158 }
159
160 // =======================================================================
161 // function : OpenGl_Text
162 // purpose  :
163 // =======================================================================
164 OpenGl_Text::OpenGl_Text (const Standard_Utf8Char* theText,
165                           const OpenGl_Vec3&       thePoint,
166                           const OpenGl_TextParam&  theParams)
167 : myWinX (0.0f),
168   myWinY (0.0f),
169   myWinZ (0.0f),
170   myScaleHeight  (1.0f),
171   myExportHeight (1.0f),
172   myParams (theParams),
173   myString (theText),
174   myPoint  (thePoint),
175   myIs2d   (false),
176   myHasPlane (false),
177   myHasAnchorPoint (true)
178 {
179   //
180 }
181
182 // =======================================================================
183 // function : OpenGl_Text
184 // purpose  :
185 // =======================================================================
186 OpenGl_Text::OpenGl_Text (const Standard_Utf8Char* theText,
187                           const gp_Ax2&            theOrientation,
188                           const OpenGl_TextParam&  theParams,
189                           const bool               theHasOwnAnchor)
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),
199   myHasPlane     (true),
200   myHasAnchorPoint (theHasOwnAnchor)
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
208 // =======================================================================
209 // function : SetPosition
210 // purpose  :
211 // =======================================================================
212 void OpenGl_Text::SetPosition (const OpenGl_Vec3& thePoint)
213 {
214   myPoint = thePoint;
215 }
216
217 // =======================================================================
218 // function : SetFontSize
219 // purpose  :
220 // =======================================================================
221 void OpenGl_Text::SetFontSize (const Handle(OpenGl_Context)& theCtx,
222                                const Standard_Integer        theFontSize)
223 {
224   if (myParams.Height != theFontSize)
225   {
226     Release (theCtx.operator->());
227   }
228   myParams.Height = theFontSize;
229 }
230
231 // =======================================================================
232 // function : Init
233 // purpose  :
234 // =======================================================================
235 void OpenGl_Text::Init (const Handle(OpenGl_Context)& theCtx,
236                         const Standard_Utf8Char*      theText,
237                         const OpenGl_Vec3&            thePoint)
238 {
239   releaseVbos (theCtx.operator->());
240   myIs2d   = false;
241   myPoint  = thePoint;
242   myString.FromUnicode (theText);
243 }
244
245 // =======================================================================
246 // function : Init
247 // purpose  :
248 // =======================================================================
249 void 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   {
256     Release (theCtx.operator->());
257   }
258   else
259   {
260     releaseVbos (theCtx.operator->());
261   }
262   myIs2d   = false;
263   myParams = theParams;
264   myPoint  = thePoint;
265   myString.FromUnicode (theText);
266 }
267
268 // =======================================================================
269 // function : Init
270 // purpose  :
271 // =======================================================================
272 void OpenGl_Text::Init (const Handle(OpenGl_Context)&     theCtx,
273                         const TCollection_ExtendedString& theText,
274                         const OpenGl_Vec2&                thePoint,
275                         const OpenGl_TextParam&           theParams)
276 {
277   if (myParams.Height != theParams.Height)
278   {
279     Release (theCtx.operator->());
280   }
281   else
282   {
283     releaseVbos (theCtx.operator->());
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 // =======================================================================
296 OpenGl_Text::~OpenGl_Text()
297 {
298   //
299 }
300
301 // =======================================================================
302 // function : releaseVbos
303 // purpose  :
304 // =======================================================================
305 void OpenGl_Text::releaseVbos (OpenGl_Context* theCtx)
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
312     if (theCtx)
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();
323 }
324
325 // =======================================================================
326 // function : Release
327 // purpose  :
328 // =======================================================================
329 void OpenGl_Text::Release (OpenGl_Context* theCtx)
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();
337     if (! aCtx.IsNull())
338       aCtx->ReleaseResource (aKey, Standard_True);
339   }
340 }
341
342 // =======================================================================
343 // function : StringSize
344 // purpose  :
345 // =======================================================================
346 void OpenGl_Text::StringSize (const Handle(OpenGl_Context)& theCtx,
347                               const NCollection_String&     theText,
348                               const OpenGl_AspectText&      theTextAspect,
349                               const OpenGl_TextParam&       theParams,
350                               const unsigned int            theResolution,
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;
358   const TCollection_AsciiString aFontKey = FontKey (theTextAspect, theParams.Height, theResolution);
359   Handle(OpenGl_Font) aFont = FindFont (theCtx, theTextAspect, theParams.Height, theResolution, aFontKey);
360   if (aFont.IsNull() || !aFont->IsValid())
361   {
362     return;
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     {
390       aWidth += aFont->FTFont()->AdvanceX (aCharThis, aCharNext);
391       continue;
392     }
393     else if (aCharThis == '\t')
394     {
395       aWidth += aFont->FTFont()->AdvanceX (' ', aCharNext) * 8.0f;
396       continue;
397     }
398
399     aWidth += aFont->FTFont()->AdvanceX (aCharThis, aCharNext);
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 // =======================================================================
412 void OpenGl_Text::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
413 {
414   const OpenGl_AspectText*      aTextAspect  = theWorkspace->ApplyAspectText();
415   const Handle(OpenGl_Texture)  aPrevTexture = theWorkspace->DisableTexture();
416   const Handle(OpenGl_Context)& aCtx         = theWorkspace->GetGlContext();
417
418   // Bind custom shader program or generate default version
419   if (aCtx->core20fwd != NULL)
420   {
421     aCtx->ShaderManager()->BindFontProgram (aTextAspect->ShaderProgramRes (aCtx));
422   }
423
424   myOrientationMatrix = theWorkspace->View()->Camera()->OrientationMatrix();
425   myProjMatrix.Convert (aCtx->ProjectionState.Current());
426
427   // use highlight color or colors from aspect
428   render (theWorkspace->PrinterContext(),
429           aCtx,
430           *aTextAspect,
431           theWorkspace->TextColor(),
432           theWorkspace->TextSubtitleColor(),
433           theWorkspace->View()->RenderingParams().Resolution);
434
435   aCtx->BindProgram (NULL);
436
437   // restore aspects
438   if (!aPrevTexture.IsNull())
439   {
440     theWorkspace->EnableTexture (aPrevTexture);
441   }
442
443   // restore Z buffer settings
444   if (theWorkspace->UseZBuffer())
445   {
446     glEnable (GL_DEPTH_TEST);
447   }
448 }
449
450 // =======================================================================
451 // function : Render
452 // purpose  :
453 // =======================================================================
454 void OpenGl_Text::Render (const Handle(OpenGl_PrinterContext)& thePrintCtx,
455                           const Handle(OpenGl_Context)&        theCtx,
456                           const OpenGl_AspectText&             theTextAspect,
457                           const unsigned int                   theResolution) const
458 {
459   render (thePrintCtx, theCtx, theTextAspect,
460           theTextAspect.Aspect()->ColorRGBA(),
461           theTextAspect.Aspect()->ColorSubTitleRGBA(),
462           theResolution);
463 }
464
465 // =======================================================================
466 // function : setupMatrix
467 // purpose  :
468 // =======================================================================
469 void OpenGl_Text::setupMatrix (const Handle(OpenGl_PrinterContext)& thePrintCtx,
470                                const Handle(OpenGl_Context)&        theCtx,
471                                const OpenGl_AspectText&             theTextAspect,
472                                const OpenGl_Vec3                    theDVec) const
473 {
474   OpenGl_Mat4d aModViewMat;
475   OpenGl_Mat4d aProjectMat;
476   if (myHasPlane && myHasAnchorPoint)
477   {
478     aProjectMat = myProjMatrix * myOrientationMatrix;
479   }
480   else
481   {
482     aProjectMat = myProjMatrix;
483   }
484
485   if (myIs2d)
486   {
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);
489     Graphic3d_TransformUtils::Rotate<GLdouble> (aModViewMat, theTextAspect.Aspect()->GetTextAngle(), 0.f, 0.f, 1.f);
490   }
491   else
492   {
493     // align coordinates to the nearest integer
494     // to avoid extra interpolation issues
495     GLdouble anObjX, anObjY, anObjZ;
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),
500                                                         OpenGl_Mat4d::Map (aProjectMat),
501                                                         myViewport,
502                                                         anObjX,
503                                                         anObjY,
504                                                         anObjZ);
505
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
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()));
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       }
527     }
528     else
529     {
530       Graphic3d_TransformUtils::Translate<GLdouble> (aModViewMat, anObjX, anObjY, anObjZ);
531       Graphic3d_TransformUtils::Rotate<GLdouble> (aModViewMat, theTextAspect.Aspect()->GetTextAngle(), 0.0, 0.0, 1.0);
532     }
533
534     if (!theTextAspect.Aspect()->GetTextZoomable())
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
547         Graphic3d_TransformUtils::Scale<GLdouble> (aModViewMat, aTextScaley, aTextScaley, aTextScaley);
548       }
549     #else
550       (void )thePrintCtx;
551     #endif
552       Graphic3d_TransformUtils::Scale<GLdouble> (aModViewMat, myScaleHeight, myScaleHeight, myScaleHeight);
553     }
554   }
555
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   }
566   theCtx->ApplyWorldViewMatrix();
567
568   if (!myIs2d)
569   {
570     theCtx->ProjectionState.SetCurrent<Standard_Real> (aProjectMat);
571     theCtx->ApplyProjectionMatrix();
572   }
573
574   if (!theCtx->ActiveProgram().IsNull())
575   {
576     // Upload updated state to shader program
577     theCtx->ShaderManager()->PushState (theCtx->ActiveProgram());
578   }
579 }
580
581 // =======================================================================
582 // function : drawText
583 // purpose  :
584 // =======================================================================
585
586 void OpenGl_Text::drawText (const Handle(OpenGl_PrinterContext)& ,
587                             const Handle(OpenGl_Context)&        theCtx,
588                           #ifdef HAVE_GL2PS
589                             const OpenGl_AspectText&             theTextAspect) const
590                           #else
591                             const OpenGl_AspectText&                          ) const
592                           #endif
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;
600   }
601 #endif
602
603   if (myVertsVbo.Length() != myTextures.Length()
604    || myTextures.IsEmpty())
605   {
606     return;
607   }
608
609   for (Standard_Integer anIter = 0; anIter < myTextures.Length(); ++anIter)
610   {
611     const GLuint aTexId = myTextures.Value (anIter);
612     glBindTexture (GL_TEXTURE_2D, aTexId);
613
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);
618
619     glDrawArrays (GL_TRIANGLES, 0, GLsizei(aVerts->GetElemsNb()));
620
621     aTCrds->UnbindAttribute (theCtx, Graphic3d_TOA_UV);
622     aVerts->UnbindAttribute (theCtx, Graphic3d_TOA_POS);
623   }
624   glBindTexture (GL_TEXTURE_2D, 0);
625 }
626
627 // =======================================================================
628 // function : FontKey
629 // purpose  :
630 // =======================================================================
631 TCollection_AsciiString OpenGl_Text::FontKey (const OpenGl_AspectText& theAspect,
632                                               const Standard_Integer   theHeight,
633                                               const unsigned int       theResolution)
634 {
635   const Font_FontAspect anAspect = theAspect.Aspect()->GetTextFontAspect() != Font_FA_Undefined
636                                  ? theAspect.Aspect()->GetTextFontAspect()
637                                  : Font_FA_Regular;
638   return theAspect.Aspect()->Font()
639        + TCollection_AsciiString(":") + Standard_Integer(anAspect)
640        + TCollection_AsciiString(":") + Standard_Integer(theResolution)
641        + TCollection_AsciiString(":") + theHeight;
642 }
643
644 // =======================================================================
645 // function : FindFont
646 // purpose  :
647 // =======================================================================
648 Handle(OpenGl_Font) OpenGl_Text::FindFont (const Handle(OpenGl_Context)& theCtx,
649                                            const OpenGl_AspectText&      theAspect,
650                                            const Standard_Integer        theHeight,
651                                            const unsigned int            theResolution,
652                                            const TCollection_AsciiString theKey)
653 {
654   Handle(OpenGl_Font) aFont;
655   if (theHeight < 2)
656   {
657     return aFont; // invalid parameters
658   }
659
660   if (!theCtx->GetResource (theKey, aFont))
661   {
662     Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
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;
667     Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (aFontName, anAspect, theHeight);
668     Handle(Font_FTFont) aFontFt;
669     if (!aRequestedFont.IsNull())
670     {
671       aFontFt = new Font_FTFont (NULL);
672
673       if (aFontFt->Init (aRequestedFont->FontPath()->ToCString(), theHeight, theResolution))
674       {
675         aFont = new OpenGl_Font (aFontFt, theKey);
676         if (!aFont->Init (theCtx))
677         {
678           TCollection_ExtendedString aMsg;
679           aMsg += "Font '";
680           aMsg += theAspect.Aspect()->Font();
681           aMsg += "' - initialization of GL resources has failed!";
682           theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
683           aFontFt.Nullify();
684           aFont->Release (theCtx.operator->());
685           aFont = new OpenGl_Font (aFontFt, theKey);
686         }
687       }
688       else
689       {
690         TCollection_ExtendedString aMsg;
691         aMsg += "Font '";
692         aMsg += theAspect.Aspect()->Font();
693         aMsg += "' is broken or has incompatible format! File path: ";
694         aMsg += aRequestedFont->FontPath()->ToCString();
695         theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
696         aFontFt.Nullify();
697         aFont = new OpenGl_Font (aFontFt, theKey);
698       }
699     }
700     else
701     {
702       TCollection_ExtendedString aMsg;
703       aMsg += "Font '";
704       aMsg += theAspect.Aspect()->Font();
705       aMsg += "' is not found in the system!";
706       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
707       aFont = new OpenGl_Font (aFontFt, theKey);
708     }
709
710     theCtx->ShareResource (theKey, aFont);
711   }
712   return aFont;
713 }
714
715 // =======================================================================
716 // function : render
717 // purpose  :
718 // =======================================================================
719 void OpenGl_Text::render (const Handle(OpenGl_PrinterContext)& thePrintCtx,
720                           const Handle(OpenGl_Context)&        theCtx,
721                           const OpenGl_AspectText&             theTextAspect,
722                           const OpenGl_Vec4&                   theColorText,
723                           const OpenGl_Vec4&                   theColorSubs,
724                           const unsigned int                   theResolution) const
725 {
726   if (myString.IsEmpty())
727   {
728     return;
729   }
730
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);
734   if (!myFont.IsNull()
735    && !myFont->ResourceKey().IsEqual (aFontKey))
736   {
737     // font changed
738     const_cast<OpenGl_Text* > (this)->Release (theCtx.operator->());
739   }
740
741   if (myFont.IsNull())
742   {
743     myFont = FindFont (theCtx, theTextAspect, myParams.Height, theResolution, aFontKey);
744   }
745   if (!myFont->WasInitialized())
746   {
747     return;
748   }
749
750   if (myTextures.IsEmpty())
751   {
752     Font_TextFormatter aFormatter;
753     aFormatter.SetupAlignment (myParams.HAlign, myParams.VAlign);
754     aFormatter.Reset();
755
756     aFormatter.Append (myString, *myFont->FTFont().operator->());
757     aFormatter.Format();
758
759     OpenGl_TextBuilder aBuilder;
760     aBuilder.Perform (aFormatter,
761                       theCtx,
762                       *myFont.operator->(),
763                       myTextures,
764                       myVertsVbo,
765                       myTCrdsVbo);
766
767     aFormatter.BndBox (myBndBox);
768   }
769
770   if (myTextures.IsEmpty())
771   {
772     return;
773   }
774
775   myExportHeight = 1.0f;
776   myScaleHeight  = 1.0f;
777
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   }
790
791   myModelMatrix.Convert (theCtx->WorldViewState.Current() * theCtx->ModelWorldState.Current());
792
793   if (!myIs2d)
794   {
795     glGetIntegerv (GL_VIEWPORT,          myViewport);
796
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);
806
807     // compute scale factor for constant text height
808     GLdouble x1, y1, z1;
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);
818
819     GLdouble x2, y2, z2;
820     const GLdouble h = (GLdouble )myFont->FTFont()->PointSize();
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);
830
831     myScaleHeight = (y2 - y1) / h;
832     if (theTextAspect.Aspect()->GetTextZoomable())
833     {
834       myExportHeight = (float )h;
835     }
836   }
837   myExportHeight = (float )myFont->FTFont()->PointSize() / myExportHeight;
838
839 #if !defined(GL_ES_VERSION_2_0)
840   if (theCtx->core11 != NULL)
841   {
842     glDisable (GL_LIGHTING);
843   }
844 #endif
845
846   // setup depth test
847   if (myIs2d
848    || theTextAspect.Aspect()->Style() == Aspect_TOST_ANNOTATION)
849   {
850     glDisable (GL_DEPTH_TEST);
851   }
852
853   if (theCtx->core15fwd != NULL)
854   {
855     theCtx->core15fwd->glActiveTexture (GL_TEXTURE0);
856   }
857 #if !defined(GL_ES_VERSION_2_0)
858   // activate texture unit
859   GLint aTexEnvParam = GL_REPLACE;
860   if (theCtx->core11 != NULL)
861   {
862     // setup alpha test
863     glAlphaFunc (GL_GEQUAL, 0.285f);
864     glEnable (GL_ALPHA_TEST);
865
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     }
873   }
874 #endif
875
876   // setup blending
877   glEnable (GL_BLEND);
878   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
879
880   // extra drawings
881   switch (theTextAspect.Aspect()->DisplayType())
882   {
883     case Aspect_TODT_BLEND:
884     {
885     #if !defined(GL_ES_VERSION_2_0)
886       glEnable  (GL_COLOR_LOGIC_OP);
887       glLogicOp (GL_XOR);
888     #endif
889       break;
890     }
891     case Aspect_TODT_SUBTITLE:
892     {
893     #if !defined(GL_ES_VERSION_2_0)
894       if (theCtx->core11 != NULL)
895       {
896         theCtx->SetColor4fv (theColorSubs);
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
908       break;
909     }
910     case Aspect_TODT_DEKALE:
911     {
912       theCtx->SetColor4fv (theColorSubs);
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     }
923     case Aspect_TODT_DIMENSION:
924     case Aspect_TODT_NORMAL:
925     {
926       break;
927     }
928   }
929
930   // main draw call
931   theCtx->SetColor4fv (theColorText);
932   setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (0.0f, 0.0f, 0.0f));
933   drawText    (thePrintCtx, theCtx, theTextAspect);
934
935   if (!myIs2d)
936   {
937     theCtx->ProjectionState.SetCurrent<Standard_Real> (myProjMatrix);
938     theCtx->ApplyProjectionMatrix();
939   }
940
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
947
948   if (theTextAspect.Aspect()->DisplayType() == Aspect_TODT_DIMENSION)
949   {
950     setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (0.0f, 0.0f, 0.00001f));
951
952     glDisable (GL_BLEND);
953     if (!myIs2d)
954     {
955       glDisable (GL_DEPTH_TEST);
956     }
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
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
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
982
983     glStencilFunc (GL_ALWAYS, 0, 0xFF);
984
985     glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
986   }
987
988   // reset OpenGL state
989   glDisable (GL_BLEND);
990   glDisable (GL_STENCIL_TEST);
991 #if !defined(GL_ES_VERSION_2_0)
992   if (theCtx->core11 != NULL)
993   {
994     glDisable (GL_ALPHA_TEST);
995   }
996   glDisable (GL_COLOR_LOGIC_OP);
997 #endif
998
999   // model view matrix was modified
1000   theCtx->WorldViewState.Pop();
1001   theCtx->ApplyModelViewMatrix();
1002 }