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