1 // Created on: 2011-07-13
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-2013 OPEN CASCADE SAS
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
20 #include <OpenGl_GlCore11.hxx>
21 #include <OpenGl_Text.hxx>
23 #include <OpenGl_AspectText.hxx>
24 #include <OpenGl_GraphicDriver.hxx>
25 #include <OpenGl_Workspace.hxx>
27 #include <Font_FontMgr.hxx>
28 #include <TCollection_HAsciiString.hxx>
40 static const GLdouble THE_IDENTITY_MATRIX[4][4] =
49 static char const* TheFamily[] = {"Helvetica", "Courier", "Times"};
50 static char const* TheItalic[] = {"Oblique", "Oblique", "Italic"};
51 static char const* TheBase[] = {"", "", "-Roman"};
53 //! Convert font name used for rendering to some "good" font names
54 //! that produce good vector text.
55 static void getGL2PSFontName (const char* theSrcFont,
58 if (strstr (theSrcFont, "Symbol"))
60 sprintf (thePsFont, "%s", "Symbol");
63 else if (strstr (theSrcFont, "ZapfDingbats"))
65 sprintf (thePsFont, "%s", "WingDings");
71 bool isItalic = false;
72 if (strstr (theSrcFont, "Courier"))
76 else if (strstr (theSrcFont, "Times"))
81 if (strstr (theSrcFont, "Bold"))
85 if (strstr (theSrcFont, "Italic")
86 || strstr (theSrcFont, "Oblique"))
95 sprintf (thePsFont, "%s-Bold%s", TheFamily[aFontId], TheItalic[aFontId]);
99 sprintf (thePsFont, "%s-Bold", TheFamily[aFontId]);
104 sprintf (thePsFont, "%s-%s", TheFamily[aFontId], TheItalic[aFontId]);
108 sprintf (thePsFont, "%s%s", TheFamily[aFontId], TheBase[aFontId]);
112 static void exportText (const NCollection_String& theText,
113 const Standard_Boolean theIs2d,
114 const OpenGl_AspectText& theAspect,
115 const Standard_Integer theHeight)
119 getGL2PSFontName (theAspect.FontName().ToCString(), aPsFont);
123 glRasterPos2f (0.0f, 0.0f);
127 glRasterPos3f (0.0f, 0.0f, 0.0f);
131 glBitmap (1, 1, 0, 0, 0, 0, &aZero);
133 // Standard GL2PS's alignment isn't used, because it doesn't work correctly
134 // for all formats, therefore alignment is calculated manually relative
135 // to the bottom-left corner, which corresponds to the GL2PS_TEXT_BL value
136 gl2psTextOpt (theText.ToCString(), aPsFont, (GLshort)theHeight, GL2PS_TEXT_BL, theAspect.Angle());
142 // =======================================================================
143 // function : OpenGl_Text
145 // =======================================================================
146 OpenGl_Text::OpenGl_Text()
150 myScaleHeight (1.0f),
151 myPoint (0.0f, 0.0f, 0.0f),
154 myParams.Height = 10;
155 myParams.HAlign = Graphic3d_HTA_LEFT;
156 myParams.VAlign = Graphic3d_VTA_BOTTOM;
159 // =======================================================================
160 // function : OpenGl_Text
162 // =======================================================================
163 OpenGl_Text::OpenGl_Text (const TCollection_ExtendedString& theText,
164 const OpenGl_Vec3& thePoint,
165 const OpenGl_TextParam& theParams)
169 myScaleHeight (1.0f),
170 myExportHeight (1.0f),
171 myParams (theParams),
172 myString ((Standard_Utf16Char* )theText.ToExtString()),
179 // =======================================================================
180 // function : SetPosition
182 // =======================================================================
183 void OpenGl_Text::SetPosition (const OpenGl_Vec3& thePoint)
188 // =======================================================================
189 // function : SetFontSize
191 // =======================================================================
192 void OpenGl_Text::SetFontSize (const Handle(OpenGl_Context)& theCtx,
193 const Standard_Integer theFontSize)
195 if (myParams.Height != theFontSize)
199 myParams.Height = theFontSize;
202 // =======================================================================
205 // =======================================================================
206 void OpenGl_Text::Init (const Handle(OpenGl_Context)& theCtx,
207 const Standard_Utf8Char* theText,
208 const OpenGl_Vec3& thePoint)
210 releaseVbos (theCtx);
213 myString.FromUnicode (theText);
216 // =======================================================================
219 // =======================================================================
220 void OpenGl_Text::Init (const Handle(OpenGl_Context)& theCtx,
221 const Standard_Utf8Char* theText,
222 const OpenGl_Vec3& thePoint,
223 const OpenGl_TextParam& theParams)
225 if (myParams.Height != theParams.Height)
231 releaseVbos (theCtx);
234 myParams = theParams;
236 myString.FromUnicode (theText);
239 // =======================================================================
242 // =======================================================================
243 void OpenGl_Text::Init (const Handle(OpenGl_Context)& theCtx,
244 const TCollection_ExtendedString& theText,
245 const OpenGl_Vec2& thePoint,
246 const OpenGl_TextParam& theParams)
248 if (myParams.Height != theParams.Height)
254 releaseVbos (theCtx);
257 myParams = theParams;
258 myPoint.xy() = thePoint;
260 myString.FromUnicode ((Standard_Utf16Char* )theText.ToExtString());
263 // =======================================================================
264 // function : ~OpenGl_Text
266 // =======================================================================
267 OpenGl_Text::~OpenGl_Text()
272 // =======================================================================
273 // function : releaseVbos
275 // =======================================================================
276 void OpenGl_Text::releaseVbos (const Handle(OpenGl_Context)& theCtx)
278 for (Standard_Integer anIter = 0; anIter < myVertsVbo.Length(); ++anIter)
280 Handle(OpenGl_VertexBuffer)& aVerts = myVertsVbo.ChangeValue (anIter);
281 Handle(OpenGl_VertexBuffer)& aTCrds = myTCrdsVbo.ChangeValue (anIter);
283 if (!theCtx.IsNull())
285 theCtx->DelayedRelease (aVerts);
286 theCtx->DelayedRelease (aTCrds);
294 myVertsArray.Clear();
295 myTCrdsArray.Clear();
298 // =======================================================================
299 // function : Release
301 // =======================================================================
302 void OpenGl_Text::Release (const Handle(OpenGl_Context)& theCtx)
304 releaseVbos (theCtx);
305 if (!myFont.IsNull())
307 Handle(OpenGl_Context) aCtx = theCtx;
308 const TCollection_AsciiString aKey = myFont->ResourceKey();
310 aCtx->ReleaseResource (aKey, Standard_True);
314 // =======================================================================
315 // function : StringSize
317 // =======================================================================
318 void OpenGl_Text::StringSize (const Handle(OpenGl_Context)& theCtx,
319 const NCollection_String& theText,
320 const OpenGl_AspectText& theTextAspect,
321 const OpenGl_TextParam& theParams,
322 Standard_ShortReal& theWidth,
323 Standard_ShortReal& theAscent,
324 Standard_ShortReal& theDescent)
329 const TCollection_AsciiString aFontKey = FontKey (theTextAspect, theParams.Height);
330 Handle(OpenGl_Font) aFont = FindFont (theCtx, theTextAspect, theParams.Height, aFontKey);
331 if (aFont.IsNull() || !aFont->IsValid())
336 theAscent = aFont->Ascender();
337 theDescent = aFont->Descender();
339 GLfloat aWidth = 0.0f;
340 for (NCollection_Utf8Iter anIter = theText.Iterator(); *anIter != 0;)
342 const Standard_Utf32Char aCharThis = *anIter;
343 const Standard_Utf32Char aCharNext = *++anIter;
345 if (aCharThis == '\x0D' // CR (carriage return)
346 || aCharThis == '\a' // BEL (alarm)
347 || aCharThis == '\f' // FF (form feed) NP (new page)
348 || aCharThis == '\b' // BS (backspace)
349 || aCharThis == '\v') // VT (vertical tab)
351 continue; // skip unsupported carriage control codes
353 else if (aCharThis == '\x0A') // LF (line feed, new line)
355 theWidth = Max (theWidth, aWidth);
359 else if (aCharThis == ' ')
361 aWidth += aFont->AdvanceX (aCharThis, aCharNext);
364 else if (aCharThis == '\t')
366 aWidth += aFont->AdvanceX (' ', aCharNext) * 8.0f;
370 aWidth += aFont->AdvanceX (aCharThis, aCharNext);
372 theWidth = Max (theWidth, aWidth);
374 Handle(OpenGl_Context) aCtx = theCtx;
376 aCtx->ReleaseResource (aFontKey, Standard_True);
379 // =======================================================================
382 // =======================================================================
383 void OpenGl_Text::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
385 const OpenGl_AspectText* aTextAspect = theWorkspace->AspectText (Standard_True);
386 const Handle(OpenGl_Texture) aPrevTexture = theWorkspace->DisableTexture();
388 // use highlight color or colors from aspect
389 if (theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT)
391 render (theWorkspace->PrinterContext(),
392 theWorkspace->GetGlContext(),
394 *theWorkspace->HighlightColor,
395 *theWorkspace->HighlightColor);
399 render (theWorkspace->PrinterContext(),
400 theWorkspace->GetGlContext(),
402 aTextAspect->Color(),
403 aTextAspect->SubtitleColor());
407 if (!aPrevTexture.IsNull())
409 theWorkspace->EnableTexture (aPrevTexture);
413 // =======================================================================
416 // =======================================================================
417 void OpenGl_Text::Render (const Handle(OpenGl_PrinterContext)& thePrintCtx,
418 const Handle(OpenGl_Context)& theCtx,
419 const OpenGl_AspectText& theTextAspect) const
421 render (thePrintCtx, theCtx, theTextAspect, theTextAspect.Color(), theTextAspect.SubtitleColor());
424 // =======================================================================
425 // function : setupMatrix
427 // =======================================================================
428 void OpenGl_Text::setupMatrix (const Handle(OpenGl_PrinterContext)& thePrintCtx,
429 const Handle(OpenGl_Context)& /*theCtx*/,
430 const OpenGl_AspectText& theTextAspect,
431 const OpenGl_Vec3 theDVec) const
437 glTranslatef (myPoint.x() + theDVec.x(), myPoint.y() + theDVec.y(), 0.0f);
438 glRotatef (180.0f, 1.0f, 0.0f, 0.0f);
442 // align coordinates to the nearest integer
443 // to avoid extra interpolation issues
444 GLdouble anObjX, anObjY, anObjZ;
445 gluUnProject (std::floor (myWinX + (GLdouble )theDVec.x()),
446 std::floor (myWinY + (GLdouble )theDVec.y()),
447 myWinZ + (GLdouble )theDVec.z(),
448 (GLdouble* )THE_IDENTITY_MATRIX, myProjMatrix, myViewport,
449 &anObjX, &anObjY, &anObjZ);
452 glTranslated (anObjX, anObjY, anObjZ);
453 glRotated (theTextAspect.Angle(), 0.0, 0.0, 1.0);
454 if (!theTextAspect.IsZoomable())
457 // if the context has assigned printer context, use it's parameters
458 if (!thePrintCtx.IsNull())
460 // get printing scaling in x and y dimensions
461 GLfloat aTextScalex = 1.0f, aTextScaley = 1.0f;
462 thePrintCtx->GetScale (aTextScalex, aTextScaley);
464 // text should be scaled in all directions with same
465 // factor to save its proportions, so use height (y) scaling
466 // as it is better for keeping text/3d graphics proportions
467 glScalef (aTextScaley, aTextScaley, aTextScaley);
470 glScaled (myScaleHeight, myScaleHeight, myScaleHeight);
475 // =======================================================================
476 // function : drawText
478 // =======================================================================
480 void OpenGl_Text::drawText (const Handle(OpenGl_PrinterContext)& ,
481 const Handle(OpenGl_Context)& theCtx,
483 const OpenGl_AspectText& theTextAspect) const
485 const OpenGl_AspectText& ) const
489 if (theCtx->IsFeedback())
491 // position of the text and alignment is calculated by transformation matrix
492 exportText (myString, myIs2d, theTextAspect, (Standard_Integer )myExportHeight);
497 if (myVertsVbo.Length() == myTextures.Length())
499 for (Standard_Integer anIter = 0; anIter < myTextures.Length(); ++anIter)
501 const GLuint aTexId = myTextures.Value (anIter);
502 const Handle(OpenGl_VertexBuffer)& aVerts = myVertsVbo.Value (anIter);
503 const Handle(OpenGl_VertexBuffer)& aTCrds = myTCrdsVbo.Value (anIter);
504 aVerts->BindFixed (theCtx, GL_VERTEX_ARRAY);
505 aTCrds->BindFixed (theCtx, GL_TEXTURE_COORD_ARRAY);
506 glBindTexture (GL_TEXTURE_2D, aTexId);
508 glDrawArrays (GL_TRIANGLES, 0, GLsizei(aVerts->GetElemsNb()));
510 glBindTexture (GL_TEXTURE_2D, 0);
511 aTCrds->UnbindFixed (theCtx, GL_TEXTURE_COORD_ARRAY);
512 aVerts->UnbindFixed (theCtx, GL_VERTEX_ARRAY);
515 else if (myVertsArray.Length() == myTextures.Length())
517 glEnableClientState (GL_VERTEX_ARRAY);
518 glEnableClientState (GL_TEXTURE_COORD_ARRAY);
519 for (Standard_Integer anIter = 0; anIter < myTextures.Length(); ++anIter)
521 const GLuint aTexId = myTextures.Value (anIter);
522 const Handle(OpenGl_Vec2Array)& aVerts = myVertsArray.Value (anIter);
523 const Handle(OpenGl_Vec2Array)& aTCrds = myTCrdsArray.Value (anIter);
525 glVertexPointer (2, GL_FLOAT, 0, (GLfloat* )&aVerts->First());
526 glTexCoordPointer (2, GL_FLOAT, 0, (GLfloat* )&aTCrds->First());
527 glBindTexture (GL_TEXTURE_2D, aTexId);
529 glDrawArrays (GL_TRIANGLES, 0, aVerts->Length());
531 glBindTexture (GL_TEXTURE_2D, 0);
533 glDisableClientState (GL_TEXTURE_COORD_ARRAY);
534 glDisableClientState (GL_VERTEX_ARRAY);
538 // =======================================================================
539 // function : FontKey
541 // =======================================================================
542 TCollection_AsciiString OpenGl_Text::FontKey (const OpenGl_AspectText& theAspect,
543 const Standard_Integer theHeight)
545 const Font_FontAspect anAspect = (theAspect.FontAspect() != Font_FA_Undefined) ? theAspect.FontAspect() : Font_FA_Regular;
546 return theAspect.FontName()
547 + TCollection_AsciiString(":") + Standard_Integer(anAspect)
548 + TCollection_AsciiString(":") + theHeight;
551 // =======================================================================
552 // function : FindFont
554 // =======================================================================
555 Handle(OpenGl_Font) OpenGl_Text::FindFont (const Handle(OpenGl_Context)& theCtx,
556 const OpenGl_AspectText& theAspect,
557 const Standard_Integer theHeight,
558 const TCollection_AsciiString theKey)
560 Handle(OpenGl_Font) aFont;
563 return aFont; // invalid parameters
566 if (!theCtx->GetResource (theKey, aFont))
568 Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
569 const Handle(TCollection_HAsciiString) aFontName = new TCollection_HAsciiString (theAspect.FontName());
570 const Font_FontAspect anAspect = (theAspect.FontAspect() != Font_FA_Undefined) ? theAspect.FontAspect() : Font_FA_Regular;
571 Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (aFontName, anAspect, theHeight);
572 if (aRequestedFont.IsNull())
577 Handle(Font_FTFont) aFontFt = new Font_FTFont (NULL);
578 if (!aFontFt->Init (aRequestedFont->FontPath()->ToCString(), theHeight))
583 Handle(OpenGl_Context) aCtx = theCtx;
584 glPushAttrib (GL_TEXTURE_BIT);
585 aFont = new OpenGl_Font (aFontFt, theKey);
586 if (!aFont->Init (aCtx))
589 //return aFont; // out of resources?
591 glPopAttrib(); // texture bit
593 aCtx->ShareResource (theKey, aFont);
598 // =======================================================================
601 // =======================================================================
602 void OpenGl_Text::render (const Handle(OpenGl_PrinterContext)& thePrintCtx,
603 const Handle(OpenGl_Context)& theCtx,
604 const OpenGl_AspectText& theTextAspect,
605 const TEL_COLOUR& theColorText,
606 const TEL_COLOUR& theColorSubs) const
608 if (myString.IsEmpty())
613 const TCollection_AsciiString aFontKey = FontKey (theTextAspect, myParams.Height);
615 && !myFont->ResourceKey().IsEqual (aFontKey))
618 const_cast<OpenGl_Text* > (this)->Release (theCtx);
623 myFont = FindFont (theCtx, theTextAspect, myParams.Height, aFontKey);
630 if (myTextures.IsEmpty())
632 OpenGl_TextFormatter aFormatter;
633 aFormatter.SetupAlignment (myParams.HAlign, myParams.VAlign);
635 aFormatter.Append (theCtx, myString, *myFont.operator->());
638 if (!theCtx->caps->vboDisable && theCtx->core15 != NULL)
640 aFormatter.Result (theCtx, myTextures, myVertsVbo, myTCrdsVbo);
644 aFormatter.Result (theCtx, myTextures, myVertsArray, myTCrdsArray);
646 aFormatter.BndBox (myBndBox);
649 if (myTextures.IsEmpty())
654 myExportHeight = 1.0f;
655 myScaleHeight = 1.0f;
657 glMatrixMode (GL_MODELVIEW);
661 // retrieve active matrices for project/unproject calls
662 glGetDoublev (GL_MODELVIEW_MATRIX, myModelMatrix);
663 glGetDoublev (GL_PROJECTION_MATRIX, myProjMatrix);
664 glGetIntegerv (GL_VIEWPORT, myViewport);
665 gluProject (myPoint.x(), myPoint.y(), myPoint.z(),
666 myModelMatrix, myProjMatrix, myViewport,
667 &myWinX, &myWinY, &myWinZ);
669 // compute scale factor for constant text height
671 gluUnProject (myWinX, myWinY, myWinZ,
672 (GLdouble* )THE_IDENTITY_MATRIX, myProjMatrix, myViewport,
676 const GLdouble h = (GLdouble )myFont->FTFont()->PointSize();
677 gluUnProject (myWinX, myWinY + h - 1.0, myWinZ,
678 (GLdouble* )THE_IDENTITY_MATRIX, myProjMatrix, myViewport,
681 myScaleHeight = (y2 - y1) / h;
682 if (theTextAspect.IsZoomable())
684 myExportHeight = (float )h;
687 myExportHeight = (float )myFont->FTFont()->PointSize() / myExportHeight;
689 // push enabled flags to the stack
690 glPushAttrib (GL_ENABLE_BIT);
694 && theTextAspect.StyleType() != Aspect_TOST_ANNOTATION)
696 glEnable (GL_DEPTH_TEST);
700 glDisable (GL_DEPTH_TEST);
704 GLint aTexEnvParam = GL_REPLACE;
705 glGetTexEnviv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &aTexEnvParam);
706 if (aTexEnvParam != GL_REPLACE)
708 glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
710 glAlphaFunc (GL_GEQUAL, 0.285f);
711 glEnable (GL_ALPHA_TEST);
715 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE
717 // activate texture unit
718 glDisable (GL_TEXTURE_1D);
719 glEnable (GL_TEXTURE_2D);
720 if (theCtx->core13 != NULL)
722 theCtx->core13->glActiveTexture (GL_TEXTURE0);
726 switch (theTextAspect.DisplayType())
728 case Aspect_TODT_BLEND:
730 glEnable (GL_COLOR_LOGIC_OP);
734 case Aspect_TODT_SUBTITLE:
736 glColor3fv (theColorSubs.rgb);
737 setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (0.0f, 0.0f, 0.00001f));
739 glBindTexture (GL_TEXTURE_2D, 0);
741 glVertex2f (myBndBox.Left, myBndBox.Top);
742 glVertex2f (myBndBox.Right, myBndBox.Top);
743 glVertex2f (myBndBox.Right, myBndBox.Bottom);
744 glVertex2f (myBndBox.Left, myBndBox.Bottom);
748 case Aspect_TODT_DEKALE:
750 glColor3fv (theColorSubs.rgb);
751 setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (+1.0f, +1.0f, 0.00001f));
752 drawText (thePrintCtx, theCtx, theTextAspect);
753 setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (-1.0f, -1.0f, 0.00001f));
754 drawText (thePrintCtx, theCtx, theTextAspect);
755 setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (-1.0f, +1.0f, 0.00001f));
756 drawText (thePrintCtx, theCtx, theTextAspect);
757 setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (+1.0f, -1.0f, 0.00001f));
758 drawText (thePrintCtx, theCtx, theTextAspect);
761 case Aspect_TODT_NORMAL:
768 glColor3fv (theColorText.rgb);
769 setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (0.0f, 0.0f, 0.0f));
770 drawText (thePrintCtx, theCtx, theTextAspect);
772 // revert OpenGL state
773 glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, aTexEnvParam);
774 glPopAttrib(); // enable bit
775 glPopMatrix(); // model view matrix was modified