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