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