1 // Created on: 2011-09-20
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <OpenGl_GlCore11.hxx>
18 #include <OpenGl_FrameBuffer.hxx>
19 #include <TColStd_Array2OfReal.hxx>
20 #include <OpenGl_telem_util.hxx>
26 #if (defined(_WIN32) || defined(__WIN32__)) && defined(HAVE_FREEIMAGE)
27 #include <NCollection_Handle.hxx>
28 #include <FreeImagePlus.h>
30 #pragma comment( lib, "FreeImage.lib" )
31 #pragma comment( lib, "FreeImagePlus.lib" )
33 typedef NCollection_Handle<fipImage> FipHandle;
36 #include <OpenGl_PrinterContext.hxx>
37 #include <OpenGl_Workspace.hxx>
38 #include <OpenGl_View.hxx>
42 #ifndef HAVE_FREEIMAGE
44 // ---------------------------------------------------------------
45 // Function: initBitmapBuffer
46 // Purpose: init device independent bitmap to hold printing data
47 // ---------------------------------------------------------------
48 static void initBitmapBuffer (const HDC theMemoryDC,
49 HBITMAP &theMemoryBmp,
50 const Standard_Integer theBmpWidth,
51 const Standard_Integer theBmpHeight,
54 // define compatible bitmap
55 BITMAPINFO aBitmapData;
56 memset (&aBitmapData, 0, sizeof (BITMAPINFOHEADER));
57 aBitmapData.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
58 aBitmapData.bmiHeader.biWidth = theBmpWidth;
59 aBitmapData.bmiHeader.biHeight = theBmpHeight;
60 aBitmapData.bmiHeader.biPlanes = 1;
61 aBitmapData.bmiHeader.biBitCount = 24;
62 aBitmapData.bmiHeader.biXPelsPerMeter = 0;
63 aBitmapData.bmiHeader.biYPelsPerMeter = 0;
64 aBitmapData.bmiHeader.biClrUsed = 0;
65 aBitmapData.bmiHeader.biClrImportant = 0;
66 aBitmapData.bmiHeader.biCompression = BI_RGB;
67 aBitmapData.bmiHeader.biSizeImage = 0;
69 // Create Device Independent Bitmap
70 theMemoryBmp = CreateDIBSection (theMemoryDC, &aBitmapData, DIB_RGB_COLORS,
71 &theBufferPtr, NULL, 0);
74 #else /* HAVE_FREEIMAGE */
76 // ---------------------------------------------------------------
77 // Function: imagePasteDC
78 // Purpose: copy the data from image buffer to the device context
79 // ---------------------------------------------------------------
80 static bool imagePasteDC(HDC theDstDC, FipHandle theImage, int theOffsetX,
81 int theOffsetY, int theWidth, int theHeight,
82 int theLeft = 0, int theTop = 0)
84 // get image parameters
85 BITMAPINFO* aBitmapData = theImage->getInfo ();
86 SetStretchBltMode (theDstDC, STRETCH_HALFTONE);
88 // organize blocks data passing if memory isn't enough to pass all the data
90 int aLinesComplete = 0, aMaxBlockWidth = theHeight, aBlockWidth = 0,
91 aPassed = 0, aInverseLine = 0, aScan = 0;
93 while (aMaxBlockWidth >= 1 && aLinesComplete < theHeight)
95 // how much lines still to pass
96 aBlockWidth = theHeight - aLinesComplete;
98 // normalize count of lines to pass to maximum lines count at one pass.
99 if (aBlockWidth > aMaxBlockWidth)
100 aBlockWidth = aMaxBlockWidth;
102 // access image data at the start scan line, we need to calculate scan from
103 // the bottom of image (image is bottom-left, the src coord is top-left)
104 aInverseLine = theTop + aBlockWidth + aLinesComplete;
105 aScan = theImage->getHeight() - aInverseLine;
106 aDataPtr = theImage->getScanLine (aScan);
110 // try to pass block to the device
113 // instead of banded output we provide blocked as it isn't always passed
114 // to printer as it is expected
115 aPassed = SetDIBitsToDevice (theDstDC, theOffsetX,
116 theOffsetY + aLinesComplete,
117 theWidth, aBlockWidth, theLeft, 0,
119 aDataPtr, aBitmapData, DIB_RGB_COLORS);
121 // if result is bad, try to decrease band width
122 if (aPassed != aBlockWidth)
124 aMaxBlockWidth = aMaxBlockWidth >> 1;
128 aLinesComplete += aBlockWidth;
132 // check for total failure
133 if (aMaxBlockWidth < 1)
139 // ---------------------------------------------------------------
140 // Function: imageStretchDC
141 // Purpose: copy pixels from image to dc by stretching them
142 // ---------------------------------------------------------------
143 static bool imageStretchDC(HDC theDstDC, FipHandle theImage, int theOffsetX,
144 int theOffsetY, int theWidth, int theHeight)
146 // access to raw image data
147 BYTE *aDataPtr = theImage->accessPixels ();
151 // get image parameters
152 unsigned int widthPx = theImage->getWidth ();
153 unsigned int heightPx = theImage->getHeight ();
154 BITMAPINFO* aBitmapData = theImage->getInfo ();
155 SetStretchBltMode (theDstDC, STRETCH_HALFTONE);
157 // pass lines and check if operation is succesfull
159 aPassed = StretchDIBits (theDstDC, theOffsetX, theOffsetY, theWidth,
160 theHeight, 0, 0, widthPx, heightPx, aDataPtr,
161 aBitmapData, DIB_RGB_COLORS, SRCCOPY);
163 if ((unsigned)aPassed != heightPx)
169 #endif /* HAVE_FREEIMAGE */
171 // ---------------------------------------------------------------
172 // Function: getNearestPowOfTwo
173 // Purpose: get the nearest power of two for theNumber
174 // ---------------------------------------------------------------
175 static GLsizei getNearestPowOfTwo (const GLsizei theNumber)
178 for (GLsizei p2 = 1; p2 <= theNumber; aLast = p2, p2 <<= 1);
182 // ---------------------------------------------------------------
183 // Function: getMaxFrameSize
184 // Purpose: get the maximum possible frame size
185 // ---------------------------------------------------------------
186 static void getMaxFrameSize(Standard_Integer& theWidth,
187 Standard_Integer& theHeight)
189 GLsizei aMaxX, aMaxY;
191 GLint aTexDim = 2048;
192 glGetIntegerv (GL_MAX_VIEWPORT_DIMS, (GLint*) &aVpDim);
193 glGetIntegerv (GL_MAX_TEXTURE_SIZE, &aTexDim);
194 (aVpDim[0] >= aTexDim) ? aMaxX = (GLsizei) aTexDim :
195 aMaxX = getNearestPowOfTwo((GLsizei)aVpDim[0]);
196 (aVpDim[1] >= aTexDim) ? aMaxY = (GLsizei) aTexDim :
197 aMaxY = getNearestPowOfTwo((GLsizei)aVpDim[1]);
199 theWidth = (Standard_Integer)aMaxX;
200 theHeight = (Standard_Integer)aMaxY;
203 // ---------------------------------------------------------------
204 // Function: fitDimensionsRatio
205 // Purpose: calculate correct width/height ratio for theWidth and
206 // theHeight parameters
207 // ---------------------------------------------------------------
208 static void fitDimensionsRatio (Standard_Integer& theWidth,
209 Standard_Integer& theHeight,
210 const Standard_Real theViewRatio)
212 // set dimensions in accordance with the viewratio
213 if (theHeight < theWidth/theViewRatio)
214 theWidth = (Standard_Integer)(theHeight*theViewRatio);
216 if (theWidth < theHeight*theViewRatio)
217 theHeight = (Standard_Integer)(theWidth/theViewRatio);
220 // ---------------------------------------------------------------
221 // Function: initBufferStretch
222 // Purpose: calculate initialization sizes for frame buffer
223 // when the stretch algorithm is selected
224 // ---------------------------------------------------------------
225 static void initBufferStretch (Standard_Integer& theFrameWidth,
226 Standard_Integer& theFrameHeight,
227 const int theViewWidth,
228 const int theViewHeight)
231 // Calculate correct width/height for framebuffer
232 Standard_Real aViewRatio = (Standard_Real)theViewWidth/theViewHeight;
233 fitDimensionsRatio (theFrameWidth, theFrameHeight, aViewRatio);
235 // downscale the framebuffer if it is too large
236 Standard_Real aWidthRate = (Standard_Real)theFrameWidth /theViewWidth;
237 Standard_Real aHeightRate = (Standard_Real)theFrameHeight/theViewHeight;
239 if ((aWidthRate > 1 && aHeightRate > 1 && aWidthRate >= aHeightRate) ||
240 (aWidthRate > 1 && aHeightRate <= 1))
242 theFrameWidth = (Standard_Integer)(theFrameWidth /aWidthRate);
243 theFrameHeight = (Standard_Integer)(theFrameHeight/aWidthRate);
245 else if ((aWidthRate > 1 && aHeightRate > 1 && aWidthRate < aHeightRate) ||
246 (aWidthRate <= 1 && aHeightRate > 1))
248 theFrameWidth = (Standard_Integer)(theFrameWidth /aHeightRate);
249 theFrameHeight = (Standard_Integer)(theFrameHeight/aHeightRate);
252 // ---------------------------------------------------------------
253 // Function: initBufferTiling
254 // Purpose: calculate initialization sizes for frame buffer
255 // when the tile algorithm is selected
256 // ---------------------------------------------------------------
257 static void initBufferTiling (Standard_Integer& theFrameWidth,
258 Standard_Integer &theFrameHeight,
259 const int theViewWidth,
260 const int theViewHeight)
262 // fit framebuffer into the printing area
263 if (theFrameWidth > theViewWidth)
264 theFrameWidth = theViewWidth;
266 if (theFrameHeight > theViewHeight)
267 theFrameHeight = theViewHeight;
272 // ---------------------------------------------------------------
273 // ---------------------------------------------------------------
277 Standard_Boolean OpenGl_Workspace::Print
278 (const Handle(OpenGl_PrinterContext)& thePrintContext,
279 const Graphic3d_CView& ACView,
280 const Aspect_CLayer2d& ACUnderLayer,
281 const Aspect_CLayer2d& ACOverLayer,
282 const Aspect_Handle hPrintDC,// const Aspect_Drawable hPrintDC,
283 const Standard_Boolean showBackground,
284 const Standard_CString filename,
285 const Aspect_PrintAlgo printAlgorithm,
286 const Standard_Real theScaleFactor)
288 if (thePrintContext.IsNull())
290 return Standard_False;
297 //MessageBox (NULL, "Print failed: can't setup the view for printing.",
298 // "The operation couldn't be completed.", MB_OK);
299 return Standard_False;
302 // printer page dimensions
303 HDC hPrnDC = (HDC) hPrintDC;
304 int devWidth = GetDeviceCaps (hPrnDC, HORZRES);
305 int devHeight = GetDeviceCaps (hPrnDC, VERTRES);
307 // if context is actually a memory dc, try to retrieve bitmap dimensions
308 // (memory dc could be used for testing purposes)
309 if (GetObjectType (hPrnDC) == OBJ_MEMDC)
311 // memory dc dimensions
313 HBITMAP aMemoryBitmap = (HBITMAP) GetCurrentObject (hPrnDC, OBJ_BITMAP);
315 if (GetObject (aMemoryBitmap, sizeof (BITMAP), &aBitmapInfo))
317 devWidth = aBitmapInfo.bmWidth;
318 devHeight = aBitmapInfo.bmHeight;
322 Standard_Integer tempWidth = (Standard_Integer) devWidth;
323 Standard_Integer tempHeight = (Standard_Integer) devHeight;
326 int viewWidth = myWidth;
327 int viewHeight = myHeight;
328 if (viewWidth == 0 || viewHeight == 0)
330 //MessageBox (NULL, "Print failed: can't setup the view for printing.",
331 // "The operation couldn't be completed.", MB_OK);
332 return Standard_False;
335 // calculate correct width/height ratio
336 Standard_Real viewRatio = (Standard_Real)viewWidth/viewHeight;
337 fitDimensionsRatio(tempWidth, tempHeight, viewRatio);
339 // width and height for printing area
340 int width = (int) (tempWidth * theScaleFactor);
341 int height = (int) (tempHeight * theScaleFactor);
343 // device independent bitmap for the whole view
344 #ifdef HAVE_FREEIMAGE
345 FipHandle aViewImage = NULL;
346 BYTE* aViewBuffer = NULL;
348 HDC hMemDC = CreateCompatibleDC (hPrnDC);
349 HBITMAP hViewBitmap = NULL;
350 HGDIOBJ hViewBitmapOld = NULL;
351 VOID* aViewBuffer = NULL;
354 // Frame buffer initialization
355 OpenGl_FrameBuffer* aFrameBuffer = NULL;
356 OpenGl_FrameBuffer* aPrevBuffer = (OpenGl_FrameBuffer*) ACView.ptrFBO;
357 Standard_Integer aFrameWidth (0), aFrameHeight (0),
358 aPrevBufferX (0), aPrevBufferY (0);
360 bool IsTiling = (printAlgorithm == 1);
362 // try to use existing frame buffer
365 GLsizei aPrevWidth = aPrevBuffer->GetSizeX();
366 GLsizei aPrevHeight = aPrevBuffer->GetSizeY();
367 bool isUsable = false;
369 // check if its possible to use previous frame buffer
370 if (!IsTiling && aPrevWidth >= width && aPrevHeight >= height)
372 aFrameWidth = (Standard_Integer) width;
373 aFrameHeight = (Standard_Integer) height;
378 // use previous frame buffer with its dimensions
379 aFrameWidth = aPrevWidth;
380 aFrameHeight = aPrevHeight;
384 // if it is enough memory for image paste dc operation
387 #ifdef HAVE_FREEIMAGE
388 // try to allocate fipImage and necessary resources
389 fipImage* anImagePtr = new fipImage (FIT_BITMAP, aFrameWidth,
392 // if allocated succesfully
393 if (anImagePtr->isValid())
395 aViewImage = anImagePtr;
396 aViewBuffer = aViewImage->accessPixels ();
408 // try to allocate compatible bitmap and necessary resources
409 initBitmapBuffer (hMemDC, hViewBitmap,
410 aFrameWidth, aFrameHeight, aViewBuffer);
415 DeleteObject (hViewBitmap);
419 hViewBitmapOld = SelectObject (hMemDC, hViewBitmap);
423 // use previous frame buffer
426 aPrevBufferX = aPrevWidth;
427 aPrevBufferY = aPrevHeight;
428 aFrameBuffer = aPrevBuffer;
429 aFrameBuffer->ChangeViewport (aFrameWidth, aFrameHeight);
433 // if previous buffer cannot be used, try to init a new one
436 aFrameBuffer = new OpenGl_FrameBuffer();
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)
443 aFrameWidth = aMaxWidth;
444 aFrameHeight = aMaxHeight;
446 // calculate dimensions for different printing algorithms
448 initBufferStretch (aFrameWidth, aFrameHeight, width, height);
450 initBufferTiling (aFrameWidth, aFrameHeight, width, height);
452 // try to initialize framebuffer
453 if (aFrameBuffer->Init (GetGlContext(), aFrameWidth, aFrameHeight))
455 #ifdef HAVE_FREEIMAGE
456 // try to allocate fipImage and necessary resources
457 fipImage* anImagePtr = new fipImage (FIT_BITMAP, aFrameWidth,
460 // if allocated succesfully
461 if (anImagePtr->isValid())
463 aViewImage = anImagePtr;
464 aViewBuffer = aViewImage->accessPixels ();
471 aFrameBuffer->Release (GetGlContext().operator->());
478 // try to allocate compatible bitmap and necessary resources
479 initBitmapBuffer (hMemDC, hViewBitmap,
480 aFrameWidth, aFrameHeight, aViewBuffer);
484 DeleteObject (hViewBitmap);
485 aFrameBuffer->Release (GetGlContext().operator->());
490 hViewBitmapOld = SelectObject (hMemDC, hViewBitmap);
496 // not initialized, decrease dimensions
497 aMaxWidth = aMaxWidth >> 1;
498 aMaxHeight = aMaxHeight >> 1;
501 // check if there are proper dimensions
502 if (aMaxWidth <= 1 || aMaxHeight <= 1)
504 MessageBox (NULL, "Print failed: can't allocate buffer for printing.",
505 "The operation couldn't be completed.", MB_OK);
509 #ifndef HAVE_FREEIMAGE
514 return Standard_False;
518 // setup printing context and viewport
519 myPrintContext = thePrintContext;
520 GLint aViewPortBack[4];
521 GLint anAlignBack = 1;
522 myPrintContext->SetLayerViewport ((GLsizei )aFrameWidth,
523 (GLsizei )aFrameHeight);
524 glGetIntegerv (GL_VIEWPORT, aViewPortBack);
525 glGetIntegerv (GL_PACK_ALIGNMENT, &anAlignBack);
526 glPixelStorei (GL_PACK_ALIGNMENT, 4);
528 // start document if the printer context is not actually a memory dc
529 // (memory dc could be used for testing purposes)
531 if (GetObjectType (hPrnDC) == OBJ_DC)
533 // Initalize printing procedure
534 di.cbSize = sizeof(DOCINFO);
535 di.lpszDocName = "Open Cascade Document - print v3d view";
536 di.lpszOutput = filename;
538 // if can't print the document
539 if (StartDoc (hPrnDC, &di) <= 0 || StartPage (hPrnDC) <= 0)
541 MessageBox (NULL, "Print failed: printer can't start operation.",
542 "The operation couldn't be completed.", MB_OK);
543 #ifndef HAVE_FREEIMAGE
546 SelectObject (hMemDC, hViewBitmapOld);
547 DeleteObject (hViewBitmap);
552 myPrintContext.Nullify();
553 return Standard_False;
557 // activate the offscreen buffer
558 aFrameBuffer->BindBuffer (GetGlContext());
560 // calculate offset for centered printing
561 int aDevOffx = (int)(devWidth - width) /2;
562 int aDevOffy = (int)(devHeight - height)/2;
564 // operation complete flag
567 // Set up status for printing
569 NamedStatus |= OPENGL_NS_WHITEBACK;
573 myPrintContext->SetScale ((GLfloat )aFrameWidth /viewWidth,
574 (GLfloat )aFrameHeight/viewHeight);
575 aFrameBuffer->SetupViewport (GetGlContext());
576 redraw1 (ACView, ACUnderLayer, ACOverLayer, 0);
577 if (!myTransientDrawToFront)
579 // render to FBO only if allowed to render to back buffer
580 RedrawImmediate (ACView, ACUnderLayer, ACOverLayer, Standard_True);
582 glReadPixels (0, 0, aFrameWidth, aFrameHeight,
583 GL_BGR_EXT, GL_UNSIGNED_BYTE, (GLvoid* )aViewBuffer);
585 // copy result to the printer device and check for errors
586 #ifdef HAVE_FREEIMAGE
587 if (!aViewImage->rescale(width, height, FILTER_BICUBIC) ||
588 !imagePasteDC (hPrnDC, aViewImage, aDevOffx, aDevOffy, width, height))
589 isDone = imageStretchDC (hPrnDC, aViewImage, aDevOffx, aDevOffy,
592 if (width > aFrameWidth && height > aFrameHeight)
594 SetStretchBltMode (hPrnDC, STRETCH_HALFTONE);
595 isDone = (StretchBlt (hPrnDC, aDevOffx, aDevOffy, width, height,
596 hMemDC, 0, 0, aFrameWidth, aFrameHeight, SRCCOPY) != 0); // to avoid warning C4800
600 isDone = (BitBlt (hPrnDC, aDevOffx, aDevOffy, width, height,
601 hMemDC, 0, 0, SRCCOPY) != 0); // to avoid warning C4800
607 // calculate total count of frames and cropping size
608 Standard_Integer aPxCropx = 0;
609 Standard_Integer aPxCropy = 0;
610 Standard_Integer aTotalx =
611 (Standard_Integer)floor ((float)width /aFrameWidth);
612 Standard_Integer aTotaly =
613 (Standard_Integer)floor ((float)height/aFrameHeight);
614 if (width %aFrameWidth != 0)
616 aPxCropx = (aFrameWidth - width%aFrameWidth)/2;
619 if (height%aFrameHeight != 0)
621 aPxCropy = (aFrameHeight - height%aFrameHeight)/2;
625 int anOddPixelx = (width %aFrameWidth) %2;
626 int anOddPixely = (height%aFrameHeight)%2;
628 // calculate scale factor for full frames
629 Standard_Real aScalex = (Standard_Real)width /aFrameWidth;
630 Standard_Real aScaley = (Standard_Real)height/aFrameHeight;
632 // calculate and set the text scaling factor for printing context
633 GLfloat aScaleRatex = (GLfloat)aFrameWidth /viewWidth;
634 GLfloat aScaleRatey = (GLfloat)aFrameHeight/viewHeight;
635 myPrintContext->SetScale (aScaleRatex * (GLfloat )aScalex,
636 aScaleRatey * (GLfloat )aScaley);
638 // initialize projection matrix for printer context
639 TColStd_Array2OfReal aProj (0, 3, 0, 3);
640 Standard_Real aDef = 0;
645 // projection matrix offsets for printer context
646 // offsets are even numbers
647 Standard_Real aOffsetx(0), aOffsety(0);
648 aOffsetx = -(aTotalx-1);
649 aOffsety = -(aTotaly-1);
651 // rect of frame image that will be copied
652 // and coordinates in view image where to put it
653 Standard_Integer aLeft = 0, aRight = 0, aBottom = 0, aTop = 0;
654 Standard_Integer aSubLeft = (Standard_Integer)aDevOffx;
655 Standard_Integer aSubTop = (Standard_Integer)aDevOffy;
657 // draw sequence of full frames
658 for (int i = 0; i < aTotalx; i++)
660 // offsets are even numbers
661 aOffsety = -(aTotaly-1);
662 aSubTop = (Standard_Integer)aDevOffy;
664 // calculate cropped frame rect
665 aLeft = (i == 0) ? aPxCropx : 0;
666 aRight = (i == aTotalx-1) ? aFrameWidth-(aPxCropx+anOddPixelx) :
669 for (int j = 0; j < aTotaly; j++)
671 // no offset for single frames
672 aProj(3,0) = (aTotalx == 1) ? 0 : -aOffsetx;
673 aProj(3,1) = (aTotaly == 1) ? 0 : aOffsety;
675 // set projection matrix
676 aProj(0,0) = aScalex;
677 aProj(1,1) = aScaley;
678 myPrintContext->SetProjTransformation (aProj);
680 // calculate cropped frame rect
681 aTop = (j == 0) ? aPxCropy : 0;
682 aBottom = (j == aTotaly-1) ? aFrameHeight-(aPxCropy+anOddPixely) :
685 // draw to the offscreen buffer and capture the result
686 aFrameBuffer->SetupViewport (GetGlContext());
687 redraw1 (ACView, ACUnderLayer, ACOverLayer, 0);
688 if (!myTransientDrawToFront)
690 // render to FBO only if forces to render to back buffer
691 RedrawImmediate (ACView, ACUnderLayer, ACOverLayer, Standard_True);
693 glReadPixels (0, 0, aFrameWidth, aFrameHeight,
694 GL_BGR_EXT, GL_UNSIGNED_BYTE, (GLvoid* )aViewBuffer);
695 #ifdef HAVE_FREEIMAGE
696 // cut out pixels that are out of printing area
697 isDone = imagePasteDC (hPrnDC, aViewImage, aSubLeft, aSubTop,
698 aRight-aLeft, aBottom-aTop, aLeft, aTop);
700 isDone = (BitBlt (hPrnDC, aSubLeft, aSubTop, aRight-aLeft, aBottom-aTop,
701 hMemDC, aLeft, aTop, SRCCOPY) != 0); // to avoid warning C4800
704 // stop operation if errors
708 // calculate new view offset for y-coordinate
710 aSubTop += aBottom-aTop;
713 // stop operation if errors
717 // calculate new view offset for x-coordinate
719 aSubLeft += aRight-aLeft;
723 // complete printing or indicate an error
724 if (GetObjectType (hPrnDC) == OBJ_DC && isDone == true)
729 else if (isDone == false)
731 MessageBox (NULL, "Print failed: insufficient memory or spool error.\nPlease use smaller printer resolution.",
732 "The opeartion couldn't be completed.", MB_OK);
733 if (GetObjectType (hPrnDC) == OBJ_DC)
737 // return OpenGl to the previous state
738 glPixelStorei (GL_PACK_ALIGNMENT, anAlignBack);
739 aFrameBuffer->UnbindBuffer (GetGlContext());
740 glViewport (aViewPortBack[0], aViewPortBack[1],
741 aViewPortBack[2], aViewPortBack[3]);
744 aPrevBuffer->ChangeViewport (aPrevBufferX, aPrevBufferY);
748 aFrameBuffer->Release (GetGlContext().operator->());
753 #ifndef HAVE_FREEIMAGE
756 SelectObject (hMemDC, hViewBitmapOld);
757 DeleteObject (hViewBitmap);
762 // Reset status after printing
763 NamedStatus &= ~OPENGL_NS_WHITEBACK;
765 myPrintContext.Nullify();
766 return (Standard_Boolean) isDone;
769 myPrintContext.Nullify();
770 return Standard_False;