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>
21 #include <Graphic3d_GraphicDriver.hxx>
23 #include <OpenGl_PrinterContext.hxx>
24 #include <OpenGl_Workspace.hxx>
25 #include <OpenGl_View.hxx>
27 #if (defined(_WIN32) || defined(__WIN32__)) && defined(HAVE_FREEIMAGE)
28 #include <NCollection_Handle.hxx>
29 #include <FreeImagePlus.h>
31 #pragma comment( lib, "FreeImage.lib" )
32 #pragma comment( lib, "FreeImagePlus.lib" )
34 typedef NCollection_Handle<fipImage> FipHandle;
39 #ifndef HAVE_FREEIMAGE
41 // ---------------------------------------------------------------
42 // Function: initBitmapBuffer
43 // Purpose: init device independent bitmap to hold printing data
44 // ---------------------------------------------------------------
45 static void initBitmapBuffer (const HDC theMemoryDC,
46 HBITMAP &theMemoryBmp,
47 const Standard_Integer theBmpWidth,
48 const Standard_Integer theBmpHeight,
51 // define compatible bitmap
52 BITMAPINFO aBitmapData;
53 memset (&aBitmapData, 0, sizeof (BITMAPINFOHEADER));
54 aBitmapData.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
55 aBitmapData.bmiHeader.biWidth = theBmpWidth;
56 aBitmapData.bmiHeader.biHeight = theBmpHeight;
57 aBitmapData.bmiHeader.biPlanes = 1;
58 aBitmapData.bmiHeader.biBitCount = 24;
59 aBitmapData.bmiHeader.biXPelsPerMeter = 0;
60 aBitmapData.bmiHeader.biYPelsPerMeter = 0;
61 aBitmapData.bmiHeader.biClrUsed = 0;
62 aBitmapData.bmiHeader.biClrImportant = 0;
63 aBitmapData.bmiHeader.biCompression = BI_RGB;
64 aBitmapData.bmiHeader.biSizeImage = 0;
66 // Create Device Independent Bitmap
67 theMemoryBmp = CreateDIBSection (theMemoryDC, &aBitmapData, DIB_RGB_COLORS,
68 &theBufferPtr, NULL, 0);
71 #else /* HAVE_FREEIMAGE */
73 // ---------------------------------------------------------------
74 // Function: imagePasteDC
75 // Purpose: copy the data from image buffer to the device context
76 // ---------------------------------------------------------------
77 static bool imagePasteDC(HDC theDstDC, FipHandle theImage, int theOffsetX,
78 int theOffsetY, int theWidth, int theHeight,
79 int theLeft = 0, int theTop = 0)
81 // get image parameters
82 BITMAPINFO* aBitmapData = theImage->getInfo ();
83 SetStretchBltMode (theDstDC, STRETCH_HALFTONE);
85 // organize blocks data passing if memory isn't enough to pass all the data
87 int aLinesComplete = 0, aMaxBlockWidth = theHeight, aBlockWidth = 0,
88 aPassed = 0, aInverseLine = 0, aScan = 0;
90 while (aMaxBlockWidth >= 1 && aLinesComplete < theHeight)
92 // how much lines still to pass
93 aBlockWidth = theHeight - aLinesComplete;
95 // normalize count of lines to pass to maximum lines count at one pass.
96 if (aBlockWidth > aMaxBlockWidth)
97 aBlockWidth = aMaxBlockWidth;
99 // access image data at the start scan line, we need to calculate scan from
100 // the bottom of image (image is bottom-left, the src coord is top-left)
101 aInverseLine = theTop + aBlockWidth + aLinesComplete;
102 aScan = theImage->getHeight() - aInverseLine;
103 aDataPtr = theImage->getScanLine (aScan);
107 // try to pass block to the device
110 // instead of banded output we provide blocked as it isn't always passed
111 // to printer as it is expected
112 aPassed = SetDIBitsToDevice (theDstDC, theOffsetX,
113 theOffsetY + aLinesComplete,
114 theWidth, aBlockWidth, theLeft, 0,
116 aDataPtr, aBitmapData, DIB_RGB_COLORS);
118 // if result is bad, try to decrease band width
119 if (aPassed != aBlockWidth)
121 aMaxBlockWidth = aMaxBlockWidth >> 1;
125 aLinesComplete += aBlockWidth;
129 // check for total failure
130 if (aMaxBlockWidth < 1)
136 // ---------------------------------------------------------------
137 // Function: imageStretchDC
138 // Purpose: copy pixels from image to dc by stretching them
139 // ---------------------------------------------------------------
140 static bool imageStretchDC(HDC theDstDC, FipHandle theImage, int theOffsetX,
141 int theOffsetY, int theWidth, int theHeight)
143 // access to raw image data
144 BYTE *aDataPtr = theImage->accessPixels ();
148 // get image parameters
149 unsigned int widthPx = theImage->getWidth ();
150 unsigned int heightPx = theImage->getHeight ();
151 BITMAPINFO* aBitmapData = theImage->getInfo ();
152 SetStretchBltMode (theDstDC, STRETCH_HALFTONE);
154 // pass lines and check if operation is succesfull
156 aPassed = StretchDIBits (theDstDC, theOffsetX, theOffsetY, theWidth,
157 theHeight, 0, 0, widthPx, heightPx, aDataPtr,
158 aBitmapData, DIB_RGB_COLORS, SRCCOPY);
160 if ((unsigned)aPassed != heightPx)
166 #endif /* HAVE_FREEIMAGE */
168 // ---------------------------------------------------------------
169 // Function: getNearestPowOfTwo
170 // Purpose: get the nearest power of two for theNumber
171 // ---------------------------------------------------------------
172 static GLsizei getNearestPowOfTwo (const GLsizei theNumber)
175 for (GLsizei p2 = 1; p2 <= theNumber; aLast = p2, p2 <<= 1);
179 // ---------------------------------------------------------------
180 // Function: getMaxFrameSize
181 // Purpose: get the maximum possible frame size
182 // ---------------------------------------------------------------
183 static void getMaxFrameSize(Standard_Integer& theWidth,
184 Standard_Integer& theHeight)
186 GLsizei aMaxX, aMaxY;
188 GLint aTexDim = 2048;
189 glGetIntegerv (GL_MAX_VIEWPORT_DIMS, (GLint*) &aVpDim);
190 glGetIntegerv (GL_MAX_TEXTURE_SIZE, &aTexDim);
191 (aVpDim[0] >= aTexDim) ? aMaxX = (GLsizei) aTexDim :
192 aMaxX = getNearestPowOfTwo((GLsizei)aVpDim[0]);
193 (aVpDim[1] >= aTexDim) ? aMaxY = (GLsizei) aTexDim :
194 aMaxY = getNearestPowOfTwo((GLsizei)aVpDim[1]);
196 theWidth = (Standard_Integer)aMaxX;
197 theHeight = (Standard_Integer)aMaxY;
200 // ---------------------------------------------------------------
201 // Function: fitDimensionsRatio
202 // Purpose: calculate correct width/height ratio for theWidth and
203 // theHeight parameters
204 // ---------------------------------------------------------------
205 static void fitDimensionsRatio (Standard_Integer& theWidth,
206 Standard_Integer& theHeight,
207 const Standard_Real theViewRatio)
209 // set dimensions in accordance with the viewratio
210 if (theHeight < theWidth/theViewRatio)
211 theWidth = (Standard_Integer)(theHeight*theViewRatio);
213 if (theWidth < theHeight*theViewRatio)
214 theHeight = (Standard_Integer)(theWidth/theViewRatio);
217 // ---------------------------------------------------------------
218 // Function: initBufferStretch
219 // Purpose: calculate initialization sizes for frame buffer
220 // when the stretch algorithm is selected
221 // ---------------------------------------------------------------
222 static void initBufferStretch (Standard_Integer& theFrameWidth,
223 Standard_Integer& theFrameHeight,
224 const int theViewWidth,
225 const int theViewHeight)
228 // Calculate correct width/height for framebuffer
229 Standard_Real aViewRatio = (Standard_Real)theViewWidth/theViewHeight;
230 fitDimensionsRatio (theFrameWidth, theFrameHeight, aViewRatio);
232 // downscale the framebuffer if it is too large
233 Standard_Real aWidthRate = (Standard_Real)theFrameWidth /theViewWidth;
234 Standard_Real aHeightRate = (Standard_Real)theFrameHeight/theViewHeight;
236 if ((aWidthRate > 1 && aHeightRate > 1 && aWidthRate >= aHeightRate) ||
237 (aWidthRate > 1 && aHeightRate <= 1))
239 theFrameWidth = (Standard_Integer)(theFrameWidth /aWidthRate);
240 theFrameHeight = (Standard_Integer)(theFrameHeight/aWidthRate);
242 else if ((aWidthRate > 1 && aHeightRate > 1 && aWidthRate < aHeightRate) ||
243 (aWidthRate <= 1 && aHeightRate > 1))
245 theFrameWidth = (Standard_Integer)(theFrameWidth /aHeightRate);
246 theFrameHeight = (Standard_Integer)(theFrameHeight/aHeightRate);
249 // ---------------------------------------------------------------
250 // Function: initBufferTiling
251 // Purpose: calculate initialization sizes for frame buffer
252 // when the tile algorithm is selected
253 // ---------------------------------------------------------------
254 static void initBufferTiling (Standard_Integer& theFrameWidth,
255 Standard_Integer &theFrameHeight,
256 const int theViewWidth,
257 const int theViewHeight)
259 // fit framebuffer into the printing area
260 if (theFrameWidth > theViewWidth)
261 theFrameWidth = theViewWidth;
263 if (theFrameHeight > theViewHeight)
264 theFrameHeight = theViewHeight;
269 // ---------------------------------------------------------------
270 // ---------------------------------------------------------------
274 Standard_Boolean OpenGl_Workspace::Print
275 (const Handle(OpenGl_PrinterContext)& thePrintContext,
276 const Graphic3d_CView& ACView,
277 const Aspect_CLayer2d& ACUnderLayer,
278 const Aspect_CLayer2d& ACOverLayer,
279 const Aspect_Handle hPrintDC,// const Aspect_Drawable hPrintDC,
280 const Standard_Boolean showBackground,
281 const Standard_CString filename,
282 const Aspect_PrintAlgo printAlgorithm,
283 const Standard_Real theScaleFactor)
285 if (thePrintContext.IsNull())
287 return Standard_False;
294 //MessageBox (NULL, "Print failed: can't setup the view for printing.",
295 // "The operation couldn't be completed.", MB_OK);
296 return Standard_False;
299 // printer page dimensions
300 HDC hPrnDC = (HDC) hPrintDC;
301 int devWidth = GetDeviceCaps (hPrnDC, HORZRES);
302 int devHeight = GetDeviceCaps (hPrnDC, VERTRES);
304 // if context is actually a memory dc, try to retrieve bitmap dimensions
305 // (memory dc could be used for testing purposes)
306 if (GetObjectType (hPrnDC) == OBJ_MEMDC)
308 // memory dc dimensions
310 HBITMAP aMemoryBitmap = (HBITMAP) GetCurrentObject (hPrnDC, OBJ_BITMAP);
312 if (GetObject (aMemoryBitmap, sizeof (BITMAP), &aBitmapInfo))
314 devWidth = aBitmapInfo.bmWidth;
315 devHeight = aBitmapInfo.bmHeight;
319 Standard_Integer tempWidth = (Standard_Integer) devWidth;
320 Standard_Integer tempHeight = (Standard_Integer) devHeight;
323 int viewWidth = myWidth;
324 int viewHeight = myHeight;
325 if (viewWidth == 0 || viewHeight == 0)
327 //MessageBox (NULL, "Print failed: can't setup the view for printing.",
328 // "The operation couldn't be completed.", MB_OK);
329 return Standard_False;
332 // calculate correct width/height ratio
333 Standard_Real viewRatio = (Standard_Real)viewWidth/viewHeight;
334 fitDimensionsRatio(tempWidth, tempHeight, viewRatio);
336 // width and height for printing area
337 int width = (int) (tempWidth * theScaleFactor);
338 int height = (int) (tempHeight * theScaleFactor);
340 // device independent bitmap for the whole view
341 #ifdef HAVE_FREEIMAGE
342 FipHandle aViewImage = NULL;
343 BYTE* aViewBuffer = NULL;
345 HDC hMemDC = CreateCompatibleDC (hPrnDC);
346 HBITMAP hViewBitmap = NULL;
347 HGDIOBJ hViewBitmapOld = NULL;
348 VOID* aViewBuffer = NULL;
351 // Frame buffer initialization
352 OpenGl_FrameBuffer* aFrameBuffer = NULL;
353 OpenGl_FrameBuffer* aPrevBuffer = (OpenGl_FrameBuffer*) ACView.ptrFBO;
354 Standard_Integer aFrameWidth (0), aFrameHeight (0),
355 aPrevBufferX (0), aPrevBufferY (0);
357 bool IsTiling = (printAlgorithm == 1);
359 // try to use existing frame buffer
362 GLsizei aPrevWidth = aPrevBuffer->GetSizeX();
363 GLsizei aPrevHeight = aPrevBuffer->GetSizeY();
364 bool isUsable = false;
366 // check if its possible to use previous frame buffer
367 if (!IsTiling && aPrevWidth >= width && aPrevHeight >= height)
369 aFrameWidth = (Standard_Integer) width;
370 aFrameHeight = (Standard_Integer) height;
375 // use previous frame buffer with its dimensions
376 aFrameWidth = aPrevWidth;
377 aFrameHeight = aPrevHeight;
381 // if it is enough memory for image paste dc operation
384 #ifdef HAVE_FREEIMAGE
385 // try to allocate fipImage and necessary resources
386 fipImage* anImagePtr = new fipImage (FIT_BITMAP, aFrameWidth,
389 // if allocated succesfully
390 if (anImagePtr->isValid())
392 aViewImage = anImagePtr;
393 aViewBuffer = aViewImage->accessPixels ();
405 // try to allocate compatible bitmap and necessary resources
406 initBitmapBuffer (hMemDC, hViewBitmap,
407 aFrameWidth, aFrameHeight, aViewBuffer);
412 DeleteObject (hViewBitmap);
416 hViewBitmapOld = SelectObject (hMemDC, hViewBitmap);
420 // use previous frame buffer
423 aPrevBufferX = aPrevWidth;
424 aPrevBufferY = aPrevHeight;
425 aFrameBuffer = aPrevBuffer;
426 aFrameBuffer->ChangeViewport (aFrameWidth, aFrameHeight);
430 // if previous buffer cannot be used, try to init a new one
433 aFrameBuffer = new OpenGl_FrameBuffer();
435 // try to create the framebuffer with the best possible size
436 Standard_Integer aMaxWidth(0), aMaxHeight(0);
437 getMaxFrameSize (aMaxWidth, aMaxHeight);
438 while (aMaxWidth > 1 && aMaxHeight > 1)
440 aFrameWidth = aMaxWidth;
441 aFrameHeight = aMaxHeight;
443 // calculate dimensions for different printing algorithms
445 initBufferStretch (aFrameWidth, aFrameHeight, width, height);
447 initBufferTiling (aFrameWidth, aFrameHeight, width, height);
449 // try to initialize framebuffer
450 if (aFrameBuffer->Init (GetGlContext(), aFrameWidth, aFrameHeight))
452 #ifdef HAVE_FREEIMAGE
453 // try to allocate fipImage and necessary resources
454 fipImage* anImagePtr = new fipImage (FIT_BITMAP, aFrameWidth,
457 // if allocated succesfully
458 if (anImagePtr->isValid())
460 aViewImage = anImagePtr;
461 aViewBuffer = aViewImage->accessPixels ();
468 aFrameBuffer->Release (GetGlContext().operator->());
475 // try to allocate compatible bitmap and necessary resources
476 initBitmapBuffer (hMemDC, hViewBitmap,
477 aFrameWidth, aFrameHeight, aViewBuffer);
481 DeleteObject (hViewBitmap);
482 aFrameBuffer->Release (GetGlContext().operator->());
487 hViewBitmapOld = SelectObject (hMemDC, hViewBitmap);
493 // not initialized, decrease dimensions
494 aMaxWidth = aMaxWidth >> 1;
495 aMaxHeight = aMaxHeight >> 1;
498 // check if there are proper dimensions
499 if (aMaxWidth <= 1 || aMaxHeight <= 1)
501 MessageBox (NULL, "Print failed: can't allocate buffer for printing.",
502 "The operation couldn't be completed.", MB_OK);
506 #ifndef HAVE_FREEIMAGE
511 return Standard_False;
515 // setup printing context and viewport
516 myPrintContext = thePrintContext;
517 GLint aViewPortBack[4];
518 GLint anAlignBack = 1;
519 myPrintContext->SetLayerViewport ((GLsizei )aFrameWidth,
520 (GLsizei )aFrameHeight);
521 glGetIntegerv (GL_VIEWPORT, aViewPortBack);
522 glGetIntegerv (GL_PACK_ALIGNMENT, &anAlignBack);
523 glPixelStorei (GL_PACK_ALIGNMENT, 4);
525 // start document if the printer context is not actually a memory dc
526 // (memory dc could be used for testing purposes)
528 if (GetObjectType (hPrnDC) == OBJ_DC)
530 // Initalize printing procedure
531 di.cbSize = sizeof(DOCINFO);
532 di.lpszDocName = "Open Cascade Document - print v3d view";
533 di.lpszOutput = filename;
535 // if can't print the document
536 if (StartDoc (hPrnDC, &di) <= 0 || StartPage (hPrnDC) <= 0)
538 MessageBox (NULL, "Print failed: printer can't start operation.",
539 "The operation couldn't be completed.", MB_OK);
540 #ifndef HAVE_FREEIMAGE
543 SelectObject (hMemDC, hViewBitmapOld);
544 DeleteObject (hViewBitmap);
549 myPrintContext.Nullify();
550 return Standard_False;
554 // calculate offset for centered printing
555 int aDevOffx = (int)(devWidth - width) /2;
556 int aDevOffy = (int)(devHeight - height)/2;
558 // operation complete flag
561 // Set up status for printing
563 NamedStatus |= OPENGL_NS_WHITEBACK;
565 // switch to mono camera for image dump
566 const Graphic3d_Camera::Projection aProjectType = myView->Camera()->ProjectionType() != Graphic3d_Camera::Projection_Stereo
567 ? myView->Camera()->ProjectionType()
568 : Graphic3d_Camera::Projection_Perspective;
571 myPrintContext->SetScale ((GLfloat )aFrameWidth /viewWidth,
572 (GLfloat )aFrameHeight/viewHeight);
573 redraw1 (ACView, ACUnderLayer, ACOverLayer, aFrameBuffer, aProjectType);
574 if (!myTransientDrawToFront)
576 // render to FBO only if allowed to render to back buffer
577 myBackBufferRestored = Standard_True;
578 myIsImmediateDrawn = Standard_False;
579 redrawImmediate (ACView, ACUnderLayer, ACOverLayer, NULL, aProjectType, aFrameBuffer);
580 myBackBufferRestored = Standard_False;
581 myIsImmediateDrawn = Standard_False;
583 glReadPixels (0, 0, aFrameWidth, aFrameHeight,
584 GL_BGR_EXT, GL_UNSIGNED_BYTE, (GLvoid* )aViewBuffer);
586 // copy result to the printer device and check for errors
587 #ifdef HAVE_FREEIMAGE
588 if (!aViewImage->rescale(width, height, FILTER_BICUBIC) ||
589 !imagePasteDC (hPrnDC, aViewImage, aDevOffx, aDevOffy, width, height))
590 isDone = imageStretchDC (hPrnDC, aViewImage, aDevOffx, aDevOffy,
593 if (width > aFrameWidth && height > aFrameHeight)
595 SetStretchBltMode (hPrnDC, STRETCH_HALFTONE);
596 isDone = (StretchBlt (hPrnDC, aDevOffx, aDevOffy, width, height,
597 hMemDC, 0, 0, aFrameWidth, aFrameHeight, SRCCOPY) != 0); // to avoid warning C4800
601 isDone = (BitBlt (hPrnDC, aDevOffx, aDevOffy, width, height,
602 hMemDC, 0, 0, SRCCOPY) != 0); // to avoid warning C4800
608 // calculate total count of frames and cropping size
609 Standard_Integer aPxCropx = 0;
610 Standard_Integer aPxCropy = 0;
611 Standard_Integer aTotalx =
612 (Standard_Integer)floor ((float)width /aFrameWidth);
613 Standard_Integer aTotaly =
614 (Standard_Integer)floor ((float)height/aFrameHeight);
615 if (width %aFrameWidth != 0)
617 aPxCropx = (aFrameWidth - width%aFrameWidth)/2;
620 if (height%aFrameHeight != 0)
622 aPxCropy = (aFrameHeight - height%aFrameHeight)/2;
626 int anOddPixelx = (width %aFrameWidth) %2;
627 int anOddPixely = (height%aFrameHeight)%2;
629 // calculate scale factor for full frames
630 Standard_Real aScalex = (Standard_Real)width /aFrameWidth;
631 Standard_Real aScaley = (Standard_Real)height/aFrameHeight;
633 // calculate and set the text scaling factor for printing context
634 GLfloat aScaleRatex = (GLfloat)aFrameWidth /viewWidth;
635 GLfloat aScaleRatey = (GLfloat)aFrameHeight/viewHeight;
636 myPrintContext->SetScale (aScaleRatex * (GLfloat )aScalex,
637 aScaleRatey * (GLfloat )aScaley);
639 // initialize projection matrix for printer context
640 TColStd_Array2OfReal aProj (0, 3, 0, 3);
641 Standard_Real aDef = 0;
646 // projection matrix offsets for printer context
647 // offsets are even numbers
648 Standard_Real aOffsetx(0), aOffsety(0);
649 aOffsetx = -(aTotalx-1);
650 aOffsety = -(aTotaly-1);
652 // rect of frame image that will be copied
653 // and coordinates in view image where to put it
654 Standard_Integer aLeft = 0, aRight = 0, aBottom = 0, aTop = 0;
655 Standard_Integer aSubLeft = (Standard_Integer)aDevOffx;
656 Standard_Integer aSubTop = (Standard_Integer)aDevOffy;
658 // draw sequence of full frames
659 for (int i = 0; i < aTotalx; i++)
661 // offsets are even numbers
662 aOffsety = -(aTotaly-1);
663 aSubTop = (Standard_Integer)aDevOffy;
665 // calculate cropped frame rect
666 aLeft = (i == 0) ? aPxCropx : 0;
667 aRight = (i == aTotalx-1) ? aFrameWidth-(aPxCropx+anOddPixelx) :
670 for (int j = 0; j < aTotaly; j++)
672 // no offset for single frames
673 aProj(3,0) = (aTotalx == 1) ? 0 : -aOffsetx;
674 aProj(3,1) = (aTotaly == 1) ? 0 : aOffsety;
676 // set projection matrix
677 aProj(0,0) = aScalex;
678 aProj(1,1) = aScaley;
679 myPrintContext->SetProjTransformation (aProj);
681 // calculate cropped frame rect
682 aTop = (j == 0) ? aPxCropy : 0;
683 aBottom = (j == aTotaly-1) ? aFrameHeight-(aPxCropy+anOddPixely) :
686 // draw to the offscreen buffer and capture the result
687 redraw1 (ACView, ACUnderLayer, ACOverLayer, aFrameBuffer, aProjectType);
688 if (!myTransientDrawToFront)
690 // render to FBO only if forces to render to back buffer
691 myBackBufferRestored = Standard_True;
692 myIsImmediateDrawn = Standard_False;
693 redrawImmediate (ACView, ACUnderLayer, ACOverLayer, NULL, aProjectType, aFrameBuffer);
694 myBackBufferRestored = Standard_False;
695 myIsImmediateDrawn = Standard_False;
697 glReadPixels (0, 0, aFrameWidth, aFrameHeight,
698 GL_BGR_EXT, GL_UNSIGNED_BYTE, (GLvoid* )aViewBuffer);
699 #ifdef HAVE_FREEIMAGE
700 // cut out pixels that are out of printing area
701 isDone = imagePasteDC (hPrnDC, aViewImage, aSubLeft, aSubTop,
702 aRight-aLeft, aBottom-aTop, aLeft, aTop);
704 isDone = (BitBlt (hPrnDC, aSubLeft, aSubTop, aRight-aLeft, aBottom-aTop,
705 hMemDC, aLeft, aTop, SRCCOPY) != 0); // to avoid warning C4800
708 // stop operation if errors
712 // calculate new view offset for y-coordinate
714 aSubTop += aBottom-aTop;
717 // stop operation if errors
721 // calculate new view offset for x-coordinate
723 aSubLeft += aRight-aLeft;
727 // complete printing or indicate an error
728 if (GetObjectType (hPrnDC) == OBJ_DC && isDone == true)
733 else if (isDone == false)
735 MessageBox (NULL, "Print failed: insufficient memory or spool error.\nPlease use smaller printer resolution.",
736 "The opeartion couldn't be completed.", MB_OK);
737 if (GetObjectType (hPrnDC) == OBJ_DC)
741 // return OpenGl to the previous state
742 glPixelStorei (GL_PACK_ALIGNMENT, anAlignBack);
743 aFrameBuffer->UnbindBuffer (GetGlContext());
744 glViewport (aViewPortBack[0], aViewPortBack[1],
745 aViewPortBack[2], aViewPortBack[3]);
748 aPrevBuffer->ChangeViewport (aPrevBufferX, aPrevBufferY);
752 aFrameBuffer->Release (GetGlContext().operator->());
757 #ifndef HAVE_FREEIMAGE
760 SelectObject (hMemDC, hViewBitmapOld);
761 DeleteObject (hViewBitmap);
766 // Reset status after printing
767 NamedStatus &= ~OPENGL_NS_WHITEBACK;
769 myPrintContext.Nullify();
770 return (Standard_Boolean) isDone;
773 myPrintContext.Nullify();
774 return Standard_False;