0023457: Slow text rendering
[occt.git] / src / OpenGl / OpenGl_Workspace_2.cxx
1 // Created on: 2011-09-20
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
20
21 #include <OpenGl_GlCore11.hxx>
22
23 #include <OpenGl_FrameBuffer.hxx>
24 #include <TColStd_Array2OfReal.hxx>
25 #include <OpenGl_telem_util.hxx>
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 #if (defined(_WIN32) || defined(__WIN32__)) && defined(HAVE_FREEIMAGE)
32   #include <NCollection_Handle.hxx>
33   #include <FreeImagePlus.h>
34   #ifdef _MSC_VER
35     #pragma comment( lib, "FreeImage.lib" )
36     #pragma comment( lib, "FreeImagePlus.lib" )
37   #endif
38   typedef NCollection_Handle<fipImage> FipHandle;
39 #endif
40
41 #include <OpenGl_PrinterContext.hxx>
42 #include <OpenGl_Workspace.hxx>
43 #include <OpenGl_View.hxx>
44 #include <OpenGl_Display.hxx>
45
46 //10-05-96 : CAL ; Ajout d'un nouveau delta dans les copies de pixels (voir CALL_DEF_DELTA)
47 #define CALL_DEF_DELTA 10
48
49 // ---------------------------------------------------------------
50 // Function: getNearestPowOfTwo
51 // Purpose:  get the nearest power of two for theNumber
52 // ---------------------------------------------------------------
53 static GLsizei getNearestPowOfTwo (const GLsizei theNumber)
54 {
55   GLsizei aLast = 1;
56   for (GLsizei p2 = 1; p2 <= theNumber; aLast = p2, p2 <<= 1);
57   return aLast;
58 }
59
60 // ---------------------------------------------------------------
61 // Function: getMaxFrameSize
62 // Purpose:  get the maximum possible frame size
63 // ---------------------------------------------------------------
64 static void getMaxFrameSize(Standard_Integer& theWidth,
65                             Standard_Integer& theHeight)
66 {
67   GLsizei aMaxX, aMaxY;
68   GLint aVpDim[2];
69   GLint aTexDim = 2048;
70   glGetIntegerv (GL_MAX_VIEWPORT_DIMS, (GLint*) &aVpDim);
71   glGetIntegerv (GL_MAX_TEXTURE_SIZE, &aTexDim);
72   (aVpDim[0] >= aTexDim) ? aMaxX = (GLsizei) aTexDim :
73                            aMaxX = getNearestPowOfTwo((GLsizei)aVpDim[0]);
74   (aVpDim[1] >= aTexDim) ? aMaxY = (GLsizei) aTexDim :
75                            aMaxY = getNearestPowOfTwo((GLsizei)aVpDim[1]);
76
77   theWidth  = (Standard_Integer)aMaxX;
78   theHeight = (Standard_Integer)aMaxY;
79 }
80
81 // ---------------------------------------------------------------
82 // Function: fitDimensionsRatio
83 // Purpose:  calculate correct width/height ratio for theWidth and
84 //           theHeight parameters
85 // ---------------------------------------------------------------
86 static void fitDimensionsRatio (Standard_Integer& theWidth,
87                                 Standard_Integer& theHeight,
88                                 const Standard_Real theViewRatio)
89 {
90   // set dimensions in accordance with the viewratio
91   if (theHeight <  theWidth/theViewRatio)
92       theWidth  = (Standard_Integer)(theHeight*theViewRatio);
93
94   if (theWidth  <  theHeight*theViewRatio)
95       theHeight = (Standard_Integer)(theWidth/theViewRatio);
96 }
97
98 // ---------------------------------------------------------------
99 // Function: getDimensionsTiling
100 // Purpose:  calculate maximum possible dimensions for framebuffer
101 //           in tiling mode according to the view size
102 // ---------------------------------------------------------------
103 static void getDimensionsTiling (Standard_Integer& theFrameWidth,
104                                  Standard_Integer& theFrameHeight,
105                                  const int theViewWidth,
106                                  const int theViewHeight)
107 {
108   // fit the maximum dimensions into the printing area
109   if (theFrameWidth > theViewWidth)
110       theFrameWidth = theViewWidth;
111
112   if (theFrameHeight > theViewHeight)
113       theFrameHeight = theViewHeight;
114 }
115
116 // ---------------------------------------------------------------
117 // Function: initBufferStretch
118 // Purpose:  calculate initialization sizes for frame buffer
119 //           when the stretch algorithm is selected
120 // ---------------------------------------------------------------
121 static void initBufferStretch (Standard_Integer& theFrameWidth,
122                                Standard_Integer& theFrameHeight,
123                                const int theViewWidth,
124                                const int theViewHeight)
125 {
126
127   // Calculate correct width/height for framebuffer
128   Standard_Real aViewRatio = (Standard_Real)theViewWidth/theViewHeight;
129   fitDimensionsRatio (theFrameWidth, theFrameHeight, aViewRatio);
130
131   // downscale the framebuffer if it is too large
132   Standard_Real aWidthRate  = (Standard_Real)theFrameWidth /theViewWidth;
133   Standard_Real aHeightRate = (Standard_Real)theFrameHeight/theViewHeight;
134
135   if ((aWidthRate > 1 && aHeightRate > 1 && aWidthRate >= aHeightRate) ||
136       (aWidthRate > 1 && aHeightRate <= 1))
137   {
138     theFrameWidth  = (Standard_Integer)(theFrameWidth /aWidthRate);
139     theFrameHeight = (Standard_Integer)(theFrameHeight/aWidthRate);
140   }
141   else if ((aWidthRate  > 1 && aHeightRate > 1 && aWidthRate < aHeightRate) ||
142            (aWidthRate <= 1 && aHeightRate > 1))
143   {
144     theFrameWidth  = (Standard_Integer)(theFrameWidth /aHeightRate);
145     theFrameHeight = (Standard_Integer)(theFrameHeight/aHeightRate);
146   }
147
148 }
149
150 // ---------------------------------------------------------------
151 // Function: initBufferTiling
152 // Purpose:  calculate initialization sizes for frame buffer
153 //           when the tile algorithm is selected
154 // ---------------------------------------------------------------
155 static void initBufferTiling (Standard_Integer& theFrameWidth,
156                               Standard_Integer &theFrameHeight,
157                               const int theViewWidth,
158                               const int theViewHeight)
159 {
160   // fit framebuffer into the printing area
161   if (theFrameWidth > theViewWidth)
162       theFrameWidth = theViewWidth;
163
164   if (theFrameHeight > theViewHeight)
165       theFrameHeight = theViewHeight;
166 }
167
168 // ---------------------------------------------------------------
169 // Function: initBitmapBuffer
170 // Purpose:  init device independent bitmap to hold printing data
171 // ---------------------------------------------------------------
172 #ifdef WNT
173 #ifndef HAVE_FREEIMAGE
174 static void initBitmapBuffer (const HDC theMemoryDC,
175                               HBITMAP &theMemoryBmp,
176                               const   Standard_Integer theBmpWidth,
177                               const   Standard_Integer theBmpHeight,
178                               VOID*   &theBufferPtr)
179 {
180   // define compatible bitmap
181   BITMAPINFO aBitmapData;
182   memset (&aBitmapData, 0, sizeof (BITMAPINFOHEADER));
183   aBitmapData.bmiHeader.biSize          = sizeof (BITMAPINFOHEADER);
184   aBitmapData.bmiHeader.biWidth         = theBmpWidth;
185   aBitmapData.bmiHeader.biHeight        = theBmpHeight;
186   aBitmapData.bmiHeader.biPlanes        = 1;
187   aBitmapData.bmiHeader.biBitCount      = 24;
188   aBitmapData.bmiHeader.biXPelsPerMeter = 0;
189   aBitmapData.bmiHeader.biYPelsPerMeter = 0;
190   aBitmapData.bmiHeader.biClrUsed       = 0;
191   aBitmapData.bmiHeader.biClrImportant  = 0;
192   aBitmapData.bmiHeader.biCompression   = BI_RGB;
193   aBitmapData.bmiHeader.biSizeImage     = 0;
194
195   // Create Device Independent Bitmap
196   theMemoryBmp = CreateDIBSection (theMemoryDC, &aBitmapData, DIB_RGB_COLORS,
197                                    &theBufferPtr, NULL, 0);
198 }
199 #else
200 // ---------------------------------------------------------------
201 // Function: imagePasteDC
202 // Purpose:  copy the data from image buffer to the device context
203 // ---------------------------------------------------------------
204 static bool imagePasteDC(HDC theDstDC,    FipHandle theImage, int theOffsetX,
205                          int theOffsetY,  int theWidth, int theHeight,
206                          int theLeft = 0, int theTop = 0)
207 {
208   // get image parameters
209   BITMAPINFO* aBitmapData = theImage->getInfo ();
210   SetStretchBltMode (theDstDC, STRETCH_HALFTONE);
211
212   // organize blocks data passing if memory isn't enough to pass all the data
213   // at once
214   int aLinesComplete = 0, aMaxBlockWidth = theHeight, aBlockWidth = 0,
215       aPassed        = 0, aInverseLine   = 0, aScan = 0;
216   BYTE *aDataPtr = 0;
217   while (aMaxBlockWidth >= 1 && aLinesComplete < theHeight)
218   {
219     // how much lines still to pass
220     aBlockWidth = theHeight - aLinesComplete;
221
222     // normalize count of lines to pass to maximum lines count at one pass.
223     if (aBlockWidth > aMaxBlockWidth)
224       aBlockWidth = aMaxBlockWidth;
225
226     // access image data at the start scan line, we need to calculate scan from
227     // the bottom of image (image is bottom-left, the src coord is top-left)
228     aInverseLine = theTop + aBlockWidth + aLinesComplete;
229     aScan = theImage->getHeight() - aInverseLine;
230     aDataPtr = theImage->getScanLine (aScan);
231     if (!aDataPtr)
232       return false;
233
234     // try to pass block to the device
235     if (aBlockWidth > 0)
236     {
237       // instead of banded output we provide blocked as it isn't always passed
238       // to printer as it is expected
239       aPassed = SetDIBitsToDevice (theDstDC, theOffsetX,
240                                    theOffsetY + aLinesComplete,
241                                    theWidth, aBlockWidth, theLeft, 0,
242                                    0, aBlockWidth,
243                                    aDataPtr, aBitmapData, DIB_RGB_COLORS);
244
245       // if result is bad, try to decrease band width
246       if (aPassed != aBlockWidth)
247       {
248         aMaxBlockWidth = aMaxBlockWidth >> 1;
249         aLinesComplete = 0;
250       }
251       else
252         aLinesComplete += aBlockWidth;
253     }
254   }
255
256   // check for total failure
257   if (aMaxBlockWidth < 1)
258     return false;
259
260   return true;
261 }
262
263 // ---------------------------------------------------------------
264 // Function: imageStretchDC
265 // Purpose:  copy pixels from image to dc by stretching them
266 // ---------------------------------------------------------------
267 static bool imageStretchDC(HDC theDstDC,   FipHandle theImage, int theOffsetX,
268                            int theOffsetY, int theWidth, int theHeight)
269 {
270   // access to raw image data
271   BYTE *aDataPtr = theImage->accessPixels ();
272   if (!aDataPtr)
273     return false;
274
275   // get image parameters
276   unsigned int widthPx    = theImage->getWidth ();
277   unsigned int heightPx   = theImage->getHeight ();
278   BITMAPINFO* aBitmapData = theImage->getInfo ();
279   SetStretchBltMode (theDstDC, STRETCH_HALFTONE);
280
281   // pass lines and check if operation is succesfull
282   int aPassed = 0;
283   aPassed = StretchDIBits (theDstDC, theOffsetX, theOffsetY, theWidth,
284                            theHeight, 0, 0, widthPx, heightPx, aDataPtr,
285                            aBitmapData, DIB_RGB_COLORS, SRCCOPY);
286
287   if (aPassed != heightPx)
288     return false;
289
290   return true;
291 }
292 #endif
293 #endif
294
295 // ---------------------------------------------------------------
296 // ---------------------------------------------------------------
297
298 //call_togl_print
299 Standard_Boolean OpenGl_Workspace::Print
300   (const Handle(OpenGl_PrinterContext)& thePrintContext,
301    const Graphic3d_CView& ACView,
302    const Aspect_CLayer2d& ACUnderLayer,
303    const Aspect_CLayer2d& ACOverLayer,
304    const Aspect_Handle    hPrintDC,// const Aspect_Drawable hPrintDC,
305    const Standard_Boolean showBackground,
306    const Standard_CString filename,
307    const Aspect_PrintAlgo printAlgorithm,
308    const Standard_Real theScaleFactor)
309 {
310   if (thePrintContext.IsNull())
311   {
312     return Standard_False;
313   }
314
315 #ifdef WNT
316
317   if (!Activate())
318   {
319     //MessageBox (NULL, "Print failed: can't setup the view for printing.",
320     //            "The operation couldn't be completed.", MB_OK);
321     return Standard_False;
322   }
323
324   // printer page dimensions
325   HDC hPrnDC = (HDC) hPrintDC;
326   int devWidth  = GetDeviceCaps (hPrnDC, HORZRES);
327   int devHeight = GetDeviceCaps (hPrnDC, VERTRES);
328
329   // if context is actually a memory dc, try to retrieve bitmap dimensions
330   // (memory dc could be used for testing purposes)
331   if (GetObjectType (hPrnDC) == OBJ_MEMDC)
332   {
333     // memory dc dimensions
334     BITMAP aBitmapInfo;
335     HBITMAP aMemoryBitmap = (HBITMAP) GetCurrentObject (hPrnDC, OBJ_BITMAP);
336     if (aMemoryBitmap)
337       if (GetObject (aMemoryBitmap, sizeof (BITMAP), &aBitmapInfo))
338       {
339         devWidth  = aBitmapInfo.bmWidth;
340         devHeight = aBitmapInfo.bmHeight;
341       }
342   }
343
344   Standard_Integer tempWidth  = (Standard_Integer) devWidth;
345   Standard_Integer tempHeight = (Standard_Integer) devHeight;
346
347   // view dimensions
348   int viewWidth  = myWidth;
349   int viewHeight = myHeight;
350   if (viewWidth == 0 || viewHeight == 0)
351   {
352     //MessageBox (NULL, "Print failed: can't setup the view for printing.",
353     //            "The operation couldn't be completed.", MB_OK);
354     return Standard_False;
355   }
356
357   // calculate correct width/height ratio
358   Standard_Real viewRatio = (Standard_Real)viewWidth/viewHeight;
359   fitDimensionsRatio(tempWidth, tempHeight, viewRatio);
360
361   // width and height for printing area
362   int width  = (int) (tempWidth  * theScaleFactor);
363   int height = (int) (tempHeight * theScaleFactor);
364
365   // device independent bitmap for the whole view
366 #ifdef HAVE_FREEIMAGE
367   FipHandle  aViewImage  = NULL;
368   BYTE*      aViewBuffer = NULL;
369 #else
370   HDC     hMemDC          = CreateCompatibleDC (hPrnDC);
371   HBITMAP hViewBitmap     = NULL;
372   HGDIOBJ hViewBitmapOld  = NULL;
373   VOID*   aViewBuffer    = NULL;
374 #endif
375
376   // Frame buffer initialization
377   OpenGl_FrameBuffer* aFrameBuffer = NULL;
378   OpenGl_FrameBuffer* aPrevBuffer = (OpenGl_FrameBuffer*) ACView.ptrFBO;
379   Standard_Integer aFrameWidth (0),  aFrameHeight (0),
380                    aPrevBufferX (0), aPrevBufferY (0);
381
382   bool IsTiling = (printAlgorithm == 1);
383
384   // try to use existing frame buffer
385   if (aPrevBuffer)
386   {
387     GLsizei aPrevWidth  = aPrevBuffer->GetSizeX();
388     GLsizei aPrevHeight = aPrevBuffer->GetSizeY();
389     bool isUsable = false;
390
391     // check if its possible to use previous frame buffer
392     if (!IsTiling && aPrevWidth >= width && aPrevHeight >= height)
393     {
394       aFrameWidth  = (Standard_Integer) width;
395       aFrameHeight = (Standard_Integer) height;
396       isUsable = true;
397     }
398     else if (IsTiling)
399     {
400       getDimensionsTiling (aFrameWidth, aFrameHeight, width, height);
401       if (aPrevWidth >= aFrameWidth && aPrevHeight >= aFrameHeight)
402         isUsable = true;
403     }
404
405     // if it is enough memory for image paste dc operation
406     if (isUsable)
407     {
408 #ifdef HAVE_FREEIMAGE
409       // try to allocate fipImage and necessary resources
410       fipImage* anImagePtr = new fipImage (FIT_BITMAP, aFrameWidth,
411                                            aFrameHeight, 24);
412
413       // if allocated succesfully
414       if (anImagePtr->isValid())
415       {
416         aViewImage  = anImagePtr;
417         aViewBuffer = aViewImage->accessPixels ();
418       }
419       else
420         delete anImagePtr;
421
422       if (!aViewBuffer)
423       {
424         isUsable = false;
425         aViewBuffer = NULL;
426         aViewImage  = NULL;
427       }
428 #else
429       // try to allocate compatible bitmap and necessary resources
430       initBitmapBuffer (hMemDC, hViewBitmap,
431                         aFrameWidth, aFrameHeight, aViewBuffer);
432       if (!aViewBuffer)
433       {
434         isUsable = false;
435         if (hViewBitmap)
436           DeleteObject (hViewBitmap);
437         hViewBitmap = NULL;
438       }
439       else
440         hViewBitmapOld = SelectObject (hMemDC, hViewBitmap);
441 #endif
442     }
443
444     // use previous frame buffer
445     if (isUsable)
446     {
447       aPrevBufferX = aPrevWidth;
448       aPrevBufferY = aPrevHeight;
449       aFrameBuffer = aPrevBuffer;
450       aFrameBuffer->ChangeViewport (aFrameWidth, aFrameHeight);
451     }
452   }
453
454   // if previous buffer cannot be used, try to init a new one
455   if (!aFrameBuffer)
456   {
457     aFrameBuffer = new OpenGl_FrameBuffer();
458
459     // try to create the framebuffer with the best possible size
460     Standard_Integer aMaxWidth(0), aMaxHeight(0);
461     getMaxFrameSize (aMaxWidth, aMaxHeight);
462     while (aMaxWidth > 1 && aMaxHeight > 1)
463     {
464       aFrameWidth  = aMaxWidth;
465       aFrameHeight = aMaxHeight;
466
467       // calculate dimensions for different printing algorithms
468       if (!IsTiling)
469         initBufferStretch (aFrameWidth, aFrameHeight, width, height);
470       else
471         initBufferTiling (aFrameWidth, aFrameHeight, width, height);
472
473       // try to initialize framebuffer
474       if (aFrameBuffer->Init (GetGlContext(), aFrameWidth, aFrameHeight))
475       {
476 #ifdef HAVE_FREEIMAGE
477         // try to allocate fipImage and necessary resources
478         fipImage* anImagePtr = new fipImage (FIT_BITMAP, aFrameWidth,
479                                             aFrameHeight, 24);
480
481         // if allocated succesfully
482         if (anImagePtr->isValid())
483         {
484           aViewImage  = anImagePtr;
485           aViewBuffer = aViewImage->accessPixels ();
486         }
487         else
488           delete anImagePtr;
489
490         if (!aViewBuffer)
491         {
492           aFrameBuffer->Release (GetGlContext());
493           aViewBuffer = NULL;
494           aViewImage  = NULL;
495         }
496         else
497           break;
498 #else
499         // try to allocate compatible bitmap and necessary resources
500         initBitmapBuffer (hMemDC, hViewBitmap,
501                           aFrameWidth, aFrameHeight, aViewBuffer);
502         if (!aViewBuffer)
503         {
504           if (hViewBitmap)
505             DeleteObject (hViewBitmap);
506           aFrameBuffer->Release (GetGlContext());
507           hViewBitmap = NULL;
508         }
509         else
510         {
511           hViewBitmapOld = SelectObject (hMemDC, hViewBitmap);
512           break;
513         }
514 #endif
515       }
516
517       // not initialized, decrease dimensions
518       aMaxWidth  = aMaxWidth  >> 1;
519       aMaxHeight = aMaxHeight >> 1;
520     }
521
522     // check if there are proper dimensions
523     if (aMaxWidth <= 1 || aMaxHeight <= 1)
524     {
525       MessageBox (NULL, "Print failed: can't allocate buffer for printing.",
526                   "The operation couldn't be completed.", MB_OK);
527
528       if (aFrameBuffer)
529         delete aFrameBuffer;
530 #ifndef HAVE_FREEIMAGE
531       if (hMemDC)
532         DeleteDC (hMemDC);
533 #endif
534
535       return Standard_False;
536     }
537   }
538
539   // setup printing context and viewport
540   myPrintContext = thePrintContext;
541   GLint aViewPortBack[4];
542   GLint anAlignBack = 1;
543   myPrintContext->SetLayerViewport ((GLsizei )aFrameWidth,
544                                     (GLsizei )aFrameHeight);
545   glGetIntegerv (GL_VIEWPORT, aViewPortBack);
546   glGetIntegerv (GL_PACK_ALIGNMENT, &anAlignBack);
547   glPixelStorei (GL_PACK_ALIGNMENT, 4);
548
549   // start document if the printer context is not actually a memory dc
550   // (memory dc could be used for testing purposes)
551   DOCINFO di;
552   if (GetObjectType (hPrnDC) == OBJ_DC)
553   {
554     // Initalize printing procedure
555     di.cbSize = sizeof(DOCINFO);
556     di.lpszDocName = "Open Cascade Document - print v3d view";
557     di.lpszOutput = filename;
558
559     // if can't print the document
560     if (StartDoc (hPrnDC, &di) <= 0 || StartPage (hPrnDC) <= 0)
561     {
562       MessageBox (NULL, "Print failed: printer can't start operation.",
563                   "The operation couldn't be completed.", MB_OK);
564 #ifndef HAVE_FREEIMAGE
565       if (hViewBitmap)
566       {
567         SelectObject (hMemDC, hViewBitmapOld);
568         DeleteObject (hViewBitmap);
569       }
570       DeleteDC (hMemDC);
571 #endif
572
573       myPrintContext.Nullify();
574       return Standard_False;
575     }
576   }
577
578   // activate the offscreen buffer
579   aFrameBuffer->BindBuffer (GetGlContext());
580
581   // calculate offset for centered printing
582   int aDevOffx = (int)(devWidth  - width) /2;
583   int aDevOffy = (int)(devHeight - height)/2;
584
585   // operation complete flag
586   bool isDone = true;
587
588   // Set up status for printing
589   if (!showBackground)
590     NamedStatus |= OPENGL_NS_WHITEBACK;
591
592   if (!IsTiling)
593   {
594     myPrintContext->SetScale ((GLfloat )aFrameWidth /viewWidth,
595                               (GLfloat )aFrameHeight/viewHeight);
596     aFrameBuffer->SetupViewport ();
597     Redraw1(ACView, ACUnderLayer, ACOverLayer, 0);
598     if (!myTransientDrawToFront)
599     {
600       // render to FBO only if allowed to render to back buffer
601       RedrawImmediatMode();
602     }
603     glReadPixels (0, 0, aFrameWidth, aFrameHeight,
604                   GL_BGR_EXT, GL_UNSIGNED_BYTE, (GLvoid* )aViewBuffer);
605
606     // copy result to the printer device and check for errors
607 #ifdef HAVE_FREEIMAGE
608     if (!aViewImage->rescale(width, height, FILTER_BICUBIC) ||
609         !imagePasteDC (hPrnDC, aViewImage, aDevOffx, aDevOffy, width, height))
610       isDone = imageStretchDC (hPrnDC, aViewImage, aDevOffx, aDevOffy,
611                                width, height);
612 #else
613     if (width > aFrameWidth && height > aFrameHeight)
614     {
615       SetStretchBltMode (hPrnDC, STRETCH_HALFTONE);
616       isDone = (StretchBlt (hPrnDC, aDevOffx, aDevOffy, width, height,
617                             hMemDC, 0, 0, aFrameWidth, aFrameHeight, SRCCOPY) != 0); // to avoid warning C4800
618     }
619     else
620     {
621       isDone = (BitBlt (hPrnDC, aDevOffx, aDevOffy, width, height,
622                         hMemDC, 0, 0, SRCCOPY) != 0); // to avoid warning C4800
623     }
624 #endif
625   }
626   else
627   {
628     // calculate total count of frames and cropping size
629     Standard_Integer aPxCropx = 0;
630     Standard_Integer aPxCropy = 0;
631     Standard_Integer aTotalx =
632                      (Standard_Integer)floor ((float)width /aFrameWidth);
633     Standard_Integer aTotaly =
634                      (Standard_Integer)floor ((float)height/aFrameHeight);
635     if (width %aFrameWidth != 0)
636     {
637       aPxCropx = (aFrameWidth - width%aFrameWidth)/2;
638       aTotalx++;
639     }
640     if (height%aFrameHeight != 0)
641     {
642       aPxCropy = (aFrameHeight - height%aFrameHeight)/2;
643       aTotaly++;
644     }
645
646     int anOddPixelx = (width %aFrameWidth) %2;
647     int anOddPixely = (height%aFrameHeight)%2;
648
649     // calculate scale factor for full frames
650     Standard_Real aScalex = (Standard_Real)width /aFrameWidth;
651     Standard_Real aScaley = (Standard_Real)height/aFrameHeight;
652
653     // calculate and set the text scaling factor for printing context
654     GLfloat aScaleRatex = (GLfloat)aFrameWidth /viewWidth;
655     GLfloat aScaleRatey = (GLfloat)aFrameHeight/viewHeight;
656     myPrintContext->SetScale (aScaleRatex * (GLfloat )aScalex,
657                               aScaleRatey * (GLfloat )aScaley);
658
659     // initialize projection matrix for printer context
660     TColStd_Array2OfReal aProj (0, 3, 0, 3);
661     Standard_Real aDef = 0;
662     aProj.Init (aDef);
663     aProj(2,2) = 1.0;
664     aProj(3,3) = 1.0;
665
666     // projection matrix offsets for printer context
667     // offsets are even numbers
668     Standard_Real aOffsetx(0), aOffsety(0);
669     aOffsetx = -(aTotalx-1);
670     aOffsety = -(aTotaly-1);
671
672     // rect of frame image that will be copied
673     // and coordinates in view image where to put it
674     Standard_Integer aLeft = 0, aRight = 0, aBottom = 0, aTop = 0;
675     Standard_Integer aSubLeft = (Standard_Integer)aDevOffx;
676     Standard_Integer aSubTop  = (Standard_Integer)aDevOffy;
677
678     // draw sequence of full frames
679     for (int i = 0; i < aTotalx; i++)
680     {
681       // offsets are even numbers
682       aOffsety = -(aTotaly-1);
683       aSubTop  =  (Standard_Integer)aDevOffy;
684
685       // calculate cropped frame rect
686       aLeft  = (i == 0) ? aPxCropx : 0;
687       aRight = (i == aTotalx-1) ? aFrameWidth-(aPxCropx+anOddPixelx) :
688                                   aFrameWidth;
689
690       for (int j = 0; j < aTotaly; j++)
691       {
692         // no offset for single frames
693         aProj(3,0) = (aTotalx == 1) ? 0 : -aOffsetx;
694         aProj(3,1) = (aTotaly == 1) ? 0 :  aOffsety;
695
696         // set projection matrix
697         aProj(0,0) = aScalex;
698         aProj(1,1) = aScaley;
699         myPrintContext->SetProjTransformation (aProj);
700
701         // calculate cropped frame rect
702         aTop    = (j == 0)         ? aPxCropy : 0;
703         aBottom = (j == aTotaly-1) ? aFrameHeight-(aPxCropy+anOddPixely) :
704                                      aFrameHeight;
705
706         // draw to the offscreen buffer and capture the result
707         aFrameBuffer->SetupViewport ();
708         Redraw1(ACView, ACUnderLayer, ACOverLayer, 0);
709         if (!myTransientDrawToFront)
710         {
711           // render to FBO only if forces to render to back buffer
712           RedrawImmediatMode();
713         }
714         glReadPixels (0, 0, aFrameWidth, aFrameHeight,
715                       GL_BGR_EXT, GL_UNSIGNED_BYTE, (GLvoid* )aViewBuffer);
716 #ifdef HAVE_FREEIMAGE
717         // cut out pixels that are out of printing area
718         isDone = imagePasteDC (hPrnDC, aViewImage, aSubLeft, aSubTop,
719                                aRight-aLeft, aBottom-aTop, aLeft, aTop);
720 #else
721         isDone = (BitBlt (hPrnDC, aSubLeft, aSubTop, aRight-aLeft, aBottom-aTop,
722                           hMemDC, aLeft, aTop, SRCCOPY) != 0); // to avoid warning C4800
723 #endif
724
725         // stop operation if errors
726         if (!isDone)
727           break;
728
729         // calculate new view offset for y-coordinate
730         aOffsety += 2.0;
731         aSubTop  += aBottom-aTop;
732       }
733
734       // stop operation if errors
735       if (!isDone)
736         break;
737
738       // calculate new view offset for x-coordinate
739       aOffsetx += 2.0;
740       aSubLeft += aRight-aLeft;
741     }
742   }
743
744   // complete printing or indicate an error
745   if (GetObjectType (hPrnDC) == OBJ_DC && isDone == true)
746   {
747     EndPage (hPrnDC);
748     EndDoc (hPrnDC);
749   }
750   else if (isDone == false)
751   {
752     MessageBox (NULL, "Print failed: insufficient memory or spool error.\nPlease use smaller printer resolution.",
753                 "The opeartion couldn't be completed.", MB_OK);
754     if (GetObjectType (hPrnDC) == OBJ_DC)
755       AbortDoc (hPrnDC);
756   }
757
758   // return OpenGl to the previous state
759   glPixelStorei (GL_PACK_ALIGNMENT, anAlignBack);
760   aFrameBuffer->UnbindBuffer (GetGlContext());
761   glViewport (aViewPortBack[0], aViewPortBack[1],
762               aViewPortBack[2], aViewPortBack[3]);
763   if (aPrevBuffer)
764   {
765     aPrevBuffer->ChangeViewport (aPrevBufferX, aPrevBufferY);
766   }
767   else
768   {
769     aFrameBuffer->Release (GetGlContext ());
770     delete aFrameBuffer;
771   }
772
773   // delete resources
774 #ifndef HAVE_FREEIMAGE
775   if (hViewBitmap)
776   {
777     SelectObject (hMemDC, hViewBitmapOld);
778     DeleteObject (hViewBitmap);
779   }
780   DeleteDC (hMemDC);
781 #endif
782
783   // Reset status after printing
784   NamedStatus &= ~OPENGL_NS_WHITEBACK;
785
786   myPrintContext.Nullify();
787   return (Standard_Boolean) isDone;
788
789 #else // not WNT
790   myPrintContext.Nullify();
791   return Standard_False;
792 #endif
793 }
794
795 /*----------------------------------------------------------------------*/
796
797 //redrawView
798 void OpenGl_Workspace::Redraw1 (const Graphic3d_CView& ACView,
799                                 const Aspect_CLayer2d& ACUnderLayer,
800                                 const Aspect_CLayer2d& ACOverLayer,
801                                 const int aswap)
802 {
803   if (myDisplay.IsNull() || myView.IsNull())
804     return;
805
806   myDisplay->UpdateUserMarkers();
807
808   // Request reset of material
809   NamedStatus |= OPENGL_NS_RESMAT;
810
811   /* GL_DITHER on/off pour le background */
812   if (myBackDither)
813     glEnable (GL_DITHER);
814   else
815     glDisable (GL_DITHER);
816
817   GLbitfield toClear = GL_COLOR_BUFFER_BIT;
818   if ( myUseZBuffer )
819   {
820     glDepthFunc(GL_LEQUAL);
821     glDepthMask(GL_TRUE);
822
823     // SAV checking if depth test was deprecated somewhere outside
824     if ( myUseDepthTest )
825       glEnable(GL_DEPTH_TEST);
826     else
827       glDisable(GL_DEPTH_TEST);
828
829     glClearDepth(1.0);
830     toClear |= GL_DEPTH_BUFFER_BIT;
831   }
832   else
833   {
834     glDisable(GL_DEPTH_TEST);
835   }
836
837   if ( NamedStatus & OPENGL_NS_WHITEBACK )
838   {
839     // Set background to white
840     glClearColor (1.F, 1.F, 1.F, 1.F);
841     toClear |= GL_DEPTH_BUFFER_BIT;
842   }
843   else
844   {
845     glClearColor (myBgColor.rgb[0], myBgColor.rgb[1], myBgColor.rgb[2], 0.F);
846   }
847   glClear (toClear);
848
849   Handle(OpenGl_Workspace) aWS(this);
850   myView->Render (myPrintContext, aWS, ACView, ACUnderLayer, ACOverLayer);
851
852   // Swap the buffers
853   if ( aswap )
854   {
855     GetGlContext()->SwapBuffers();
856     myBackBufferRestored = Standard_False;
857   }
858   else
859     glFlush();
860 }
861
862 /*----------------------------------------------------------------------*/
863
864 //TelCopyBuffers
865 void OpenGl_Workspace::CopyBuffers (const Standard_Boolean theFrontToBack)
866 {
867   if (theFrontToBack)
868   {
869     myBackBufferRestored = Standard_False;
870   }
871
872   glMatrixMode (GL_PROJECTION);
873   glPushMatrix ();
874   glLoadIdentity ();
875   gluOrtho2D ((GLdouble) 0., (GLdouble) myWidth, 0., (GLdouble) myHeight);
876   glMatrixMode (GL_MODELVIEW);
877   glPushMatrix ();
878   glLoadIdentity ();
879
880   DisableFeatures();
881
882   glDrawBuffer (theFrontToBack ? GL_BACK  : GL_FRONT);
883   glReadBuffer (theFrontToBack ? GL_FRONT : GL_BACK);
884
885   glRasterPos2i (0, 0);
886   glCopyPixels  (0, 0, myWidth  + 1, myHeight + 1, GL_COLOR);
887
888   EnableFeatures();
889
890   glMatrixMode (GL_PROJECTION);
891   glPopMatrix ();
892   glMatrixMode (GL_MODELVIEW);
893   glPopMatrix ();
894
895   glDrawBuffer (GL_BACK);
896 }
897
898 /*----------------------------------------------------------------------*/
899
900 //call_subr_displayCB
901 void OpenGl_Workspace::DisplayCallback (const Graphic3d_CView& theCView,
902                                         int theReason)
903 {
904   if (theCView.GDisplayCB == NULL)
905   {
906     return;
907   }
908
909   Aspect_GraphicCallbackStruct aCallData;
910   aCallData.reason    = theReason;
911   aCallData.glContext = GetGlContext();
912   aCallData.wsID      = theCView.WsId;
913   aCallData.viewID    = theCView.ViewId;
914   theCView.GDisplayCB (theCView.DefWindow.XWindow, theCView.GClientData, &aCallData);
915 }
916
917 /*----------------------------------------------------------------------*/