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