Commit | Line | Data |
---|---|---|
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 | // --------------------------------------------------------------- | |
53 | static 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 | // --------------------------------------------------------------- | |
64 | static 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 | // --------------------------------------------------------------- | |
86 | static 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 | // --------------------------------------------------------------- | |
103 | static 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 | // --------------------------------------------------------------- | |
121 | static 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 | // --------------------------------------------------------------- | |
155 | static 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 |
174 | static 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 | // --------------------------------------------------------------- | |
204 | static 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 | // --------------------------------------------------------------- | |
267 | static 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 |
299 | Standard_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 | 798 | void 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 | 863 | void 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 | 899 | void 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 | /*----------------------------------------------------------------------*/ |