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