0022752: Fix compilation on Unix with FreeImage and GL2PS support
[occt.git] / src / OpenGl / OpenGl_Display_1.cxx
index 257cd71..52e2bee 100644 (file)
@@ -1,17 +1,37 @@
-// File:      OpenGl_Display_1.cxx
-// Created:   25 October 2011
-// Author:    Sergey ZERCHANINOV
-// Copyright: OPEN CASCADE 2011
-
+// Created on: 2011-10-25
+// Created by: Sergey ZERCHANINOV
+// Copyright (c) 2011-2012 OPEN CASCADE SAS
+//
+// The content of this file is subject to the Open CASCADE Technology Public
+// License Version 6.5 (the "License"). You may not use the content of this file
+// except in compliance with the License. Please obtain a copy of the License
+// at http://www.opencascade.org and read it completely before using this file.
+//
+// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
+// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
+//
+// The Original Code and all software distributed under the License is
+// distributed on an "AS IS" basis, without warranty of any kind, and the
+// Initial Developer hereby disclaims all such warranties, including without
+// limitation, any warranties of merchantability, fitness for a particular
+// purpose or non-infringement. Please see the License for the specific terms
+// and conditions governing the rights and limitations under the License.
+
+
+#include <InterfaceGraphic.hxx>
 #include <OpenGl_Display.hxx>
 
 #include <TCollection_AsciiString.hxx>
 #include <TCollection_HAsciiString.hxx>
 
 #include <OpenGl_FontMgr.hxx>
-
+#include <OpenGl_PrinterContext.hxx>
 #include <OpenGl_AspectText.hxx>
 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
 #ifdef HAVE_GL2PS
 #include <gl2ps.h>
 #endif
@@ -201,6 +221,277 @@ void OpenGl_Display::StringSize (const wchar_t *str, int &width, int &ascent, in
   }
 }
 
