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