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