0026936: Drawbacks of inlining in new type system in OCCT 7.0 -- automatic
[occt.git] / src / OpenGl / OpenGl_View_Print.cxx
CommitLineData
b311480e 1// Created on: 2011-09-20
2// Created by: Sergey ZERCHANINOV
973c2be1 3// Copyright (c) 2011-2014 OPEN CASCADE SAS
b311480e 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
b311480e 6//
d5f74e42 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
973c2be1 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.
b311480e 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
7fd59977 15
5f8b738e 16#include <OpenGl_GlCore11.hxx>
7fd59977 17
7edf74fd 18#include <OpenGl_FrameBuffer.hxx>
7edf74fd 19#include <TColStd_Array2OfReal.hxx>
2166f0fa 20#include <OpenGl_telem_util.hxx>
c04c30b3 21#include <Graphic3d_GraphicDriver.hxx>
22
23#include <OpenGl_PrinterContext.hxx>
24#include <OpenGl_Workspace.hxx>
25#include <OpenGl_View.hxx>
7fd59977 26
c357e426 27#include <Standard_NotImplemented.hxx>
28
4fe56619 29#if (defined(_WIN32) || defined(__WIN32__)) && defined(HAVE_FREEIMAGE)
7edf74fd
A
30 #include <NCollection_Handle.hxx>
31 #include <FreeImagePlus.h>
32 #ifdef _MSC_VER
4fe56619 33 #pragma comment( lib, "FreeImage.lib" )
34 #pragma comment( lib, "FreeImagePlus.lib" )
7edf74fd
A
35 #endif
36 typedef NCollection_Handle<fipImage> FipHandle;
37#endif
7fd59977 38
8cb69787 39#ifdef _WIN32
7edf74fd 40
8cb69787 41#ifndef HAVE_FREEIMAGE
7fd59977 42
c357e426 43 // =======================================================================
44// function : initBitmapBuffer
45// purpose : init device independent bitmap to hold printing data
46// =======================================================================
7edf74fd
A
47static void initBitmapBuffer (const HDC theMemoryDC,
48 HBITMAP &theMemoryBmp,
49 const Standard_Integer theBmpWidth,
50 const Standard_Integer theBmpHeight,
51 VOID* &theBufferPtr)
52{
53 // define compatible bitmap
54 BITMAPINFO aBitmapData;
55 memset (&aBitmapData, 0, sizeof (BITMAPINFOHEADER));
56 aBitmapData.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
57 aBitmapData.bmiHeader.biWidth = theBmpWidth;
58 aBitmapData.bmiHeader.biHeight = theBmpHeight;
59 aBitmapData.bmiHeader.biPlanes = 1;
60 aBitmapData.bmiHeader.biBitCount = 24;
61 aBitmapData.bmiHeader.biXPelsPerMeter = 0;
62 aBitmapData.bmiHeader.biYPelsPerMeter = 0;
63 aBitmapData.bmiHeader.biClrUsed = 0;
64 aBitmapData.bmiHeader.biClrImportant = 0;
65 aBitmapData.bmiHeader.biCompression = BI_RGB;
66 aBitmapData.bmiHeader.biSizeImage = 0;
67
68 // Create Device Independent Bitmap
69 theMemoryBmp = CreateDIBSection (theMemoryDC, &aBitmapData, DIB_RGB_COLORS,
70 &theBufferPtr, NULL, 0);
71}
8cb69787 72
73#else /* HAVE_FREEIMAGE */
74
c357e426 75// =======================================================================
76// function : imagePasteDC
77// purpose : copy the data from image buffer to the device context
78// =======================================================================
7edf74fd 79static bool imagePasteDC(HDC theDstDC, FipHandle theImage, int theOffsetX,
4fe56619 80 int theOffsetY, int theWidth, int theHeight,
7edf74fd
A
81 int theLeft = 0, int theTop = 0)
82{
83 // get image parameters
84 BITMAPINFO* aBitmapData = theImage->getInfo ();
85 SetStretchBltMode (theDstDC, STRETCH_HALFTONE);
4fe56619 86
7edf74fd
A
87 // organize blocks data passing if memory isn't enough to pass all the data
88 // at once
89 int aLinesComplete = 0, aMaxBlockWidth = theHeight, aBlockWidth = 0,
90 aPassed = 0, aInverseLine = 0, aScan = 0;
91 BYTE *aDataPtr = 0;
92 while (aMaxBlockWidth >= 1 && aLinesComplete < theHeight)
93 {
94 // how much lines still to pass
95 aBlockWidth = theHeight - aLinesComplete;
96
97 // normalize count of lines to pass to maximum lines count at one pass.
98 if (aBlockWidth > aMaxBlockWidth)
99 aBlockWidth = aMaxBlockWidth;
100
101 // access image data at the start scan line, we need to calculate scan from
102 // the bottom of image (image is bottom-left, the src coord is top-left)
103 aInverseLine = theTop + aBlockWidth + aLinesComplete;
104 aScan = theImage->getHeight() - aInverseLine;
105 aDataPtr = theImage->getScanLine (aScan);
106 if (!aDataPtr)
107 return false;
108
109 // try to pass block to the device
110 if (aBlockWidth > 0)
111 {
112 // instead of banded output we provide blocked as it isn't always passed
113 // to printer as it is expected
114 aPassed = SetDIBitsToDevice (theDstDC, theOffsetX,
115 theOffsetY + aLinesComplete,
116 theWidth, aBlockWidth, theLeft, 0,
117 0, aBlockWidth,
118 aDataPtr, aBitmapData, DIB_RGB_COLORS);
119
120 // if result is bad, try to decrease band width
121 if (aPassed != aBlockWidth)
122 {
123 aMaxBlockWidth = aMaxBlockWidth >> 1;
124 aLinesComplete = 0;
125 }
126 else
127 aLinesComplete += aBlockWidth;
128 }
7fd59977 129 }
7edf74fd
A
130
131 // check for total failure
132 if (aMaxBlockWidth < 1)
133 return false;
134
135 return true;
7fd59977 136}
7fd59977 137
c357e426 138// =======================================================================
139// function : imageStretchDC
140// purpose : copy pixels from image to dc by stretching them
141// =======================================================================
7edf74fd
A
142static bool imageStretchDC(HDC theDstDC, FipHandle theImage, int theOffsetX,
143 int theOffsetY, int theWidth, int theHeight)
144{
145 // access to raw image data
146 BYTE *aDataPtr = theImage->accessPixels ();
147 if (!aDataPtr)
148 return false;
149
150 // get image parameters
151 unsigned int widthPx = theImage->getWidth ();
152 unsigned int heightPx = theImage->getHeight ();
153 BITMAPINFO* aBitmapData = theImage->getInfo ();
154 SetStretchBltMode (theDstDC, STRETCH_HALFTONE);
4fe56619 155
7edf74fd
A
156 // pass lines and check if operation is succesfull
157 int aPassed = 0;
158 aPassed = StretchDIBits (theDstDC, theOffsetX, theOffsetY, theWidth,
159 theHeight, 0, 0, widthPx, heightPx, aDataPtr,
160 aBitmapData, DIB_RGB_COLORS, SRCCOPY);
161
105aae76 162 if ((unsigned)aPassed != heightPx)
7edf74fd 163 return false;
4fe56619 164
7edf74fd
A
165 return true;
166}
8cb69787 167
168#endif /* HAVE_FREEIMAGE */
169
c357e426 170// =======================================================================
171// function : getNearestPowOfTwo
172// purpose : get the nearest power of two for theNumber
173// =======================================================================
8cb69787 174static GLsizei getNearestPowOfTwo (const GLsizei theNumber)
175{
176 GLsizei aLast = 1;
177 for (GLsizei p2 = 1; p2 <= theNumber; aLast = p2, p2 <<= 1);
178 return aLast;
179}
47afc367 180
c357e426 181// =======================================================================
182// function : getMaxFrameSize
183// purpose : get the maximum possible frame size
184// =======================================================================
47afc367 185static void getMaxFrameSize(Standard_Integer& theWidth,
186 Standard_Integer& theHeight)
187{
188 GLsizei aMaxX, aMaxY;
189 GLint aVpDim[2];
190 GLint aTexDim = 2048;
191 glGetIntegerv (GL_MAX_VIEWPORT_DIMS, (GLint*) &aVpDim);
192 glGetIntegerv (GL_MAX_TEXTURE_SIZE, &aTexDim);
193 (aVpDim[0] >= aTexDim) ? aMaxX = (GLsizei) aTexDim :
194 aMaxX = getNearestPowOfTwo((GLsizei)aVpDim[0]);
195 (aVpDim[1] >= aTexDim) ? aMaxY = (GLsizei) aTexDim :
196 aMaxY = getNearestPowOfTwo((GLsizei)aVpDim[1]);
197
198 theWidth = (Standard_Integer)aMaxX;
199 theHeight = (Standard_Integer)aMaxY;
200}
47afc367 201
c357e426 202// =======================================================================
203// function : fitDimensionsRatio
204// purpose : calculate correct width/height ratio for theWidth and
205// theHeight parameters
206// =======================================================================
8cb69787 207static void fitDimensionsRatio (Standard_Integer& theWidth,
208 Standard_Integer& theHeight,
209 const Standard_Real theViewRatio)
210{
211 // set dimensions in accordance with the viewratio
212 if (theHeight < theWidth/theViewRatio)
213 theWidth = (Standard_Integer)(theHeight*theViewRatio);
214
215 if (theWidth < theHeight*theViewRatio)
216 theHeight = (Standard_Integer)(theWidth/theViewRatio);
217}
218
c357e426 219// =======================================================================
220// function : initBufferStretch
221// purpose : calculate initialization sizes for frame buffer
222// when the stretch algorithm is selected
223// =======================================================================
47afc367 224static void initBufferStretch (Standard_Integer& theFrameWidth,
225 Standard_Integer& theFrameHeight,
226 const int theViewWidth,
227 const int theViewHeight)
228{
229
230 // Calculate correct width/height for framebuffer
231 Standard_Real aViewRatio = (Standard_Real)theViewWidth/theViewHeight;
232 fitDimensionsRatio (theFrameWidth, theFrameHeight, aViewRatio);
233
234 // downscale the framebuffer if it is too large
235 Standard_Real aWidthRate = (Standard_Real)theFrameWidth /theViewWidth;
236 Standard_Real aHeightRate = (Standard_Real)theFrameHeight/theViewHeight;
237
238 if ((aWidthRate > 1 && aHeightRate > 1 && aWidthRate >= aHeightRate) ||
239 (aWidthRate > 1 && aHeightRate <= 1))
240 {
241 theFrameWidth = (Standard_Integer)(theFrameWidth /aWidthRate);
242 theFrameHeight = (Standard_Integer)(theFrameHeight/aWidthRate);
243 }
244 else if ((aWidthRate > 1 && aHeightRate > 1 && aWidthRate < aHeightRate) ||
245 (aWidthRate <= 1 && aHeightRate > 1))
246 {
247 theFrameWidth = (Standard_Integer)(theFrameWidth /aHeightRate);
248 theFrameHeight = (Standard_Integer)(theFrameHeight/aHeightRate);
249 }
250}
c357e426 251
252// =======================================================================
253// function : initBufferTiling
254// purpose : calculate initialization sizes for frame buffer
255// when the tile algorithm is selected
256// =======================================================================
47afc367 257static void initBufferTiling (Standard_Integer& theFrameWidth,
258 Standard_Integer &theFrameHeight,
259 const int theViewWidth,
260 const int theViewHeight)
261{
262 // fit framebuffer into the printing area
263 if (theFrameWidth > theViewWidth)
264 theFrameWidth = theViewWidth;
265
266 if (theFrameHeight > theViewHeight)
267 theFrameHeight = theViewHeight;
268}
8cb69787 269
270#endif /* _WIN32 */
7fd59977 271
c357e426 272// =======================================================================
273// function : Print
274// purpose :
275// =======================================================================
276Standard_Boolean OpenGl_View::Print (const Aspect_Handle thePrinterDC,
277 const Standard_Boolean theToShowBackground,
278 const Standard_CString theFileName,
279 const Aspect_PrintAlgo thePrintAlgorithm,
280 const Standard_Real theScaleFactor)
2166f0fa 281{
47afc367 282#ifdef _WIN32
c357e426 283 if (!myWorkspace->Activate())
7edf74fd 284 {
2166f0fa
SK
285 //MessageBox (NULL, "Print failed: can't setup the view for printing.",
286 // "The operation couldn't be completed.", MB_OK);
7edf74fd
A
287 return Standard_False;
288 }
7fd59977 289
c357e426 290 Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
291
7edf74fd 292 // printer page dimensions
c357e426 293 HDC hPrnDC = (HDC) thePrinterDC;
7edf74fd
A
294 int devWidth = GetDeviceCaps (hPrnDC, HORZRES);
295 int devHeight = GetDeviceCaps (hPrnDC, VERTRES);
7fd59977 296
7edf74fd
A
297 // if context is actually a memory dc, try to retrieve bitmap dimensions
298 // (memory dc could be used for testing purposes)
299 if (GetObjectType (hPrnDC) == OBJ_MEMDC)
300 {
301 // memory dc dimensions
302 BITMAP aBitmapInfo;
303 HBITMAP aMemoryBitmap = (HBITMAP) GetCurrentObject (hPrnDC, OBJ_BITMAP);
304 if (aMemoryBitmap)
305 if (GetObject (aMemoryBitmap, sizeof (BITMAP), &aBitmapInfo))
306 {
307 devWidth = aBitmapInfo.bmWidth;
308 devHeight = aBitmapInfo.bmHeight;
309 }
310 }
7fd59977 311
7edf74fd
A
312 Standard_Integer tempWidth = (Standard_Integer) devWidth;
313 Standard_Integer tempHeight = (Standard_Integer) devHeight;
7fd59977 314
7edf74fd 315 // view dimensions
c357e426 316 int viewWidth = myWindow->Width();
317 int viewHeight = myWindow->Height();
7edf74fd 318 if (viewWidth == 0 || viewHeight == 0)
7fd59977 319 {
2166f0fa
SK
320 //MessageBox (NULL, "Print failed: can't setup the view for printing.",
321 // "The operation couldn't be completed.", MB_OK);
7edf74fd
A
322 return Standard_False;
323 }
324
325 // calculate correct width/height ratio
326 Standard_Real viewRatio = (Standard_Real)viewWidth/viewHeight;
327 fitDimensionsRatio(tempWidth, tempHeight, viewRatio);
328
329 // width and height for printing area
330 int width = (int) (tempWidth * theScaleFactor);
331 int height = (int) (tempHeight * theScaleFactor);
332
333 // device independent bitmap for the whole view
334#ifdef HAVE_FREEIMAGE
335 FipHandle aViewImage = NULL;
336 BYTE* aViewBuffer = NULL;
7fd59977 337#else
7edf74fd
A
338 HDC hMemDC = CreateCompatibleDC (hPrnDC);
339 HBITMAP hViewBitmap = NULL;
340 HGDIOBJ hViewBitmapOld = NULL;
341 VOID* aViewBuffer = NULL;
7fd59977 342#endif
343
7edf74fd
A
344 // Frame buffer initialization
345 OpenGl_FrameBuffer* aFrameBuffer = NULL;
b128c892 346 OpenGl_FrameBuffer* aPrevBuffer = myFBO.operator->();
7edf74fd
A
347 Standard_Integer aFrameWidth (0), aFrameHeight (0),
348 aPrevBufferX (0), aPrevBufferY (0);
7fd59977 349
c357e426 350 bool IsTiling = (thePrintAlgorithm == Aspect_PA_TILE);
2166f0fa 351
7edf74fd
A
352 // try to use existing frame buffer
353 if (aPrevBuffer)
354 {
355 GLsizei aPrevWidth = aPrevBuffer->GetSizeX();
356 GLsizei aPrevHeight = aPrevBuffer->GetSizeY();
357 bool isUsable = false;
358
359 // check if its possible to use previous frame buffer
360 if (!IsTiling && aPrevWidth >= width && aPrevHeight >= height)
7fd59977 361 {
7edf74fd
A
362 aFrameWidth = (Standard_Integer) width;
363 aFrameHeight = (Standard_Integer) height;
364 isUsable = true;
7fd59977 365 }
7edf74fd 366 else if (IsTiling)
7fd59977 367 {
b5ac8292 368 // use previous frame buffer with its dimensions
369 aFrameWidth = aPrevWidth;
370 aFrameHeight = aPrevHeight;
371 isUsable = true;
7fd59977 372 }
373
7edf74fd
A
374 // if it is enough memory for image paste dc operation
375 if (isUsable)
7fd59977 376 {
7edf74fd
A
377#ifdef HAVE_FREEIMAGE
378 // try to allocate fipImage and necessary resources
379 fipImage* anImagePtr = new fipImage (FIT_BITMAP, aFrameWidth,
380 aFrameHeight, 24);
381
c357e426 382 // if allocated successfully
7edf74fd
A
383 if (anImagePtr->isValid())
384 {
385 aViewImage = anImagePtr;
386 aViewBuffer = aViewImage->accessPixels ();
387 }
388 else
389 delete anImagePtr;
390
391 if (!aViewBuffer)
392 {
393 isUsable = false;
394 aViewBuffer = NULL;
395 aViewImage = NULL;
396 }
7fd59977 397#else
7edf74fd 398 // try to allocate compatible bitmap and necessary resources
4fe56619 399 initBitmapBuffer (hMemDC, hViewBitmap,
7edf74fd
A
400 aFrameWidth, aFrameHeight, aViewBuffer);
401 if (!aViewBuffer)
402 {
403 isUsable = false;
404 if (hViewBitmap)
405 DeleteObject (hViewBitmap);
406 hViewBitmap = NULL;
407 }
408 else
409 hViewBitmapOld = SelectObject (hMemDC, hViewBitmap);
410#endif
7fd59977 411 }
412
7edf74fd
A
413 // use previous frame buffer
414 if (isUsable)
7fd59977 415 {
7edf74fd
A
416 aPrevBufferX = aPrevWidth;
417 aPrevBufferY = aPrevHeight;
418 aFrameBuffer = aPrevBuffer;
419 aFrameBuffer->ChangeViewport (aFrameWidth, aFrameHeight);
7fd59977 420 }
7edf74fd 421 }
7fd59977 422
7edf74fd
A
423 // if previous buffer cannot be used, try to init a new one
424 if (!aFrameBuffer)
425 {
426 aFrameBuffer = new OpenGl_FrameBuffer();
7fd59977 427
7edf74fd
A
428 // try to create the framebuffer with the best possible size
429 Standard_Integer aMaxWidth(0), aMaxHeight(0);
430 getMaxFrameSize (aMaxWidth, aMaxHeight);
431 while (aMaxWidth > 1 && aMaxHeight > 1)
7fd59977 432 {
7edf74fd
A
433 aFrameWidth = aMaxWidth;
434 aFrameHeight = aMaxHeight;
435
436 // calculate dimensions for different printing algorithms
437 if (!IsTiling)
438 initBufferStretch (aFrameWidth, aFrameHeight, width, height);
439 else
440 initBufferTiling (aFrameWidth, aFrameHeight, width, height);
441
442 // try to initialize framebuffer
3c4b62a4 443 if (aFrameBuffer->Init (aCtx, aFrameWidth, aFrameHeight, GL_RGBA8, GL_DEPTH24_STENCIL8))
7edf74fd
A
444 {
445#ifdef HAVE_FREEIMAGE
446 // try to allocate fipImage and necessary resources
447 fipImage* anImagePtr = new fipImage (FIT_BITMAP, aFrameWidth,
448 aFrameHeight, 24);
449
c357e426 450 // if allocated successfully
7edf74fd
A
451 if (anImagePtr->isValid())
452 {
453 aViewImage = anImagePtr;
454 aViewBuffer = aViewImage->accessPixels ();
455 }
456 else
457 delete anImagePtr;
458
459 if (!aViewBuffer)
460 {
c357e426 461 aFrameBuffer->Release (aCtx.operator->());
7edf74fd
A
462 aViewBuffer = NULL;
463 aViewImage = NULL;
464 }
465 else
466 break;
467#else
468 // try to allocate compatible bitmap and necessary resources
4fe56619 469 initBitmapBuffer (hMemDC, hViewBitmap,
7edf74fd
A
470 aFrameWidth, aFrameHeight, aViewBuffer);
471 if (!aViewBuffer)
472 {
473 if (hViewBitmap)
474 DeleteObject (hViewBitmap);
c357e426 475 aFrameBuffer->Release (aCtx.operator->());
7edf74fd
A
476 hViewBitmap = NULL;
477 }
478 else
479 {
480 hViewBitmapOld = SelectObject (hMemDC, hViewBitmap);
481 break;
482 }
7fd59977 483#endif
7edf74fd 484 }
7fd59977 485
7edf74fd
A
486 // not initialized, decrease dimensions
487 aMaxWidth = aMaxWidth >> 1;
488 aMaxHeight = aMaxHeight >> 1;
7fd59977 489 }
490
4fe56619 491 // check if there are proper dimensions
7edf74fd
A
492 if (aMaxWidth <= 1 || aMaxHeight <= 1)
493 {
494 MessageBox (NULL, "Print failed: can't allocate buffer for printing.",
c357e426 495 "The operation couldn't be completed.", MB_OK);
7edf74fd
A
496
497 if (aFrameBuffer)
498 delete aFrameBuffer;
499#ifndef HAVE_FREEIMAGE
500 if (hMemDC)
501 DeleteDC (hMemDC);
7fd59977 502#endif
503
7edf74fd
A
504 return Standard_False;
505 }
506 }
7fd59977 507
7edf74fd 508 // setup printing context and viewport
c357e426 509 myWorkspace->PrinterContext() = new OpenGl_PrinterContext();
510 myWorkspace->PrinterContext()->SetLayerViewport ((GLsizei )aFrameWidth, (GLsizei )aFrameHeight);
4fe56619 511 GLint aViewPortBack[4];
5e27df78 512 GLint anAlignBack = 1;
7edf74fd
A
513 glGetIntegerv (GL_VIEWPORT, aViewPortBack);
514 glGetIntegerv (GL_PACK_ALIGNMENT, &anAlignBack);
515 glPixelStorei (GL_PACK_ALIGNMENT, 4);
516
517 // start document if the printer context is not actually a memory dc
518 // (memory dc could be used for testing purposes)
2166f0fa 519 DOCINFO di;
7edf74fd
A
520 if (GetObjectType (hPrnDC) == OBJ_DC)
521 {
c357e426 522 // Initialize printing procedure
7fd59977 523 di.cbSize = sizeof(DOCINFO);
7edf74fd 524 di.lpszDocName = "Open Cascade Document - print v3d view";
c357e426 525 di.lpszOutput = theFileName;
7fd59977 526
7edf74fd
A
527 // if can't print the document
528 if (StartDoc (hPrnDC, &di) <= 0 || StartPage (hPrnDC) <= 0)
529 {
530 MessageBox (NULL, "Print failed: printer can't start operation.",
531 "The operation couldn't be completed.", MB_OK);
532#ifndef HAVE_FREEIMAGE
533 if (hViewBitmap)
534 {
535 SelectObject (hMemDC, hViewBitmapOld);
536 DeleteObject (hViewBitmap);
537 }
538 DeleteDC (hMemDC);
539#endif
7fd59977 540
c357e426 541 myWorkspace->PrinterContext().Nullify();
7edf74fd
A
542 return Standard_False;
543 }
544 }
7fd59977 545
7edf74fd
A
546 // calculate offset for centered printing
547 int aDevOffx = (int)(devWidth - width) /2;
548 int aDevOffy = (int)(devHeight - height)/2;
7fd59977 549
7edf74fd
A
550 // operation complete flag
551 bool isDone = true;
2166f0fa
SK
552
553 // Set up status for printing
c357e426 554 if (!theToShowBackground)
555 {
556 myWorkspace->NamedStatus |= OPENGL_NS_WHITEBACK;
557 }
2166f0fa 558
38a0206f 559 // switch to mono camera for image dump
c357e426 560 const Graphic3d_Camera::Projection aProjectType = myCamera->ProjectionType() != Graphic3d_Camera::Projection_Stereo
561 ? myCamera->ProjectionType()
38a0206f 562 : Graphic3d_Camera::Projection_Perspective;
7edf74fd
A
563 if (!IsTiling)
564 {
c357e426 565 myWorkspace->PrinterContext()->SetScale ((GLfloat )aFrameWidth /viewWidth, (GLfloat )aFrameHeight/viewHeight);
566 redraw (aProjectType, aFrameBuffer);
1981cb22 567 if (!myTransientDrawToFront)
568 {
569 // render to FBO only if allowed to render to back buffer
ee51a9fe 570 myBackBufferRestored = Standard_True;
571 myIsImmediateDrawn = Standard_False;
c357e426 572 redrawImmediate (aProjectType, NULL, aFrameBuffer);
ee51a9fe 573 myBackBufferRestored = Standard_False;
574 myIsImmediateDrawn = Standard_False;
1981cb22 575 }
7edf74fd
A
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);
7fd59977 585#else
7edf74fd 586 if (width > aFrameWidth && height > aFrameHeight)
7fd59977 587 {
7edf74fd 588 SetStretchBltMode (hPrnDC, STRETCH_HALFTONE);
6de552e6 589 isDone = (StretchBlt (hPrnDC, aDevOffx, aDevOffy, width, height,
590 hMemDC, 0, 0, aFrameWidth, aFrameHeight, SRCCOPY) != 0); // to avoid warning C4800
7fd59977 591 }
7edf74fd 592 else
7fd59977 593 {
6de552e6 594 isDone = (BitBlt (hPrnDC, aDevOffx, aDevOffy, width, height,
595 hMemDC, 0, 0, SRCCOPY) != 0); // to avoid warning C4800
7fd59977 596 }
7edf74fd
A
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;
4fe56619 604 Standard_Integer aTotalx =
7edf74fd 605 (Standard_Integer)floor ((float)width /aFrameWidth);
4fe56619 606 Standard_Integer aTotaly =
7edf74fd
A
607 (Standard_Integer)floor ((float)height/aFrameHeight);
608 if (width %aFrameWidth != 0)
7fd59977 609 {
7edf74fd
A
610 aPxCropx = (aFrameWidth - width%aFrameWidth)/2;
611 aTotalx++;
7fd59977 612 }
7edf74fd 613 if (height%aFrameHeight != 0)
7fd59977 614 {
7edf74fd
A
615 aPxCropy = (aFrameHeight - height%aFrameHeight)/2;
616 aTotaly++;
7fd59977 617 }
7edf74fd
A
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;
c357e426 629 myWorkspace->PrinterContext()->SetScale (aScaleRatex * (GLfloat )aScalex, aScaleRatey * (GLfloat )aScaley);
7edf74fd
A
630
631 // initialize projection matrix for printer context
632 TColStd_Array2OfReal aProj (0, 3, 0, 3);
633 Standard_Real aDef = 0;
634 aProj.Init (aDef);
635 aProj(2,2) = 1.0;
636 aProj(3,3) = 1.0;
637
638 // projection matrix offsets for printer context
639 // offsets are even numbers
640 Standard_Real aOffsetx(0), aOffsety(0);
641 aOffsetx = -(aTotalx-1);
642 aOffsety = -(aTotaly-1);
643
644 // rect of frame image that will be copied
645 // and coordinates in view image where to put it
646 Standard_Integer aLeft = 0, aRight = 0, aBottom = 0, aTop = 0;
647 Standard_Integer aSubLeft = (Standard_Integer)aDevOffx;
648 Standard_Integer aSubTop = (Standard_Integer)aDevOffy;
649
650 // draw sequence of full frames
651 for (int i = 0; i < aTotalx; i++)
7fd59977 652 {
7edf74fd
A
653 // offsets are even numbers
654 aOffsety = -(aTotaly-1);
655 aSubTop = (Standard_Integer)aDevOffy;
656
657 // calculate cropped frame rect
658 aLeft = (i == 0) ? aPxCropx : 0;
659 aRight = (i == aTotalx-1) ? aFrameWidth-(aPxCropx+anOddPixelx) :
660 aFrameWidth;
661
662 for (int j = 0; j < aTotaly; j++)
663 {
664 // no offset for single frames
665 aProj(3,0) = (aTotalx == 1) ? 0 : -aOffsetx;
666 aProj(3,1) = (aTotaly == 1) ? 0 : aOffsety;
667
668 // set projection matrix
669 aProj(0,0) = aScalex;
670 aProj(1,1) = aScaley;
c357e426 671 myWorkspace->PrinterContext()->SetProjTransformation (aProj);
7edf74fd
A
672
673 // calculate cropped frame rect
674 aTop = (j == 0) ? aPxCropy : 0;
675 aBottom = (j == aTotaly-1) ? aFrameHeight-(aPxCropy+anOddPixely) :
676 aFrameHeight;
677
678 // draw to the offscreen buffer and capture the result
c357e426 679 redraw (aProjectType, aFrameBuffer);
1981cb22 680 if (!myTransientDrawToFront)
681 {
682 // render to FBO only if forces to render to back buffer
ee51a9fe 683 myBackBufferRestored = Standard_True;
684 myIsImmediateDrawn = Standard_False;
c357e426 685 redrawImmediate (aProjectType, NULL, aFrameBuffer);
ee51a9fe 686 myBackBufferRestored = Standard_False;
687 myIsImmediateDrawn = Standard_False;
1981cb22 688 }
7edf74fd
A
689 glReadPixels (0, 0, aFrameWidth, aFrameHeight,
690 GL_BGR_EXT, GL_UNSIGNED_BYTE, (GLvoid* )aViewBuffer);
691#ifdef HAVE_FREEIMAGE
692 // cut out pixels that are out of printing area
693 isDone = imagePasteDC (hPrnDC, aViewImage, aSubLeft, aSubTop,
694 aRight-aLeft, aBottom-aTop, aLeft, aTop);
695#else
6de552e6 696 isDone = (BitBlt (hPrnDC, aSubLeft, aSubTop, aRight-aLeft, aBottom-aTop,
697 hMemDC, aLeft, aTop, SRCCOPY) != 0); // to avoid warning C4800
7edf74fd
A
698#endif
699
700 // stop operation if errors
701 if (!isDone)
702 break;
703
704 // calculate new view offset for y-coordinate
705 aOffsety += 2.0;
706 aSubTop += aBottom-aTop;
707 }
708
709 // stop operation if errors
710 if (!isDone)
711 break;
4fe56619 712
7edf74fd
A
713 // calculate new view offset for x-coordinate
714 aOffsetx += 2.0;
715 aSubLeft += aRight-aLeft;
7fd59977 716 }
7edf74fd 717 }
7fd59977 718
7edf74fd
A
719 // complete printing or indicate an error
720 if (GetObjectType (hPrnDC) == OBJ_DC && isDone == true)
721 {
722 EndPage (hPrnDC);
723 EndDoc (hPrnDC);
7fd59977 724 }
7edf74fd
A
725 else if (isDone == false)
726 {
727 MessageBox (NULL, "Print failed: insufficient memory or spool error.\nPlease use smaller printer resolution.",
728 "The opeartion couldn't be completed.", MB_OK);
729 if (GetObjectType (hPrnDC) == OBJ_DC)
730 AbortDoc (hPrnDC);
731 }
4fe56619 732
7edf74fd 733 // return OpenGl to the previous state
7edf74fd 734 glPixelStorei (GL_PACK_ALIGNMENT, anAlignBack);
c357e426 735 aFrameBuffer->UnbindBuffer (aCtx);
4fe56619 736 glViewport (aViewPortBack[0], aViewPortBack[1],
7edf74fd
A
737 aViewPortBack[2], aViewPortBack[3]);
738 if (aPrevBuffer)
96352003 739 {
7edf74fd 740 aPrevBuffer->ChangeViewport (aPrevBufferX, aPrevBufferY);
96352003 741 }
7edf74fd 742 else
96352003 743 {
c357e426 744 aFrameBuffer->Release (aCtx.operator->());
7edf74fd 745 delete aFrameBuffer;
96352003 746 }
7edf74fd
A
747
748 // delete resources
749#ifndef HAVE_FREEIMAGE
750 if (hViewBitmap)
751 {
752 SelectObject (hMemDC, hViewBitmapOld);
753 DeleteObject (hViewBitmap);
754 }
755 DeleteDC (hMemDC);
756#endif
757
2166f0fa 758 // Reset status after printing
c357e426 759 myWorkspace->NamedStatus &= ~OPENGL_NS_WHITEBACK;
760 myWorkspace->PrinterContext().Nullify();
7edf74fd 761 return (Standard_Boolean) isDone;
7fd59977 762
47afc367 763#else // not _WIN32
c85385c0 764 (void )thePrinterDC;
765 (void )theToShowBackground;
766 (void )theFileName;
767 (void )thePrintAlgorithm;
768 (void )theScaleFactor;
c357e426 769 Standard_NotImplemented::Raise ("OpenGl_View::Print is implemented only on Windows");
770 myWorkspace->PrinterContext().Nullify();
7edf74fd 771 return Standard_False;
4fe56619 772#endif
7fd59977 773}