+/*
+  Class       : MultilineTextRenderer
+  Description : Class for constructing text and multi-line text
+*/
+
+class MultilineTextRenderer
+{
+  private:
+
+  Standard_Integer        myLFNum;        // Number of '\n' (Line Feed) '\x00\x0A' 
+  Standard_Integer        myCurrPos;      // Position of the current substring
+  Standard_Integer        myNewStrLen;    // Length of the new string 
+  Standard_Integer        mySubstrNum;    // Number of substrings
+  wchar_t                 *myNewStr;      // New string
+  const wchar_t           *myStrPtr;      // Pointer to the original string
+
+  public:
+
+  // ----------------------------------------------
+  // Function: MultilineTextRenderer
+  // Purpose:  Constructor with initialization
+  // ----------------------------------------------
+  MultilineTextRenderer ( const wchar_t           *theStr,
+                          GLdouble                &theXdis,
+                          GLdouble                &theYdis,
+                          const OpenGl_TextParam  *theParam,
+                          const FTFont            *theFnt,
+                          GLint                   theWidthFont,
+                          GLint                   theAscentFont,
+                          GLint                   theDescentFont ) :
+
+      myLFNum         (0),
+      myCurrPos       (0),
+      myNewStrLen     (0),
+      mySubstrNum     (0),
+      myNewStr        (0),
+      myStrPtr        (&theStr[0])
+  {
+    const Standard_Integer  aStrLen       = wcslen(theStr); // Length of the original string
+    Standard_Integer        aNextCRChar   = 0;  // Character after '\r' (Carriage Return)        '\x00\x0D'
+    Standard_Integer        aHTNum        = 0;  // Number of       '\t' (Horizontal Tabulation)  '\x00\x09'
+    Standard_Integer        aDumpNum      = 0;  // Number of '\a', '\b', '\v' and '\f'
+    Standard_Integer        anAllSpaces   = 0;  // Number of spaces instead of all '\t' characters
+    Standard_Integer        aMaxSubstrLen = 0;  // Length of the largest substring in the new string
+
+    Standard_Integer        aTimeVar      = 0;
+
+    // Calculation index after last '\r' character
+    for ( Standard_Integer anIndex = 0; anIndex < aStrLen; ++anIndex )
+    {
+      if ( theStr[anIndex] == '\r' )  aNextCRChar = anIndex+1;
+    }
+
+    // Calculation numbers of the some control characters
+    for (Standard_Integer anIndex = aNextCRChar; anIndex < aStrLen; anIndex++)
+    {
+      ++aTimeVar;
+      switch ( theStr[anIndex] )
+      {
+      case '\n':
+        ++myLFNum;
+        aTimeVar = 0;
+        break;
+      case '\b':
+      case '\v':
+      case '\f':
+      case '\a':
+        ++aDumpNum;
+        --aTimeVar;
+        break;
+      case '\t':
+        ++aHTNum;
+        anAllSpaces += ( 8 - ( aTimeVar - 1 )%8 );
+        aTimeVar = 0;
+        break;
+      }
+    }
+
+    // Calculation length of the new string
+    myStrPtr += aNextCRChar;
+    myNewStrLen = aStrLen - aNextCRChar + anAllSpaces - aHTNum - aDumpNum;
+
+    myNewStr = new wchar_t[myNewStrLen + 1];
+    myNewStr[myNewStrLen]='\0';
+
+    CalcString (aStrLen, aMaxSubstrLen);
+    CalcHAlign (theXdis, theParam, theWidthFont, aStrLen, aMaxSubstrLen);
+    CalcVAlign (theYdis, theParam, theFnt, theAscentFont, theDescentFont);
+  }
+
+  // ----------------------------------------------
+  // Function: ~MultilineTextRenderer
+  // Purpose:  Default destructor
+  // ----------------------------------------------
+  ~MultilineTextRenderer ()
+  {
+    delete[] myNewStr;
+  }
+
+  // ----------------------------------------------
+  // Function: Next
+  // Purpose:  Calculate position of the next substring
+  // ----------------------------------------------
+  void Next ()
+  {
+    for ( Standard_Integer anIndex = 0; anIndex <= myNewStrLen; ++anIndex )
+    {
+      if ( myNewStr[myCurrPos + anIndex] == '\0' )
+      {
+        ++mySubstrNum;
+        myCurrPos += anIndex + 1;
+        break;
+      }
+    }
+  }
+
+  // ----------------------------------------------
+  // Function: More
+  // Purpose:  Calculate position of the next substring
+  // ----------------------------------------------
+  Standard_Boolean More ()
+  {
+    if ( mySubstrNum <= myLFNum )  return Standard_True;
+    else                           return Standard_False;
+  }
+
+  // ----------------------------------------------
+  // Function: GetValue
+  // Purpose:  Returns current substring
+  // ----------------------------------------------
+  wchar_t* GetValue ()
+  {
+    return ( myNewStr + myCurrPos );
+  }
+
+  private:
+
+  // ----------------------------------------------
+  // Function: CalcString
+  // Purpose:  Calculate new string separated by '\0' without '\n', '\t', '\b', '\v', '\f', '\a'
+  // ----------------------------------------------
+  void CalcString ( const Standard_Integer theStrLen, Standard_Integer &theMaxSubstrLen )
+  {
+    Standard_Integer
+        aHelpIndex  = 0,
+        aTimeVar    = 0,
+        aSpacesNum  = 0;
+
+    for ( Standard_Integer anIndex1 = 0, anIndex2 = 0;
+          (anIndex1 < theStrLen)&&(anIndex2 < myNewStrLen);
+          ++anIndex1, ++anIndex2 )
+    {
+      ++aTimeVar;
+
+      if ( *(myStrPtr + anIndex1) == '\n' ) aTimeVar = 0;
+
+      while ( (*(myStrPtr + anIndex1)=='\b')||(*(myStrPtr + anIndex1)=='\f')
+            ||(*(myStrPtr + anIndex1)=='\v')||(*(myStrPtr + anIndex1)=='\a') )
+      {
+        ++anIndex1;
+      }
+
+      if ( *(myStrPtr + anIndex1) == '\t' )
+      {
+        aSpacesNum = ( 8 - ( aTimeVar - 1 )%8 );
+
+        for ( aHelpIndex = 0; aHelpIndex < aSpacesNum; aHelpIndex++ )
+        {
+          myNewStr[anIndex2 + aHelpIndex] = ' ';
+        }
+        anIndex2 += aHelpIndex - 1;
+        aTimeVar = 0;
+      }
+      else 
+      {
+        myNewStr[anIndex2] = *(myStrPtr + anIndex1);
+      }
+    }
+
+    // After this part of code we will have a string separated by '\0' characters
+    Standard_Integer aHelpLength = 0;
+
+    if( myNewStr )
+    {
+      for( Standard_Integer anIndex = 0; anIndex <= myNewStrLen; ++anIndex )
+      {
+        if ( myNewStr[anIndex] == '\n' )
+        {
+          myNewStr[anIndex] = '\0';
+        }
+
+        // Calculating length of the largest substring of the new string.
+        // It's needed for horizontal alignment
+        if ( myNewStr[anIndex] != '\0' )
+        {
+          ++aHelpLength;
+        }
+        else
+        {
+          if ( aHelpLength > theMaxSubstrLen ) theMaxSubstrLen = aHelpLength;
+
+          aHelpLength = 0;
+        }
+      }
+    }
+  }
+
+  // ----------------------------------------------
+  // Function: CalcVAlign
+  // Purpose:  Calculate vertical alignment for text
+  // ----------------------------------------------
+  void CalcVAlign ( GLdouble                &theYdis,
+                    const OpenGl_TextParam  *theParam,
+                    const FTFont            *theFnt,
+                    GLint                   theAscentFont,
+                    GLint                   theDescentFont )
+  {
+    switch (theParam->VAlign)
+    {
+    case Graphic3d_VTA_BOTTOM:
+      theYdis = (GLdouble)(myLFNum * theFnt->FaceSize());
+      break;
+    case Graphic3d_VTA_CENTER:
+      if ( (myLFNum%2) == 0 )   // An odd number of strings
+      {
+        theYdis = (GLdouble)((myLFNum/2.0) * theFnt->FaceSize()) + theDescentFont; 
+      }
+      else                      // An even number of strings
+      {
+        theYdis = (GLdouble)((myLFNum - 1)/2.0 * theFnt->FaceSize()) - theDescentFont/2.0;
+      }
+      break;
+    case Graphic3d_VTA_TOP:
+      theYdis = -(GLdouble)theAscentFont - theDescentFont;
+      break;
+    default:
+      theYdis = (GLdouble)(myLFNum * theFnt->FaceSize());
+      break;
+    }
+  }
+
+  // ----------------------------------------------
+  // Function: CalcHAlign
+  // Purpose:  Calculate horizontal alignment for text
+  // ----------------------------------------------
+  void CalcHAlign ( GLdouble                &theXdis,
+                    const OpenGl_TextParam  *theParam,
+                    GLint                   theWidthFont,
+                    const Standard_Integer  theStrLen,
+                    Standard_Integer        theMaxSubstrLen)
+  {
+    GLdouble aWidth = (GLdouble)(theMaxSubstrLen * theWidthFont)/theStrLen;
+
+    switch (theParam->HAlign)
+    {
+    case Graphic3d_HTA_LEFT:
+      theXdis = 0.;
+      break;
+    case Graphic3d_HTA_CENTER:
+      theXdis = -0.5 * (GLdouble)aWidth;
+      break;
+    case Graphic3d_HTA_RIGHT:
+      theXdis = -(GLdouble)aWidth;
+      break;
+    default:
+      theXdis = 0.;
+      break;
+    }
+  }
+};
+
 /*-----------------------------------------------------------------------------*/
 
 void OpenGl_Display::RenderText (const wchar_t* str, const int is2d, const float x, const float y, const float z,
@@ -217,33 +508,19 @@ void OpenGl_Display::RenderText (const wchar_t* str, const int is2d, const float
   int widthFont, ascentFont, descentFont;
   StringSize( str, widthFont, ascentFont, descentFont );
 
-  GLdouble xdis = 0.;
-  switch (param->HAlign)
-  {
-    case Graphic3d_HTA_CENTER:
-      xdis = -0.5 * (GLdouble)widthFont;
-      break;
-    case Graphic3d_HTA_RIGHT:
-      xdis = -(GLdouble)widthFont;
-      break;
-    //case Graphic3d_HTA_LEFT:
-    //default: break;
-  }
-  GLdouble ydis = 0.;
-  switch (param->VAlign)
-  {
-    case Graphic3d_VTA_CENTER:
-      ydis = -0.5 * (GLdouble)ascentFont - descentFont;
-      break;
-    case Graphic3d_VTA_TOP:
-      ydis = -(GLdouble)ascentFont - descentFont;
-      break;
-    //case Graphic3d_VTA_BOTTOM:
-    //default: break;
-  }
+  GLdouble xdis = 0., ydis = 0.;
 
   float export_h = 1.;
 
+  MultilineTextRenderer aRenderer( str,
+                                   xdis,
+                                   ydis,
+                                   param,
+                                   fnt,
+                                   widthFont,
+                                   ascentFont,
+                                   descentFont );
+
   glMatrixMode(GL_MODELVIEW);
   glPushMatrix();
   if (is2d)
@@ -297,11 +574,27 @@ void OpenGl_Display::RenderText (const wchar_t* str, const int is2d, const float
 
     if( !aspect->IsZoomable() )
     {
+#ifdef WNT
+      // if the context has assigned printer context, use it's parameters
+      OpenGl_PrinterContext* aPrinterContext = 
+        OpenGl_PrinterContext::GetPrinterContext( GET_GL_CONTEXT() );
+      if( aPrinterContext )
+      {
+        // get printing scaling in x and y dimensions
+        GLfloat aTextScalex = 1, aTextScaley = 1;
+        aPrinterContext->GetScale( aTextScalex, aTextScaley );
+        
+        // text should be scaled in all directions with same
+        // factor to save its proportions, so use height (y) scaling
+        // as it is better for keeping text/3d graphics proportions
+        glScalef( aTextScaley, aTextScaley, aTextScaley );
+      }
+#endif
       glScaled( h, h, h );
     }
     else
     {
-      export_h = (float )h;
+      export_h = (float)h;
     }
   }
 
@@ -311,47 +604,34 @@ void OpenGl_Display::RenderText (const wchar_t* str, const int is2d, const float
   {
 #ifdef HAVE_GL2PS
     export_h = (float)fnt->FaceSize() / export_h;
-    glPopMatrix();
-    ExportText( str, is2d, x, y, z, aspect, param, (short)export_h );
+    for ( ; aRenderer.More(); aRenderer.Next() )
+    {
+      // x, y, z coordinates are used here as zero values, because position of the text
+      // and alignment is calculated in the code above using glTranslated methods
+      ExportText( aRenderer.GetValue(), is2d, 0, 0, 0, aspect, param, (short)export_h );
+      glTranslated(0, -(GLdouble)fnt->FaceSize(), 0);
+    }
 #endif
   }
   else
   {
-    mgr->render_text( myFont, str, is2d );
-    glPopMatrix();
+    for ( ; aRenderer.More(); aRenderer.Next() )
+    {
+      mgr->render_text( myFont, aRenderer.GetValue(), is2d );
+      glTranslated(0, -(GLdouble)fnt->FaceSize(), 0);
+    }
   }
+  glPopMatrix();
   glPopAttrib();
 }
 
 /*-----------------------------------------------------------------------------*/
 
-static const int alignmentforgl2ps[3][3] = { {5,2,8}, {4,1,7}, {6,3,9} };
-
 void OpenGl_Display::ExportText (const wchar_t* text, const int is2d, const float x, const float y, const float z,
                                 const OpenGl_AspectText *aspect, const OpenGl_TextParam *param, const short height)
 {
 #ifdef HAVE_GL2PS
 
-  int vh = 1;
-  switch (param->HAlign)
-  {
-    case Graphic3d_HTA_CENTER: vh = 2; break;
-    case Graphic3d_HTA_RIGHT: vh = 3; break;
-    //case Graphic3d_HTA_LEFT:
-    //default: break;
-  }
-
-  int vv = 1;
-  switch (param->VAlign)
-  {
-    case Graphic3d_VTA_CENTER: vv = 2; break;
-    case Graphic3d_VTA_TOP: vv = 3; break;
-    //case Graphic3d_VTA_BOTTOM:
-    //default: break;
-  }
-
-  const int alignment = alignmentforgl2ps[vh-1][vv-1];
-
   const char* fontname = aspect->Font();
   float angle = aspect->Angle();
 
@@ -371,7 +651,11 @@ void OpenGl_Display::ExportText (const wchar_t* text, const int is2d, const floa
   const int len = 4 * (wcslen(text) + 1); //szv: should be more than enough
   char *astr = new char[len];
   wcstombs(astr,text,len);
-  gl2psTextOpt(astr, ps_font, height, alignment, angle);
+
+  // Standard GL2PS's alignment isn't used, because it doesn't work correctly
+  // for all formats, therefore alignment is calculated manually relative
+  // to the bottom-left corner, which corresponds to the GL2PS_TEXT_BL value
+  gl2psTextOpt(astr, ps_font, height, GL2PS_TEXT_BL, angle);
   delete[] astr;
 
 #endif