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