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