0023715: Generated cmake files should link against Cocoa on Mac OS X
[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 Graphic3d_CView& ACView,
301    const Aspect_CLayer2d& ACUnderLayer,
302    const Aspect_CLayer2d& ACOverLayer,
303    const Aspect_Handle    hPrintDC,// const Aspect_Drawable hPrintDC,
304    const Standard_Boolean showBackground,
305    const Standard_CString filename,
306    const Aspect_PrintAlgo printAlgorithm,
307    const Standard_Real theScaleFactor)
308 {
309 #ifdef WNT
310
311   if (!Activate())
312   {
313     //MessageBox (NULL, "Print failed: can't setup the view for printing.",
314     //            "The operation couldn't be completed.", MB_OK);
315     return Standard_False;
316   }
317
318   // printer page dimensions
319   HDC hPrnDC = (HDC) hPrintDC;
320   int devWidth  = GetDeviceCaps (hPrnDC, HORZRES);
321   int devHeight = GetDeviceCaps (hPrnDC, VERTRES);
322
323   // if context is actually a memory dc, try to retrieve bitmap dimensions
324   // (memory dc could be used for testing purposes)
325   if (GetObjectType (hPrnDC) == OBJ_MEMDC)
326   {
327     // memory dc dimensions
328     BITMAP aBitmapInfo;
329     HBITMAP aMemoryBitmap = (HBITMAP) GetCurrentObject (hPrnDC, OBJ_BITMAP);
330     if (aMemoryBitmap)
331       if (GetObject (aMemoryBitmap, sizeof (BITMAP), &aBitmapInfo))
332       {
333         devWidth  = aBitmapInfo.bmWidth;
334         devHeight = aBitmapInfo.bmHeight;
335       }
336   }
337
338   Standard_Integer tempWidth  = (Standard_Integer) devWidth;
339   Standard_Integer tempHeight = (Standard_Integer) devHeight;
340
341   // view dimensions
342   int viewWidth  = myWidth;
343   int viewHeight = myHeight;
344   if (viewWidth == 0 || viewHeight == 0)
345   {
346     //MessageBox (NULL, "Print failed: can't setup the view for printing.",
347     //            "The operation couldn't be completed.", MB_OK);
348     return Standard_False;
349   }
350
351   // calculate correct width/height ratio
352   Standard_Real viewRatio = (Standard_Real)viewWidth/viewHeight;
353   fitDimensionsRatio(tempWidth, tempHeight, viewRatio);
354
355   // width and height for printing area
356   int width  = (int) (tempWidth  * theScaleFactor);
357   int height = (int) (tempHeight * theScaleFactor);
358
359   // device independent bitmap for the whole view
360 #ifdef HAVE_FREEIMAGE
361   FipHandle  aViewImage  = NULL;
362   BYTE*      aViewBuffer = NULL;
363 #else
364   HDC     hMemDC          = CreateCompatibleDC (hPrnDC);
365   HBITMAP hViewBitmap     = NULL;
366   HGDIOBJ hViewBitmapOld  = NULL;
367   VOID*   aViewBuffer    = NULL;
368 #endif
369
370   // Frame buffer initialization
371   OpenGl_FrameBuffer* aFrameBuffer = NULL;
372   OpenGl_FrameBuffer* aPrevBuffer = (OpenGl_FrameBuffer*) ACView.ptrFBO;
373   Standard_Integer aFrameWidth (0),  aFrameHeight (0),
374                    aPrevBufferX (0), aPrevBufferY (0);
375
376   bool IsTiling = (printAlgorithm == 1);
377
378   // try to use existing frame buffer
379   if (aPrevBuffer)
380   {
381     GLsizei aPrevWidth  = aPrevBuffer->GetSizeX();
382     GLsizei aPrevHeight = aPrevBuffer->GetSizeY();
383     bool isUsable = false;
384
385     // check if its possible to use previous frame buffer
386     if (!IsTiling && aPrevWidth >= width && aPrevHeight >= height)
387     {
388       aFrameWidth  = (Standard_Integer) width;
389       aFrameHeight = (Standard_Integer) height;
390       isUsable = true;
391     }
392     else if (IsTiling)
393     {
394       getDimensionsTiling (aFrameWidth, aFrameHeight, width, height);
395       if (aPrevWidth >= aFrameWidth && aPrevHeight >= aFrameHeight)
396         isUsable = true;
397     }
398
399     // if it is enough memory for image paste dc operation
400     if (isUsable)
401     {
402 #ifdef HAVE_FREEIMAGE
403       // try to allocate fipImage and necessary resources
404       fipImage* anImagePtr = new fipImage (FIT_BITMAP, aFrameWidth,
405                                            aFrameHeight, 24);
406
407       // if allocated succesfully
408       if (anImagePtr->isValid())
409       {
410         aViewImage  = anImagePtr;
411         aViewBuffer = aViewImage->accessPixels ();
412       }
413       else
414         delete anImagePtr;
415
416       if (!aViewBuffer)
417       {
418         isUsable = false;
419         aViewBuffer = NULL;
420         aViewImage  = NULL;
421       }
422 #else
423       // try to allocate compatible bitmap and necessary resources
424       initBitmapBuffer (hMemDC, hViewBitmap,
425                         aFrameWidth, aFrameHeight, aViewBuffer);
426       if (!aViewBuffer)
427       {
428         isUsable = false;
429         if (hViewBitmap)
430           DeleteObject (hViewBitmap);
431         hViewBitmap = NULL;
432       }
433       else
434         hViewBitmapOld = SelectObject (hMemDC, hViewBitmap);
435 #endif
436     }
437
438     // use previous frame buffer
439     if (isUsable)
440     {
441       aPrevBufferX = aPrevWidth;
442       aPrevBufferY = aPrevHeight;
443       aFrameBuffer = aPrevBuffer;
444       aFrameBuffer->ChangeViewport (aFrameWidth, aFrameHeight);
445     }
446   }
447
448   // if previous buffer cannot be used, try to init a new one
449   if (!aFrameBuffer)
450   {
451     aFrameBuffer = new OpenGl_FrameBuffer();
452
453     // try to create the framebuffer with the best possible size
454     Standard_Integer aMaxWidth(0), aMaxHeight(0);
455     getMaxFrameSize (aMaxWidth, aMaxHeight);
456     while (aMaxWidth > 1 && aMaxHeight > 1)
457     {
458       aFrameWidth  = aMaxWidth;
459       aFrameHeight = aMaxHeight;
460
461       // calculate dimensions for different printing algorithms
462       if (!IsTiling)
463         initBufferStretch (aFrameWidth, aFrameHeight, width, height);
464       else
465         initBufferTiling (aFrameWidth, aFrameHeight, width, height);
466
467       // try to initialize framebuffer
468       if (aFrameBuffer->Init (GetGlContext(), aFrameWidth, aFrameHeight))
469       {
470 #ifdef HAVE_FREEIMAGE
471         // try to allocate fipImage and necessary resources
472         fipImage* anImagePtr = new fipImage (FIT_BITMAP, aFrameWidth,
473                                             aFrameHeight, 24);
474
475         // if allocated succesfully
476         if (anImagePtr->isValid())
477         {
478           aViewImage  = anImagePtr;
479           aViewBuffer = aViewImage->accessPixels ();
480         }
481         else
482           delete anImagePtr;
483
484         if (!aViewBuffer)
485         {
486           aFrameBuffer->Release (GetGlContext());
487           aViewBuffer = NULL;
488           aViewImage  = NULL;
489         }
490         else
491           break;
492 #else
493         // try to allocate compatible bitmap and necessary resources
494         initBitmapBuffer (hMemDC, hViewBitmap,
495                           aFrameWidth, aFrameHeight, aViewBuffer);
496         if (!aViewBuffer)
497         {
498           if (hViewBitmap)
499             DeleteObject (hViewBitmap);
500           aFrameBuffer->Release (GetGlContext());
501           hViewBitmap = NULL;
502         }
503         else
504         {
505           hViewBitmapOld = SelectObject (hMemDC, hViewBitmap);
506           break;
507         }
508 #endif
509       }
510
511       // not initialized, decrease dimensions
512       aMaxWidth  = aMaxWidth  >> 1;
513       aMaxHeight = aMaxHeight >> 1;
514     }
515
516     // check if there are proper dimensions
517     if (aMaxWidth <= 1 || aMaxHeight <= 1)
518     {
519       MessageBox (NULL, "Print failed: can't allocate buffer for printing.",
520                   "The operation couldn't be completed.", MB_OK);
521
522       if (aFrameBuffer)
523         delete aFrameBuffer;
524 #ifndef HAVE_FREEIMAGE
525       if (hMemDC)
526         DeleteDC (hMemDC);
527 #endif
528
529       return Standard_False;
530     }
531   }
532
533   // setup printing context and viewport
534   GLint aViewPortBack[4];
535   GLint anAlignBack = 1;
536
537   OpenGl_PrinterContext aPrinterContext (GetGContext());
538   aPrinterContext.SetLayerViewport ((GLsizei)aFrameWidth,
539                                     (GLsizei)aFrameHeight);
540   glGetIntegerv (GL_VIEWPORT, aViewPortBack);
541   glGetIntegerv (GL_PACK_ALIGNMENT, &anAlignBack);
542   glPixelStorei (GL_PACK_ALIGNMENT, 4);
543
544   // start document if the printer context is not actually a memory dc
545   // (memory dc could be used for testing purposes)
546   DOCINFO di;
547   if (GetObjectType (hPrnDC) == OBJ_DC)
548   {
549     // Initalize printing procedure
550     di.cbSize = sizeof(DOCINFO);
551     di.lpszDocName = "Open Cascade Document - print v3d view";
552     di.lpszOutput = filename;
553
554     // if can't print the document
555     if (StartDoc (hPrnDC, &di) <= 0 || StartPage (hPrnDC) <= 0)
556     {
557       MessageBox (NULL, "Print failed: printer can't start operation.",
558                   "The operation couldn't be completed.", MB_OK);
559 #ifndef HAVE_FREEIMAGE
560       if (hViewBitmap)
561       {
562         SelectObject (hMemDC, hViewBitmapOld);
563         DeleteObject (hViewBitmap);
564       }
565       DeleteDC (hMemDC);
566 #endif
567
568       return Standard_False;
569     }
570   }
571
572   // activate the offscreen buffer
573   aFrameBuffer->BindBuffer (GetGlContext());
574
575   // calculate offset for centered printing
576   int aDevOffx = (int)(devWidth  - width) /2;
577   int aDevOffy = (int)(devHeight - height)/2;
578
579   // operation complete flag
580   bool isDone = true;
581
582   // Set up status for printing
583   if (!showBackground)
584     NamedStatus |= OPENGL_NS_WHITEBACK;
585
586   if (!IsTiling)
587   {
588     aPrinterContext.SetScale ((GLfloat)aFrameWidth /viewWidth,
589                               (GLfloat)aFrameHeight/viewHeight);
590     aFrameBuffer->SetupViewport ();
591     Redraw1(ACView, ACUnderLayer, ACOverLayer, 0);
592     if (!myTransientDrawToFront)
593     {
594       // render to FBO only if allowed to render to back buffer
595       RedrawImmediatMode();
596     }
597     glReadPixels (0, 0, aFrameWidth, aFrameHeight,
598                   GL_BGR_EXT, GL_UNSIGNED_BYTE, (GLvoid* )aViewBuffer);
599
600     // copy result to the printer device and check for errors
601 #ifdef HAVE_FREEIMAGE
602     if (!aViewImage->rescale(width, height, FILTER_BICUBIC) ||
603         !imagePasteDC (hPrnDC, aViewImage, aDevOffx, aDevOffy, width, height))
604       isDone = imageStretchDC (hPrnDC, aViewImage, aDevOffx, aDevOffy,
605                                width, height);
606 #else
607     if (width > aFrameWidth && height > aFrameHeight)
608     {
609       SetStretchBltMode (hPrnDC, STRETCH_HALFTONE);
610       isDone = (StretchBlt (hPrnDC, aDevOffx, aDevOffy, width, height,
611                             hMemDC, 0, 0, aFrameWidth, aFrameHeight, SRCCOPY) != 0); // to avoid warning C4800
612     }
613     else
614     {
615       isDone = (BitBlt (hPrnDC, aDevOffx, aDevOffy, width, height,
616                         hMemDC, 0, 0, SRCCOPY) != 0); // to avoid warning C4800
617     }
618 #endif
619   }
620   else
621   {
622     // calculate total count of frames and cropping size
623     Standard_Integer aPxCropx = 0;
624     Standard_Integer aPxCropy = 0;
625     Standard_Integer aTotalx =
626                      (Standard_Integer)floor ((float)width /aFrameWidth);
627     Standard_Integer aTotaly =
628                      (Standard_Integer)floor ((float)height/aFrameHeight);
629     if (width %aFrameWidth != 0)
630     {
631       aPxCropx = (aFrameWidth - width%aFrameWidth)/2;
632       aTotalx++;
633     }
634     if (height%aFrameHeight != 0)
635     {
636       aPxCropy = (aFrameHeight - height%aFrameHeight)/2;
637       aTotaly++;
638     }
639
640     int anOddPixelx = (width %aFrameWidth) %2;
641     int anOddPixely = (height%aFrameHeight)%2;
642
643     // calculate scale factor for full frames
644     Standard_Real aScalex = (Standard_Real)width /aFrameWidth;
645     Standard_Real aScaley = (Standard_Real)height/aFrameHeight;
646
647     // calculate and set the text scaling factor for printing context
648     GLfloat aScaleRatex = (GLfloat)aFrameWidth /viewWidth;
649     GLfloat aScaleRatey = (GLfloat)aFrameHeight/viewHeight;
650     aPrinterContext.SetScale (aScaleRatex*(GLfloat)aScalex,
651                               aScaleRatey*(GLfloat)aScaley);
652
653     // initialize projection matrix for printer context
654     TColStd_Array2OfReal aProj (0, 3, 0, 3);
655     Standard_Real aDef = 0;
656     aProj.Init (aDef);
657     aProj(2,2) = 1.0;
658     aProj(3,3) = 1.0;
659
660     // projection matrix offsets for printer context
661     // offsets are even numbers
662     Standard_Real aOffsetx(0), aOffsety(0);
663     aOffsetx = -(aTotalx-1);
664     aOffsety = -(aTotaly-1);
665
666     // rect of frame image that will be copied
667     // and coordinates in view image where to put it
668     Standard_Integer aLeft = 0, aRight = 0, aBottom = 0, aTop = 0;
669     Standard_Integer aSubLeft = (Standard_Integer)aDevOffx;
670     Standard_Integer aSubTop  = (Standard_Integer)aDevOffy;
671
672     // draw sequence of full frames
673     for (int i = 0; i < aTotalx; i++)
674     {
675       // offsets are even numbers
676       aOffsety = -(aTotaly-1);
677       aSubTop  =  (Standard_Integer)aDevOffy;
678
679       // calculate cropped frame rect
680       aLeft  = (i == 0) ? aPxCropx : 0;
681       aRight = (i == aTotalx-1) ? aFrameWidth-(aPxCropx+anOddPixelx) :
682                                   aFrameWidth;
683
684       for (int j = 0; j < aTotaly; j++)
685       {
686         // no offset for single frames
687         aProj(3,0) = (aTotalx == 1) ? 0 : -aOffsetx;
688         aProj(3,1) = (aTotaly == 1) ? 0 :  aOffsety;
689
690         // set projection matrix
691         aProj(0,0) = aScalex;
692         aProj(1,1) = aScaley;
693         aPrinterContext.SetProjTransformation (aProj);
694
695         // calculate cropped frame rect
696         aTop    = (j == 0)         ? aPxCropy : 0;
697         aBottom = (j == aTotaly-1) ? aFrameHeight-(aPxCropy+anOddPixely) :
698                                      aFrameHeight;
699
700         // draw to the offscreen buffer and capture the result
701         aFrameBuffer->SetupViewport ();
702         Redraw1(ACView, ACUnderLayer, ACOverLayer, 0);
703         if (!myTransientDrawToFront)
704         {
705           // render to FBO only if forces to render to back buffer
706           RedrawImmediatMode();
707         }
708         glReadPixels (0, 0, aFrameWidth, aFrameHeight,
709                       GL_BGR_EXT, GL_UNSIGNED_BYTE, (GLvoid* )aViewBuffer);
710 #ifdef HAVE_FREEIMAGE
711         // cut out pixels that are out of printing area
712         isDone = imagePasteDC (hPrnDC, aViewImage, aSubLeft, aSubTop,
713                                aRight-aLeft, aBottom-aTop, aLeft, aTop);
714 #else
715         isDone = (BitBlt (hPrnDC, aSubLeft, aSubTop, aRight-aLeft, aBottom-aTop,
716                           hMemDC, aLeft, aTop, SRCCOPY) != 0); // to avoid warning C4800
717 #endif
718
719         // stop operation if errors
720         if (!isDone)
721           break;
722
723         // calculate new view offset for y-coordinate
724         aOffsety += 2.0;
725         aSubTop  += aBottom-aTop;
726       }
727
728       // stop operation if errors
729       if (!isDone)
730         break;
731
732       // calculate new view offset for x-coordinate
733       aOffsetx += 2.0;
734       aSubLeft += aRight-aLeft;
735     }
736   }
737
738   // complete printing or indicate an error
739   if (GetObjectType (hPrnDC) == OBJ_DC && isDone == true)
740   {
741     EndPage (hPrnDC);
742     EndDoc (hPrnDC);
743   }
744   else if (isDone == false)
745   {
746     MessageBox (NULL, "Print failed: insufficient memory or spool error.\nPlease use smaller printer resolution.",
747                 "The opeartion couldn't be completed.", MB_OK);
748     if (GetObjectType (hPrnDC) == OBJ_DC)
749       AbortDoc (hPrnDC);
750   }
751
752   // return OpenGl to the previous state
753   aPrinterContext.Deactivate ();
754   glPixelStorei (GL_PACK_ALIGNMENT, anAlignBack);
755   aFrameBuffer->UnbindBuffer (GetGlContext());
756   glViewport (aViewPortBack[0], aViewPortBack[1],
757               aViewPortBack[2], aViewPortBack[3]);
758   if (aPrevBuffer)
759   {
760     aPrevBuffer->ChangeViewport (aPrevBufferX, aPrevBufferY);
761   }
762   else
763   {
764     aFrameBuffer->Release (GetGlContext ());
765     delete aFrameBuffer;
766   }
767
768   // delete resources
769 #ifndef HAVE_FREEIMAGE
770   if (hViewBitmap)
771   {
772     SelectObject (hMemDC, hViewBitmapOld);
773     DeleteObject (hViewBitmap);
774   }
775   DeleteDC (hMemDC);
776 #endif
777
778   // Reset status after printing
779   NamedStatus &= ~OPENGL_NS_WHITEBACK;
780
781   return (Standard_Boolean) isDone;
782
783 #else // not WNT
784   return Standard_False;
785 #endif
786 }
787
788 /*----------------------------------------------------------------------*/
789
790 //redrawView
791 void OpenGl_Workspace::Redraw1 (const Graphic3d_CView& ACView,
792                                const Aspect_CLayer2d& ACUnderLayer,
793                                const Aspect_CLayer2d& ACOverLayer,
794                                const int aswap)
795 {
796   if (myDisplay.IsNull() || myView.IsNull())
797     return;
798
799   myDisplay->UpdateUserMarkers();
800
801   // Request reset of material
802   NamedStatus |= OPENGL_NS_RESMAT;
803
804   /* GL_DITHER on/off pour le background */
805   if (myBackDither)
806     glEnable (GL_DITHER);
807   else
808     glDisable (GL_DITHER);
809
810   GLbitfield toClear = GL_COLOR_BUFFER_BIT;
811   if ( myUseZBuffer )
812   {
813     glDepthFunc(GL_LEQUAL);
814     glDepthMask(GL_TRUE);
815
816     // SAV checking if depth test was deprecated somewhere outside
817     if ( myUseDepthTest )
818       glEnable(GL_DEPTH_TEST);
819     else
820       glDisable(GL_DEPTH_TEST);
821
822     glClearDepth(1.0);
823     toClear |= GL_DEPTH_BUFFER_BIT;
824   }
825   else
826   {
827     glDisable(GL_DEPTH_TEST);
828   }
829
830   if ( NamedStatus & OPENGL_NS_WHITEBACK )
831   {
832     // Set background to white
833     glClearColor (1.F, 1.F, 1.F, 1.F);
834     toClear |= GL_DEPTH_BUFFER_BIT;
835   }
836   else
837   {
838     glClearColor (myBgColor.rgb[0], myBgColor.rgb[1], myBgColor.rgb[2], 0.F);
839   }
840   glClear (toClear);
841
842   Handle(OpenGl_Workspace) aWS(this);
843   myView->Render(aWS,ACView,ACUnderLayer,ACOverLayer);
844
845   // Swap the buffers
846   if ( aswap )
847   {
848     GetGlContext()->SwapBuffers();
849     myBackBufferRestored = Standard_False;
850   }
851   else
852     glFlush();
853 }
854
855 /*----------------------------------------------------------------------*/
856
857 //TelCopyBuffers
858 void OpenGl_Workspace::CopyBuffers (const Standard_Boolean theFrontToBack)
859 {
860   if (theFrontToBack)
861   {
862     myBackBufferRestored = Standard_False;
863   }
864
865   glMatrixMode (GL_PROJECTION);
866   glPushMatrix ();
867   glLoadIdentity ();
868   gluOrtho2D ((GLdouble) 0., (GLdouble) myWidth, 0., (GLdouble) myHeight);
869   glMatrixMode (GL_MODELVIEW);
870   glPushMatrix ();
871   glLoadIdentity ();
872
873   DisableFeatures();
874
875   glDrawBuffer (theFrontToBack ? GL_BACK  : GL_FRONT);
876   glReadBuffer (theFrontToBack ? GL_FRONT : GL_BACK);
877
878   glRasterPos2i (0, 0);
879   glCopyPixels  (0, 0, myWidth  + 1, myHeight + 1, GL_COLOR);
880
881   EnableFeatures();
882
883   glMatrixMode (GL_PROJECTION);
884   glPopMatrix ();
885   glMatrixMode (GL_MODELVIEW);
886   glPopMatrix ();
887
888   glDrawBuffer (GL_BACK);
889 }
890
891 /*----------------------------------------------------------------------*/
892
893 //call_subr_displayCB
894 void OpenGl_Workspace::DisplayCallback (const Graphic3d_CView& theCView,
895                                         int theReason)
896 {
897   if (theCView.GDisplayCB == NULL)
898   {
899     return;
900   }
901
902   Aspect_GraphicCallbackStruct aCallData;
903   aCallData.reason    = theReason;
904   aCallData.glContext = GetGlContext();
905   aCallData.wsID      = theCView.WsId;
906   aCallData.viewID    = theCView.ViewId;
907   theCView.GDisplayCB (theCView.DefWindow.XWindow, theCView.GClientData, &aCallData);
908 }
909
910 /*----------------------------------------------------------------------*/