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