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