0024298: Eliminate GCC compiler warning about unused in linux functions
[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: fitDimensionsRatio
62 // Purpose:  calculate correct width/height ratio for theWidth and
63 //           theHeight parameters
64 // ---------------------------------------------------------------
65 static void fitDimensionsRatio (Standard_Integer& theWidth,
66                                 Standard_Integer& theHeight,
67                                 const Standard_Real theViewRatio)
68 {
69   // set dimensions in accordance with the viewratio
70   if (theHeight <  theWidth/theViewRatio)
71       theWidth  = (Standard_Integer)(theHeight*theViewRatio);
72
73   if (theWidth  <  theHeight*theViewRatio)
74       theHeight = (Standard_Integer)(theWidth/theViewRatio);
75 }
76
77 // ---------------------------------------------------------------
78 // Function: initBitmapBuffer
79 // Purpose:  init device independent bitmap to hold printing data
80 // ---------------------------------------------------------------
81 #ifdef _WIN32
82 #ifndef HAVE_FREEIMAGE
83 static void initBitmapBuffer (const HDC theMemoryDC,
84                               HBITMAP &theMemoryBmp,
85                               const   Standard_Integer theBmpWidth,
86                               const   Standard_Integer theBmpHeight,
87                               VOID*   &theBufferPtr)
88 {
89   // define compatible bitmap
90   BITMAPINFO aBitmapData;
91   memset (&aBitmapData, 0, sizeof (BITMAPINFOHEADER));
92   aBitmapData.bmiHeader.biSize          = sizeof (BITMAPINFOHEADER);
93   aBitmapData.bmiHeader.biWidth         = theBmpWidth;
94   aBitmapData.bmiHeader.biHeight        = theBmpHeight;
95   aBitmapData.bmiHeader.biPlanes        = 1;
96   aBitmapData.bmiHeader.biBitCount      = 24;
97   aBitmapData.bmiHeader.biXPelsPerMeter = 0;
98   aBitmapData.bmiHeader.biYPelsPerMeter = 0;
99   aBitmapData.bmiHeader.biClrUsed       = 0;
100   aBitmapData.bmiHeader.biClrImportant  = 0;
101   aBitmapData.bmiHeader.biCompression   = BI_RGB;
102   aBitmapData.bmiHeader.biSizeImage     = 0;
103
104   // Create Device Independent Bitmap
105   theMemoryBmp = CreateDIBSection (theMemoryDC, &aBitmapData, DIB_RGB_COLORS,
106                                    &theBufferPtr, NULL, 0);
107 }
108 #else
109 // ---------------------------------------------------------------
110 // Function: imagePasteDC
111 // Purpose:  copy the data from image buffer to the device context
112 // ---------------------------------------------------------------
113 static bool imagePasteDC(HDC theDstDC,    FipHandle theImage, int theOffsetX,
114                          int theOffsetY,  int theWidth, int theHeight,
115                          int theLeft = 0, int theTop = 0)
116 {
117   // get image parameters
118   BITMAPINFO* aBitmapData = theImage->getInfo ();
119   SetStretchBltMode (theDstDC, STRETCH_HALFTONE);
120
121   // organize blocks data passing if memory isn't enough to pass all the data
122   // at once
123   int aLinesComplete = 0, aMaxBlockWidth = theHeight, aBlockWidth = 0,
124       aPassed        = 0, aInverseLine   = 0, aScan = 0;
125   BYTE *aDataPtr = 0;
126   while (aMaxBlockWidth >= 1 && aLinesComplete < theHeight)
127   {
128     // how much lines still to pass
129     aBlockWidth = theHeight - aLinesComplete;
130
131     // normalize count of lines to pass to maximum lines count at one pass.
132     if (aBlockWidth > aMaxBlockWidth)
133       aBlockWidth = aMaxBlockWidth;
134
135     // access image data at the start scan line, we need to calculate scan from
136     // the bottom of image (image is bottom-left, the src coord is top-left)
137     aInverseLine = theTop + aBlockWidth + aLinesComplete;
138     aScan = theImage->getHeight() - aInverseLine;
139     aDataPtr = theImage->getScanLine (aScan);
140     if (!aDataPtr)
141       return false;
142
143     // try to pass block to the device
144     if (aBlockWidth > 0)
145     {
146       // instead of banded output we provide blocked as it isn't always passed
147       // to printer as it is expected
148       aPassed = SetDIBitsToDevice (theDstDC, theOffsetX,
149                                    theOffsetY + aLinesComplete,
150                                    theWidth, aBlockWidth, theLeft, 0,
151                                    0, aBlockWidth,
152                                    aDataPtr, aBitmapData, DIB_RGB_COLORS);
153
154       // if result is bad, try to decrease band width
155       if (aPassed != aBlockWidth)
156       {
157         aMaxBlockWidth = aMaxBlockWidth >> 1;
158         aLinesComplete = 0;
159       }
160       else
161         aLinesComplete += aBlockWidth;
162     }
163   }
164
165   // check for total failure
166   if (aMaxBlockWidth < 1)
167     return false;
168
169   return true;
170 }
171
172 // ---------------------------------------------------------------
173 // Function: imageStretchDC
174 // Purpose:  copy pixels from image to dc by stretching them
175 // ---------------------------------------------------------------
176 static bool imageStretchDC(HDC theDstDC,   FipHandle theImage, int theOffsetX,
177                            int theOffsetY, int theWidth, int theHeight)
178 {
179   // access to raw image data
180   BYTE *aDataPtr = theImage->accessPixels ();
181   if (!aDataPtr)
182     return false;
183
184   // get image parameters
185   unsigned int widthPx    = theImage->getWidth ();
186   unsigned int heightPx   = theImage->getHeight ();
187   BITMAPINFO* aBitmapData = theImage->getInfo ();
188   SetStretchBltMode (theDstDC, STRETCH_HALFTONE);
189
190   // pass lines and check if operation is succesfull
191   int aPassed = 0;
192   aPassed = StretchDIBits (theDstDC, theOffsetX, theOffsetY, theWidth,
193                            theHeight, 0, 0, widthPx, heightPx, aDataPtr,
194                            aBitmapData, DIB_RGB_COLORS, SRCCOPY);
195
196   if ((unsigned)aPassed != heightPx)
197     return false;
198
199   return true;
200 }
201 #endif
202
203 // ---------------------------------------------------------------
204 // Function: getMaxFrameSize
205 // Purpose:  get the maximum possible frame size
206 // ---------------------------------------------------------------
207 static void getMaxFrameSize(Standard_Integer& theWidth,
208                             Standard_Integer& theHeight)
209 {
210   GLsizei aMaxX, aMaxY;
211   GLint aVpDim[2];
212   GLint aTexDim = 2048;
213   glGetIntegerv (GL_MAX_VIEWPORT_DIMS, (GLint*) &aVpDim);
214   glGetIntegerv (GL_MAX_TEXTURE_SIZE, &aTexDim);
215   (aVpDim[0] >= aTexDim) ? aMaxX = (GLsizei) aTexDim :
216                            aMaxX = getNearestPowOfTwo((GLsizei)aVpDim[0]);
217   (aVpDim[1] >= aTexDim) ? aMaxY = (GLsizei) aTexDim :
218                            aMaxY = getNearestPowOfTwo((GLsizei)aVpDim[1]);
219
220   theWidth  = (Standard_Integer)aMaxX;
221   theHeight = (Standard_Integer)aMaxY;
222 }
223 // ---------------------------------------------------------------
224 // Function: getDimensionsTiling
225 // Purpose:  calculate maximum possible dimensions for framebuffer
226 //           in tiling mode according to the view size
227 // ---------------------------------------------------------------
228 static void getDimensionsTiling (Standard_Integer& theFrameWidth,
229                                  Standard_Integer& theFrameHeight,
230                                  const int theViewWidth,
231                                  const int theViewHeight)
232 {
233   // fit the maximum dimensions into the printing area
234   if (theFrameWidth > theViewWidth)
235       theFrameWidth = theViewWidth;
236
237   if (theFrameHeight > theViewHeight)
238       theFrameHeight = theViewHeight;
239 }
240 // ---------------------------------------------------------------
241 // Function: initBufferStretch
242 // Purpose:  calculate initialization sizes for frame buffer
243 //           when the stretch algorithm is selected
244 // ---------------------------------------------------------------
245 static void initBufferStretch (Standard_Integer& theFrameWidth,
246                                Standard_Integer& theFrameHeight,
247                                const int theViewWidth,
248                                const int theViewHeight)
249 {
250
251   // Calculate correct width/height for framebuffer
252   Standard_Real aViewRatio = (Standard_Real)theViewWidth/theViewHeight;
253   fitDimensionsRatio (theFrameWidth, theFrameHeight, aViewRatio);
254
255   // downscale the framebuffer if it is too large
256   Standard_Real aWidthRate  = (Standard_Real)theFrameWidth /theViewWidth;
257   Standard_Real aHeightRate = (Standard_Real)theFrameHeight/theViewHeight;
258
259   if ((aWidthRate > 1 && aHeightRate > 1 && aWidthRate >= aHeightRate) ||
260       (aWidthRate > 1 && aHeightRate <= 1))
261   {
262     theFrameWidth  = (Standard_Integer)(theFrameWidth /aWidthRate);
263     theFrameHeight = (Standard_Integer)(theFrameHeight/aWidthRate);
264   }
265   else if ((aWidthRate  > 1 && aHeightRate > 1 && aWidthRate < aHeightRate) ||
266            (aWidthRate <= 1 && aHeightRate > 1))
267   {
268     theFrameWidth  = (Standard_Integer)(theFrameWidth /aHeightRate);
269     theFrameHeight = (Standard_Integer)(theFrameHeight/aHeightRate);
270   }
271 }
272 // ---------------------------------------------------------------
273 // Function: initBufferTiling
274 // Purpose:  calculate initialization sizes for frame buffer
275 //           when the tile algorithm is selected
276 // ---------------------------------------------------------------
277 static void initBufferTiling (Standard_Integer& theFrameWidth,
278                               Standard_Integer &theFrameHeight,
279                               const int theViewWidth,
280                               const int theViewHeight)
281 {
282   // fit framebuffer into the printing area
283   if (theFrameWidth > theViewWidth)
284       theFrameWidth = theViewWidth;
285
286   if (theFrameHeight > theViewHeight)
287       theFrameHeight = theViewHeight;
288 }
289 #endif
290
291 // ---------------------------------------------------------------
292 // ---------------------------------------------------------------
293
294 //call_togl_print
295
296 Standard_Boolean OpenGl_Workspace::Print
297   (const Handle(OpenGl_PrinterContext)& thePrintContext,
298    const Graphic3d_CView& ACView,
299    const Aspect_CLayer2d& ACUnderLayer,
300    const Aspect_CLayer2d& ACOverLayer,
301    const Aspect_Handle    hPrintDC,// const Aspect_Drawable hPrintDC,
302    const Standard_Boolean showBackground,
303    const Standard_CString filename,
304    const Aspect_PrintAlgo printAlgorithm,
305    const Standard_Real theScaleFactor)
306 {
307   if (thePrintContext.IsNull())
308   {
309     return Standard_False;
310   }
311
312 #ifdef _WIN32
313
314   if (!Activate())
315   {
316     //MessageBox (NULL, "Print failed: can't setup the view for printing.",
317     //            "The operation couldn't be completed.", MB_OK);
318     return Standard_False;
319   }
320
321   // printer page dimensions
322   HDC hPrnDC = (HDC) hPrintDC;
323   int devWidth  = GetDeviceCaps (hPrnDC, HORZRES);
324   int devHeight = GetDeviceCaps (hPrnDC, VERTRES);
325
326   // if context is actually a memory dc, try to retrieve bitmap dimensions
327   // (memory dc could be used for testing purposes)
328   if (GetObjectType (hPrnDC) == OBJ_MEMDC)
329   {
330     // memory dc dimensions
331     BITMAP aBitmapInfo;
332     HBITMAP aMemoryBitmap = (HBITMAP) GetCurrentObject (hPrnDC, OBJ_BITMAP);
333     if (aMemoryBitmap)
334       if (GetObject (aMemoryBitmap, sizeof (BITMAP), &aBitmapInfo))
335       {
336         devWidth  = aBitmapInfo.bmWidth;
337         devHeight = aBitmapInfo.bmHeight;
338       }
339   }
340
341   Standard_Integer tempWidth  = (Standard_Integer) devWidth;
342   Standard_Integer tempHeight = (Standard_Integer) devHeight;
343
344   // view dimensions
345   int viewWidth  = myWidth;
346   int viewHeight = myHeight;
347   if (viewWidth == 0 || viewHeight == 0)
348   {
349     //MessageBox (NULL, "Print failed: can't setup the view for printing.",
350     //            "The operation couldn't be completed.", MB_OK);
351     return Standard_False;
352   }
353
354   // calculate correct width/height ratio
355   Standard_Real viewRatio = (Standard_Real)viewWidth/viewHeight;
356   fitDimensionsRatio(tempWidth, tempHeight, viewRatio);
357
358   // width and height for printing area
359   int width  = (int) (tempWidth  * theScaleFactor);
360   int height = (int) (tempHeight * theScaleFactor);
361
362   // device independent bitmap for the whole view
363 #ifdef HAVE_FREEIMAGE
364   FipHandle  aViewImage  = NULL;
365   BYTE*      aViewBuffer = NULL;
366 #else
367   HDC     hMemDC          = CreateCompatibleDC (hPrnDC);
368   HBITMAP hViewBitmap     = NULL;
369   HGDIOBJ hViewBitmapOld  = NULL;
370   VOID*   aViewBuffer    = NULL;
371 #endif
372
373   // Frame buffer initialization
374   OpenGl_FrameBuffer* aFrameBuffer = NULL;
375   OpenGl_FrameBuffer* aPrevBuffer = (OpenGl_FrameBuffer*) ACView.ptrFBO;
376   Standard_Integer aFrameWidth (0),  aFrameHeight (0),
377                    aPrevBufferX (0), aPrevBufferY (0);
378
379   bool IsTiling = (printAlgorithm == 1);
380
381   // try to use existing frame buffer
382   if (aPrevBuffer)
383   {
384     GLsizei aPrevWidth  = aPrevBuffer->GetSizeX();
385     GLsizei aPrevHeight = aPrevBuffer->GetSizeY();
386     bool isUsable = false;
387
388     // check if its possible to use previous frame buffer
389     if (!IsTiling && aPrevWidth >= width && aPrevHeight >= height)
390     {
391       aFrameWidth  = (Standard_Integer) width;
392       aFrameHeight = (Standard_Integer) height;
393       isUsable = true;
394     }
395     else if (IsTiling)
396     {
397       getDimensionsTiling (aFrameWidth, aFrameHeight, width, height);
398       if (aPrevWidth >= aFrameWidth && aPrevHeight >= aFrameHeight)
399         isUsable = true;
400     }
401
402     // if it is enough memory for image paste dc operation
403     if (isUsable)
404     {
405 #ifdef HAVE_FREEIMAGE
406       // try to allocate fipImage and necessary resources
407       fipImage* anImagePtr = new fipImage (FIT_BITMAP, aFrameWidth,
408                                            aFrameHeight, 24);
409
410       // if allocated succesfully
411       if (anImagePtr->isValid())
412       {
413         aViewImage  = anImagePtr;
414         aViewBuffer = aViewImage->accessPixels ();
415       }
416       else
417         delete anImagePtr;
418
419       if (!aViewBuffer)
420       {
421         isUsable = false;
422         aViewBuffer = NULL;
423         aViewImage  = NULL;
424       }
425 #else
426       // try to allocate compatible bitmap and necessary resources
427       initBitmapBuffer (hMemDC, hViewBitmap,
428                         aFrameWidth, aFrameHeight, aViewBuffer);
429       if (!aViewBuffer)
430       {
431         isUsable = false;
432         if (hViewBitmap)
433           DeleteObject (hViewBitmap);
434         hViewBitmap = NULL;
435       }
436       else
437         hViewBitmapOld = SelectObject (hMemDC, hViewBitmap);
438 #endif
439     }
440
441     // use previous frame buffer
442     if (isUsable)
443     {
444       aPrevBufferX = aPrevWidth;
445       aPrevBufferY = aPrevHeight;
446       aFrameBuffer = aPrevBuffer;
447       aFrameBuffer->ChangeViewport (aFrameWidth, aFrameHeight);
448     }
449   }
450
451   // if previous buffer cannot be used, try to init a new one
452   if (!aFrameBuffer)
453   {
454     aFrameBuffer = new OpenGl_FrameBuffer();
455
456     // try to create the framebuffer with the best possible size
457     Standard_Integer aMaxWidth(0), aMaxHeight(0);
458     getMaxFrameSize (aMaxWidth, aMaxHeight);
459     while (aMaxWidth > 1 && aMaxHeight > 1)
460     {
461       aFrameWidth  = aMaxWidth;
462       aFrameHeight = aMaxHeight;
463
464       // calculate dimensions for different printing algorithms
465       if (!IsTiling)
466         initBufferStretch (aFrameWidth, aFrameHeight, width, height);
467       else
468         initBufferTiling (aFrameWidth, aFrameHeight, width, height);
469
470       // try to initialize framebuffer
471       if (aFrameBuffer->Init (GetGlContext(), aFrameWidth, aFrameHeight))
472       {
473 #ifdef HAVE_FREEIMAGE
474         // try to allocate fipImage and necessary resources
475         fipImage* anImagePtr = new fipImage (FIT_BITMAP, aFrameWidth,
476                                             aFrameHeight, 24);
477
478         // if allocated succesfully
479         if (anImagePtr->isValid())
480         {
481           aViewImage  = anImagePtr;
482           aViewBuffer = aViewImage->accessPixels ();
483         }
484         else
485           delete anImagePtr;
486
487         if (!aViewBuffer)
488         {
489           aFrameBuffer->Release (GetGlContext().operator->());
490           aViewBuffer = NULL;
491           aViewImage  = NULL;
492         }
493         else
494           break;
495 #else
496         // try to allocate compatible bitmap and necessary resources
497         initBitmapBuffer (hMemDC, hViewBitmap,
498                           aFrameWidth, aFrameHeight, aViewBuffer);
499         if (!aViewBuffer)
500         {
501           if (hViewBitmap)
502             DeleteObject (hViewBitmap);
503           aFrameBuffer->Release (GetGlContext().operator->());
504           hViewBitmap = NULL;
505         }
506         else
507         {
508           hViewBitmapOld = SelectObject (hMemDC, hViewBitmap);
509           break;
510         }
511 #endif
512       }
513
514       // not initialized, decrease dimensions
515       aMaxWidth  = aMaxWidth  >> 1;
516       aMaxHeight = aMaxHeight >> 1;
517     }
518
519     // check if there are proper dimensions
520     if (aMaxWidth <= 1 || aMaxHeight <= 1)
521     {
522       MessageBox (NULL, "Print failed: can't allocate buffer for printing.",
523                   "The operation couldn't be completed.", MB_OK);
524
525       if (aFrameBuffer)
526         delete aFrameBuffer;
527 #ifndef HAVE_FREEIMAGE
528       if (hMemDC)
529         DeleteDC (hMemDC);
530 #endif
531
532       return Standard_False;
533     }
534   }
535
536   // setup printing context and viewport
537   myPrintContext = thePrintContext;
538   GLint aViewPortBack[4];
539   GLint anAlignBack = 1;
540   myPrintContext->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       myPrintContext.Nullify();
571       return Standard_False;
572     }
573   }
574
575   // activate the offscreen buffer
576   aFrameBuffer->BindBuffer (GetGlContext());
577
578   // calculate offset for centered printing
579   int aDevOffx = (int)(devWidth  - width) /2;
580   int aDevOffy = (int)(devHeight - height)/2;
581
582   // operation complete flag
583   bool isDone = true;
584
585   // Set up status for printing
586   if (!showBackground)
587     NamedStatus |= OPENGL_NS_WHITEBACK;
588
589   if (!IsTiling)
590   {
591     myPrintContext->SetScale ((GLfloat )aFrameWidth /viewWidth,
592                               (GLfloat )aFrameHeight/viewHeight);
593     aFrameBuffer->SetupViewport (GetGlContext());
594     Redraw1(ACView, ACUnderLayer, ACOverLayer, 0);
595     if (!myTransientDrawToFront)
596     {
597       // render to FBO only if allowed to render to back buffer
598       RedrawImmediatMode();
599     }
600     glReadPixels (0, 0, aFrameWidth, aFrameHeight,
601                   GL_BGR_EXT, GL_UNSIGNED_BYTE, (GLvoid* )aViewBuffer);
602
603     // copy result to the printer device and check for errors
604 #ifdef HAVE_FREEIMAGE
605     if (!aViewImage->rescale(width, height, FILTER_BICUBIC) ||
606         !imagePasteDC (hPrnDC, aViewImage, aDevOffx, aDevOffy, width, height))
607       isDone = imageStretchDC (hPrnDC, aViewImage, aDevOffx, aDevOffy,
608                                width, height);
609 #else
610     if (width > aFrameWidth && height > aFrameHeight)
611     {
612       SetStretchBltMode (hPrnDC, STRETCH_HALFTONE);
613       isDone = (StretchBlt (hPrnDC, aDevOffx, aDevOffy, width, height,
614                             hMemDC, 0, 0, aFrameWidth, aFrameHeight, SRCCOPY) != 0); // to avoid warning C4800
615     }
616     else
617     {
618       isDone = (BitBlt (hPrnDC, aDevOffx, aDevOffy, width, height,
619                         hMemDC, 0, 0, SRCCOPY) != 0); // to avoid warning C4800
620     }
621 #endif
622   }
623   else
624   {
625     // calculate total count of frames and cropping size
626     Standard_Integer aPxCropx = 0;
627     Standard_Integer aPxCropy = 0;
628     Standard_Integer aTotalx =
629                      (Standard_Integer)floor ((float)width /aFrameWidth);
630     Standard_Integer aTotaly =
631                      (Standard_Integer)floor ((float)height/aFrameHeight);
632     if (width %aFrameWidth != 0)
633     {
634       aPxCropx = (aFrameWidth - width%aFrameWidth)/2;
635       aTotalx++;
636     }
637     if (height%aFrameHeight != 0)
638     {
639       aPxCropy = (aFrameHeight - height%aFrameHeight)/2;
640       aTotaly++;
641     }
642
643     int anOddPixelx = (width %aFrameWidth) %2;
644     int anOddPixely = (height%aFrameHeight)%2;
645
646     // calculate scale factor for full frames
647     Standard_Real aScalex = (Standard_Real)width /aFrameWidth;
648     Standard_Real aScaley = (Standard_Real)height/aFrameHeight;
649
650     // calculate and set the text scaling factor for printing context
651     GLfloat aScaleRatex = (GLfloat)aFrameWidth /viewWidth;
652     GLfloat aScaleRatey = (GLfloat)aFrameHeight/viewHeight;
653     myPrintContext->SetScale (aScaleRatex * (GLfloat )aScalex,
654                               aScaleRatey * (GLfloat )aScaley);
655
656     // initialize projection matrix for printer context
657     TColStd_Array2OfReal aProj (0, 3, 0, 3);
658     Standard_Real aDef = 0;
659     aProj.Init (aDef);
660     aProj(2,2) = 1.0;
661     aProj(3,3) = 1.0;
662
663     // projection matrix offsets for printer context
664     // offsets are even numbers
665     Standard_Real aOffsetx(0), aOffsety(0);
666     aOffsetx = -(aTotalx-1);
667     aOffsety = -(aTotaly-1);
668
669     // rect of frame image that will be copied
670     // and coordinates in view image where to put it
671     Standard_Integer aLeft = 0, aRight = 0, aBottom = 0, aTop = 0;
672     Standard_Integer aSubLeft = (Standard_Integer)aDevOffx;
673     Standard_Integer aSubTop  = (Standard_Integer)aDevOffy;
674
675     // draw sequence of full frames
676     for (int i = 0; i < aTotalx; i++)
677     {
678       // offsets are even numbers
679       aOffsety = -(aTotaly-1);
680       aSubTop  =  (Standard_Integer)aDevOffy;
681
682       // calculate cropped frame rect
683       aLeft  = (i == 0) ? aPxCropx : 0;
684       aRight = (i == aTotalx-1) ? aFrameWidth-(aPxCropx+anOddPixelx) :
685                                   aFrameWidth;
686
687       for (int j = 0; j < aTotaly; j++)
688       {
689         // no offset for single frames
690         aProj(3,0) = (aTotalx == 1) ? 0 : -aOffsetx;
691         aProj(3,1) = (aTotaly == 1) ? 0 :  aOffsety;
692
693         // set projection matrix
694         aProj(0,0) = aScalex;
695         aProj(1,1) = aScaley;
696         myPrintContext->SetProjTransformation (aProj);
697
698         // calculate cropped frame rect
699         aTop    = (j == 0)         ? aPxCropy : 0;
700         aBottom = (j == aTotaly-1) ? aFrameHeight-(aPxCropy+anOddPixely) :
701                                      aFrameHeight;
702
703         // draw to the offscreen buffer and capture the result
704         aFrameBuffer->SetupViewport (GetGlContext());
705         Redraw1(ACView, ACUnderLayer, ACOverLayer, 0);
706         if (!myTransientDrawToFront)
707         {
708           // render to FBO only if forces to render to back buffer
709           RedrawImmediatMode();
710         }
711         glReadPixels (0, 0, aFrameWidth, aFrameHeight,
712                       GL_BGR_EXT, GL_UNSIGNED_BYTE, (GLvoid* )aViewBuffer);
713 #ifdef HAVE_FREEIMAGE
714         // cut out pixels that are out of printing area
715         isDone = imagePasteDC (hPrnDC, aViewImage, aSubLeft, aSubTop,
716                                aRight-aLeft, aBottom-aTop, aLeft, aTop);
717 #else
718         isDone = (BitBlt (hPrnDC, aSubLeft, aSubTop, aRight-aLeft, aBottom-aTop,
719                           hMemDC, aLeft, aTop, SRCCOPY) != 0); // to avoid warning C4800
720 #endif
721
722         // stop operation if errors
723         if (!isDone)
724           break;
725
726         // calculate new view offset for y-coordinate
727         aOffsety += 2.0;
728         aSubTop  += aBottom-aTop;
729       }
730
731       // stop operation if errors
732       if (!isDone)
733         break;
734
735       // calculate new view offset for x-coordinate
736       aOffsetx += 2.0;
737       aSubLeft += aRight-aLeft;
738     }
739   }
740
741   // complete printing or indicate an error
742   if (GetObjectType (hPrnDC) == OBJ_DC && isDone == true)
743   {
744     EndPage (hPrnDC);
745     EndDoc (hPrnDC);
746   }
747   else if (isDone == false)
748   {
749     MessageBox (NULL, "Print failed: insufficient memory or spool error.\nPlease use smaller printer resolution.",
750                 "The opeartion couldn't be completed.", MB_OK);
751     if (GetObjectType (hPrnDC) == OBJ_DC)
752       AbortDoc (hPrnDC);
753   }
754
755   // return OpenGl to the previous state
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().operator->());
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   myPrintContext.Nullify();
784   return (Standard_Boolean) isDone;
785
786 #else // not _WIN32
787   myPrintContext.Nullify();
788   return Standard_False;
789 #endif
790 }
791
792 /*----------------------------------------------------------------------*/
793
794 //redrawView
795 void OpenGl_Workspace::Redraw1 (const Graphic3d_CView& ACView,
796                                 const Aspect_CLayer2d& ACUnderLayer,
797                                 const Aspect_CLayer2d& ACOverLayer,
798                                 const int aswap)
799 {
800   if (myDisplay.IsNull() || myView.IsNull())
801     return;
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 (myPrintContext, 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 /*----------------------------------------------------------------------*/