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