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