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