0022752: Fix compilation on Unix with FreeImage and GL2PS support
[occt.git] / src / OpenGl / OpenGl_Display_1.cxx
CommitLineData
b311480e 1// Created on: 2011-10-25
2// Created by: Sergey ZERCHANINOV
3// Copyright (c) 2011-2012 OPEN CASCADE SAS
4//
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.
9//
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.
12//
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.
19
2166f0fa 20
4dd0865c 21#include <InterfaceGraphic.hxx>
2166f0fa
SK
22#include <OpenGl_Display.hxx>
23
24#include <TCollection_AsciiString.hxx>
25#include <TCollection_HAsciiString.hxx>
26
27#include <OpenGl_FontMgr.hxx>
34a44cbd 28#include <OpenGl_PrinterContext.hxx>
2166f0fa
SK
29#include <OpenGl_AspectText.hxx>
30
498ce577 31#ifdef HAVE_CONFIG_H
32# include <config.h>
33#endif
34
2166f0fa
SK
35#ifdef HAVE_GL2PS
36#include <gl2ps.h>
37#endif
38
39/*-----------------------------------------------------------------------------*/
40/*
41* Prototypes variables statiques
42*/
43
44struct FontMapNode
45{
46 const char * EnumName;
47 const char * FontName;
48 OSD_FontAspect FontAspect;
49};
50
51static const FontMapNode myFontMap[] =
52{
53
54#ifdef WNT
55
56 { "Courier" , "Courier New" , OSD_FA_Regular },
57 { "Times-Roman" , "Times New Roman", OSD_FA_Regular },
58 { "Times-Bold" , "Times New Roman", OSD_FA_Bold },
59 { "Times-Italic" , "Times New Roman", OSD_FA_Italic },
60 { "Times-BoldItalic" , "Times New Roman", OSD_FA_BoldItalic },
61 { "ZapfChancery-MediumItalic", "Script" , OSD_FA_Regular },
62 { "Symbol" , "Symbol" , OSD_FA_Regular },
63 { "ZapfDingbats" , "WingDings" , OSD_FA_Regular },
64 { "Rock" , "Arial" , OSD_FA_Regular },
65 { "Iris" , "Lucida Console" , OSD_FA_Regular }
66
67#else //X11
68
69 { "Courier" , "Courier" , OSD_FA_Regular },
70 { "Times-Roman" , "Times" , OSD_FA_Regular },
71 { "Times-Bold" , "Times" , OSD_FA_Bold },
72 { "Times-Italic" , "Times" , OSD_FA_Italic },
73 { "Times-BoldItalic" , "Times" , OSD_FA_BoldItalic },
74 { "Arial" , "Helvetica" , OSD_FA_Regular },
75 { "ZapfChancery-MediumItalic", "-adobe-itc zapf chancery-medium-i-normal--*-*-*-*-*-*-iso8859-1" , OSD_FA_Regular },
76 { "Symbol" , "-adobe-symbol-medium-r-normal--*-*-*-*-*-*-adobe-fontspecific" , OSD_FA_Regular },
77 { "ZapfDingbats" , "-adobe-itc zapf dingbats-medium-r-normal--*-*-*-*-*-*-adobe-fontspecific" , OSD_FA_Regular },
78 { "Rock" , "-sgi-rock-medium-r-normal--*-*-*-*-p-*-iso8859-1" , OSD_FA_Regular },
79 { "Iris" , "--iris-medium-r-normal--*-*-*-*-m-*-iso8859-1" , OSD_FA_Regular }
80#endif
81
82};
83
84#define NUM_FONT_ENTRIES (sizeof(myFontMap)/sizeof(FontMapNode))
85
86/*-----------------------------------------------------------------------------*/
87
88/*
89* Constants
90*/
91
92#ifdef HAVE_GL2PS
93void OpenGl_Display::getGL2PSFontName (const char *src_font, char *ps_font)
94{
95 /*
96 Convert font name used for rendering to some "good" font names
97 that produce good vector text
98 */
99 static char const *family[] = {"Helvetica", "Courier", "Times"};
100 static char const *italic[] = {"Oblique", "Oblique", "Italic"};
101 static char const *base[] = {"", "", "-Roman"};
102
103 int font = 0;
104 int isBold = 0;
105 int isItalic = 0;
106
107 if( strstr( src_font, "Symbol" ) ){
108 sprintf( ps_font, "%s", "Symbol" );
109 return;
110 }
111
112 if( strstr( src_font, "ZapfDingbats" ) ){
113 sprintf( ps_font, "%s", "WingDings" );
114 return;
115 }
116
117 if ( strstr( src_font, "Courier" ) ){
118 font = 1;
119 }
120 else if ( strstr( src_font, "Times" ) ){
121 font = 2;
122 }
123
124 if ( strstr( src_font, "Bold" ) ){
125 isBold = 1;
126 }
127
128 if ( strstr( src_font, "Italic" ) || strstr( src_font, "Oblique" ) ){
129 isItalic = 1;
130 }
131
132 if ( isBold ){
133 sprintf( ps_font, "%s-%s", family[font], "Bold");
134 if ( isItalic ){
135 sprintf(ps_font, "%s%s", ps_font, italic[font]);
136 }
137 }
138 else if ( isItalic )
139 {
140 sprintf( ps_font, "%s-%s", family[font], italic[font] );
141 }
142 else
143 {
144 sprintf( ps_font, "%s%s", family[font], base[font] );
145 }
146}
147#endif
148
149/*-----------------------------------------------------------------------------*/
150
151/*
152* Fonctions publiques
153*/
154
155/*-----------------------------------------------------------------------------*/
156
157int OpenGl_Display::FindFont (const char* AFontName, const OSD_FontAspect AFontAspect,
158 const int ABestSize, const float AXScale, const float AYScale)
159{
160 if (!AFontName)
161 return -1;
162
163 if (ABestSize != -1)
164 myFontSize = ABestSize;
165
166 OpenGl_FontMgr* mgr = OpenGl_FontMgr::instance();
167
168 Handle(TCollection_HAsciiString) family_name = new TCollection_HAsciiString(AFontName);
169 myFont = mgr->request_font( family_name, AFontAspect, myFontSize );
170
171 if( myFont == -1 )
172 {
173 //try to use font names mapping
174 FontMapNode newTempFont = myFontMap[0];
175 for ( int i = 0; i < NUM_FONT_ENTRIES; ++i )
176 {
177 if ( TCollection_AsciiString(myFontMap[i].EnumName).IsEqual( family_name->ToCString() ) )
178 {
179 newTempFont = myFontMap[i];
180 break;
181 }
182 }
183 family_name = new TCollection_HAsciiString(newTempFont.FontName);
184 myFont = mgr->request_font( family_name, newTempFont.FontAspect, myFontSize );
185 }
186
187 // Requested family name not found -> serach for any font family with given aspect and height
188 if ( myFont == -1 )
189 {
190 family_name = new TCollection_HAsciiString( "" );
191 myFont = mgr->request_font( family_name, AFontAspect, myFontSize );
192 }
193
194 // The last resort: trying to use ANY font available in the system
195 if ( myFont == -1 )
196 {
197 myFont = mgr->request_font( family_name, OSD_FA_Undefined, -1 );
198 }
199
200 if ( myFont != -1 )
201 mgr->setCurrentScale( AXScale, AYScale );
202
203 return myFont;
204}
205
206/*-----------------------------------------------------------------------------*/
207
208void OpenGl_Display::StringSize (const wchar_t *str, int &width, int &ascent, int &descent)
209{
210 ascent = 0;
211 descent = 0;
212 width = 0;
213 if (myFont != -1) {
214 OpenGl_FontMgr* mgr = OpenGl_FontMgr::instance();
215 const FTFont* font = mgr->fontById( myFont );
216 if ( font ) {
217 width = int( mgr->computeWidth( myFont, str ) );
218 ascent = int( font->Ascender() );
219 descent = int( font->Descender() );
220 }
221 }
222}
223
f3f08423 224/*
225 Class : MultilineTextRenderer
226 Description : Class for constructing text and multi-line text
227*/
228
229class MultilineTextRenderer
230{
231 private:
232
233 Standard_Integer myLFNum; // Number of '\n' (Line Feed) '\x00\x0A'
234 Standard_Integer myCurrPos; // Position of the current substring
235 Standard_Integer myNewStrLen; // Length of the new string
236 Standard_Integer mySubstrNum; // Number of substrings
237 wchar_t *myNewStr; // New string
238 const wchar_t *myStrPtr; // Pointer to the original string
239
240 public:
241
242 // ----------------------------------------------
243 // Function: MultilineTextRenderer
244 // Purpose: Constructor with initialization
245 // ----------------------------------------------
246 MultilineTextRenderer ( const wchar_t *theStr,
247 GLdouble &theXdis,
248 GLdouble &theYdis,
249 const OpenGl_TextParam *theParam,
250 const FTFont *theFnt,
251 GLint theWidthFont,
252 GLint theAscentFont,
253 GLint theDescentFont ) :
254
255 myLFNum (0),
256 myCurrPos (0),
257 myNewStrLen (0),
258 mySubstrNum (0),
259 myNewStr (0),
260 myStrPtr (&theStr[0])
261 {
262 const Standard_Integer aStrLen = wcslen(theStr); // Length of the original string
263 Standard_Integer aNextCRChar = 0; // Character after '\r' (Carriage Return) '\x00\x0D'
264 Standard_Integer aHTNum = 0; // Number of '\t' (Horizontal Tabulation) '\x00\x09'
265 Standard_Integer aDumpNum = 0; // Number of '\a', '\b', '\v' and '\f'
266 Standard_Integer anAllSpaces = 0; // Number of spaces instead of all '\t' characters
267 Standard_Integer aMaxSubstrLen = 0; // Length of the largest substring in the new string
268
269 Standard_Integer aTimeVar = 0;
270
271 // Calculation index after last '\r' character
272 for ( Standard_Integer anIndex = 0; anIndex < aStrLen; ++anIndex )
273 {
274 if ( theStr[anIndex] == '\r' ) aNextCRChar = anIndex+1;
275 }
276
277 // Calculation numbers of the some control characters
278 for (Standard_Integer anIndex = aNextCRChar; anIndex < aStrLen; anIndex++)
279 {
280 ++aTimeVar;
281 switch ( theStr[anIndex] )
282 {
283 case '\n':
284 ++myLFNum;
285 aTimeVar = 0;
286 break;
287 case '\b':
288 case '\v':
289 case '\f':
290 case '\a':
291 ++aDumpNum;
292 --aTimeVar;
293 break;
294 case '\t':
295 ++aHTNum;
296 anAllSpaces += ( 8 - ( aTimeVar - 1 )%8 );
297 aTimeVar = 0;
298 break;
299 }
300 }
301
302 // Calculation length of the new string
303 myStrPtr += aNextCRChar;
304 myNewStrLen = aStrLen - aNextCRChar + anAllSpaces - aHTNum - aDumpNum;
305
306 myNewStr = new wchar_t[myNewStrLen + 1];
307 myNewStr[myNewStrLen]='\0';
308
309 CalcString (aStrLen, aMaxSubstrLen);
310 CalcHAlign (theXdis, theParam, theWidthFont, aStrLen, aMaxSubstrLen);
311 CalcVAlign (theYdis, theParam, theFnt, theAscentFont, theDescentFont);
312 }
313
314 // ----------------------------------------------
315 // Function: ~MultilineTextRenderer
316 // Purpose: Default destructor
317 // ----------------------------------------------
318 ~MultilineTextRenderer ()
319 {
320 delete[] myNewStr;
321 }
322
323 // ----------------------------------------------
324 // Function: Next
325 // Purpose: Calculate position of the next substring
326 // ----------------------------------------------
327 void Next ()
328 {
329 for ( Standard_Integer anIndex = 0; anIndex <= myNewStrLen; ++anIndex )
330 {
331 if ( myNewStr[myCurrPos + anIndex] == '\0' )
332 {
333 ++mySubstrNum;
334 myCurrPos += anIndex + 1;
335 break;
336 }
337 }
338 }
339
340 // ----------------------------------------------
341 // Function: More
342 // Purpose: Calculate position of the next substring
343 // ----------------------------------------------
344 Standard_Boolean More ()
345 {
346 if ( mySubstrNum <= myLFNum ) return Standard_True;
347 else return Standard_False;
348 }
349
350 // ----------------------------------------------
351 // Function: GetValue
352 // Purpose: Returns current substring
353 // ----------------------------------------------
354 wchar_t* GetValue ()
355 {
356 return ( myNewStr + myCurrPos );
357 }
358
359 private:
360
361 // ----------------------------------------------
362 // Function: CalcString
363 // Purpose: Calculate new string separated by '\0' without '\n', '\t', '\b', '\v', '\f', '\a'
364 // ----------------------------------------------
365 void CalcString ( const Standard_Integer theStrLen, Standard_Integer &theMaxSubstrLen )
366 {
367 Standard_Integer
368 aHelpIndex = 0,
369 aTimeVar = 0,
370 aSpacesNum = 0;
371
372 for ( Standard_Integer anIndex1 = 0, anIndex2 = 0;
373 (anIndex1 < theStrLen)&&(anIndex2 < myNewStrLen);
374 ++anIndex1, ++anIndex2 )
375 {
376 ++aTimeVar;
377
378 if ( *(myStrPtr + anIndex1) == '\n' ) aTimeVar = 0;
379
380 while ( (*(myStrPtr + anIndex1)=='\b')||(*(myStrPtr + anIndex1)=='\f')
381 ||(*(myStrPtr + anIndex1)=='\v')||(*(myStrPtr + anIndex1)=='\a') )
382 {
383 ++anIndex1;
384 }
385
386 if ( *(myStrPtr + anIndex1) == '\t' )
387 {
388 aSpacesNum = ( 8 - ( aTimeVar - 1 )%8 );
389
390 for ( aHelpIndex = 0; aHelpIndex < aSpacesNum; aHelpIndex++ )
391 {
392 myNewStr[anIndex2 + aHelpIndex] = ' ';
393 }
394 anIndex2 += aHelpIndex - 1;
395 aTimeVar = 0;
396 }
397 else
398 {
399 myNewStr[anIndex2] = *(myStrPtr + anIndex1);
400 }
401 }
402
403 // After this part of code we will have a string separated by '\0' characters
404 Standard_Integer aHelpLength = 0;
405
406 if( myNewStr )
407 {
408 for( Standard_Integer anIndex = 0; anIndex <= myNewStrLen; ++anIndex )
409 {
410 if ( myNewStr[anIndex] == '\n' )
411 {
412 myNewStr[anIndex] = '\0';
413 }
414
415 // Calculating length of the largest substring of the new string.
416 // It's needed for horizontal alignment
417 if ( myNewStr[anIndex] != '\0' )
418 {
419 ++aHelpLength;
420 }
421 else
422 {
423 if ( aHelpLength > theMaxSubstrLen ) theMaxSubstrLen = aHelpLength;
424
425 aHelpLength = 0;
426 }
427 }
428 }
429 }
430
431 // ----------------------------------------------
432 // Function: CalcVAlign
433 // Purpose: Calculate vertical alignment for text
434 // ----------------------------------------------
435 void CalcVAlign ( GLdouble &theYdis,
436 const OpenGl_TextParam *theParam,
437 const FTFont *theFnt,
438 GLint theAscentFont,
439 GLint theDescentFont )
440 {
441 switch (theParam->VAlign)
442 {
443 case Graphic3d_VTA_BOTTOM:
444 theYdis = (GLdouble)(myLFNum * theFnt->FaceSize());
445 break;
446 case Graphic3d_VTA_CENTER:
447 if ( (myLFNum%2) == 0 ) // An odd number of strings
448 {
449 theYdis = (GLdouble)((myLFNum/2.0) * theFnt->FaceSize()) + theDescentFont;
450 }
451 else // An even number of strings
452 {
453 theYdis = (GLdouble)((myLFNum - 1)/2.0 * theFnt->FaceSize()) - theDescentFont/2.0;
454 }
455 break;
456 case Graphic3d_VTA_TOP:
457 theYdis = -(GLdouble)theAscentFont - theDescentFont;
458 break;
459 default:
460 theYdis = (GLdouble)(myLFNum * theFnt->FaceSize());
461 break;
462 }
463 }
464
465 // ----------------------------------------------
466 // Function: CalcHAlign
467 // Purpose: Calculate horizontal alignment for text
468 // ----------------------------------------------
469 void CalcHAlign ( GLdouble &theXdis,
470 const OpenGl_TextParam *theParam,
471 GLint theWidthFont,
472 const Standard_Integer theStrLen,
473 Standard_Integer theMaxSubstrLen)
474 {
475 GLdouble aWidth = (GLdouble)(theMaxSubstrLen * theWidthFont)/theStrLen;
476
477 switch (theParam->HAlign)
478 {
479 case Graphic3d_HTA_LEFT:
480 theXdis = 0.;
481 break;
482 case Graphic3d_HTA_CENTER:
483 theXdis = -0.5 * (GLdouble)aWidth;
484 break;
485 case Graphic3d_HTA_RIGHT:
486 theXdis = -(GLdouble)aWidth;
487 break;
488 default:
489 theXdis = 0.;
490 break;
491 }
492 }
493};
494
2166f0fa
SK
495/*-----------------------------------------------------------------------------*/
496
497void OpenGl_Display::RenderText (const wchar_t* str, const int is2d, const float x, const float y, const float z,
498 const OpenGl_AspectText *aspect, const OpenGl_TextParam *param)
499{
500 OpenGl_FontMgr* mgr = OpenGl_FontMgr::instance();
501 const FTFont* fnt = mgr->fontById( myFont );
502 if ( !fnt )
503 return;
504
505 // FTFont changes texture state when it renders and computes size for the text
506 glPushAttrib(GL_TEXTURE_BIT);
507
508 int widthFont, ascentFont, descentFont;
509 StringSize( str, widthFont, ascentFont, descentFont );
510
f3f08423 511 GLdouble xdis = 0., ydis = 0.;
2166f0fa
SK
512
513 float export_h = 1.;
514
f3f08423 515 MultilineTextRenderer aRenderer( str,
516 xdis,
517 ydis,
518 param,
519 fnt,
520 widthFont,
521 ascentFont,
522 descentFont );
523
2166f0fa
SK
524 glMatrixMode(GL_MODELVIEW);
525 glPushMatrix();
526 if (is2d)
527 {
528 glLoadIdentity();
529 glTranslatef(x, y, 0.f);
530 glRotatef( 180, 1, 0, 0 );
531 }
532 else
533 {
534 const GLdouble identityMatrix[4][4] =
535 {
536 {1.,0.,0.,0.},
537 {0.,1.,0.,0.},
538 {0.,0.,1.,0.},
539 {0.,0.,0.,1.}
540 };
541
542 GLdouble projMatrix[4][4], modelMatrix[4][4];
543 GLint viewport[4];
544
545 GLdouble wx, wy, wz;
546 GLdouble x1, y1, z1;
547 GLdouble x2, y2, z2;
548
549 glGetDoublev( GL_MODELVIEW_MATRIX, (GLdouble*)modelMatrix );
550 glGetDoublev( GL_PROJECTION_MATRIX, (GLdouble*)projMatrix );
551 glGetIntegerv( GL_VIEWPORT, (GLint*)viewport );
552
553 gluProject( x, y, z,
554 (GLdouble*)modelMatrix,
555 (GLdouble*)projMatrix,
556 (GLint*)viewport,
557 &wx, &wy, &wz );
558 glLoadIdentity();
559 gluUnProject( wx, wy, wz,
560 (GLdouble*)identityMatrix, (GLdouble*)projMatrix, (GLint*)viewport,
561 &x1, &y1 , &z1 );
562
563 GLdouble h = (GLdouble)fnt->FaceSize();
564
565 gluUnProject( wx, wy + h - 1., wz,
566 (GLdouble*)identityMatrix, (GLdouble*)projMatrix, (GLint*)viewport,
567 &x2, &y2, &z2 );
568
569 h = (y2-y1)/h;
570
571 glTranslated( x1, y1 , z1 );
572 glRotated(aspect->Angle(), 0, 0, 1);
573 glTranslated(xdis, ydis, 0);
574
575 if( !aspect->IsZoomable() )
576 {
34a44cbd 577#ifdef WNT
578 // if the context has assigned printer context, use it's parameters
579 OpenGl_PrinterContext* aPrinterContext =
580 OpenGl_PrinterContext::GetPrinterContext( GET_GL_CONTEXT() );
581 if( aPrinterContext )
582 {
583 // get printing scaling in x and y dimensions
584 GLfloat aTextScalex = 1, aTextScaley = 1;
585 aPrinterContext->GetScale( aTextScalex, aTextScaley );
586
587 // text should be scaled in all directions with same
588 // factor to save its proportions, so use height (y) scaling
589 // as it is better for keeping text/3d graphics proportions
590 glScalef( aTextScaley, aTextScaley, aTextScaley );
591 }
592#endif
2166f0fa
SK
593 glScaled( h, h, h );
594 }
595 else
596 {
f3f08423 597 export_h = (float)h;
2166f0fa
SK
598 }
599 }
600
601 GLint renderMode;
602 glGetIntegerv(GL_RENDER_MODE, &renderMode);
603 if ( renderMode == GL_FEEDBACK )
604 {
605#ifdef HAVE_GL2PS
c320e557 606 export_h = (float)fnt->FaceSize() / export_h;
f3f08423 607 for ( ; aRenderer.More(); aRenderer.Next() )
608 {
609 // x, y, z coordinates are used here as zero values, because position of the text
610 // and alignment is calculated in the code above using glTranslated methods
611 ExportText( aRenderer.GetValue(), is2d, 0, 0, 0, aspect, param, (short)export_h );
612 glTranslated(0, -(GLdouble)fnt->FaceSize(), 0);
613 }
2166f0fa
SK
614#endif
615 }
616 else
617 {
f3f08423 618 for ( ; aRenderer.More(); aRenderer.Next() )
619 {
620 mgr->render_text( myFont, aRenderer.GetValue(), is2d );
621 glTranslated(0, -(GLdouble)fnt->FaceSize(), 0);
622 }
2166f0fa 623 }
f3f08423 624 glPopMatrix();
2166f0fa
SK
625 glPopAttrib();
626}
627
628/*-----------------------------------------------------------------------------*/
629
2166f0fa 630void OpenGl_Display::ExportText (const wchar_t* text, const int is2d, const float x, const float y, const float z,
c320e557 631 const OpenGl_AspectText *aspect, const OpenGl_TextParam *param, const short height)
2166f0fa
SK
632{
633#ifdef HAVE_GL2PS
634
2166f0fa
SK
635 const char* fontname = aspect->Font();
636 float angle = aspect->Angle();
637
638 GLubyte zero = 0;
639 char ps_font[64];
640
641 getGL2PSFontName(fontname, ps_font);
642
643 if( is2d )
644 glRasterPos2f( x, y );
645 else
646 glRasterPos3f( x, y, z );
647
648 glBitmap( 1, 1, 0, 0, 0, 0, &zero );
649
650 //szv: workaround for gl2ps!
651 const int len = 4 * (wcslen(text) + 1); //szv: should be more than enough
652 char *astr = new char[len];
653 wcstombs(astr,text,len);
f3f08423 654
655 // Standard GL2PS's alignment isn't used, because it doesn't work correctly
656 // for all formats, therefore alignment is calculated manually relative
657 // to the bottom-left corner, which corresponds to the GL2PS_TEXT_BL value
658 gl2psTextOpt(astr, ps_font, height, GL2PS_TEXT_BL, angle);
2166f0fa
SK
659 delete[] astr;
660
661#endif
662}