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