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