Commit | Line | Data |
---|---|---|
b311480e | 1 | // Created on: 2011-09-20 |
2 | // Created by: Sergey ZERCHANINOV | |
3 | // Copyright (c) 2011-2012 OPEN CASCADE SAS | |
4 | // | |
5 | // The content of this file is subject to the Open CASCADE Technology Public | |
6 | // License Version 6.5 (the "License"). You may not use the content of this file | |
7 | // except in compliance with the License. Please obtain a copy of the License | |
8 | // at http://www.opencascade.org and read it completely before using this file. | |
9 | // | |
10 | // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its | |
11 | // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. | |
12 | // | |
13 | // The Original Code and all software distributed under the License is | |
14 | // distributed on an "AS IS" basis, without warranty of any kind, and the | |
15 | // Initial Developer hereby disclaims all such warranties, including without | |
16 | // limitation, any warranties of merchantability, fitness for a particular | |
17 | // purpose or non-infringement. Please see the License for the specific terms | |
18 | // and conditions governing the rights and limitations under the License. | |
19 | ||
7fd59977 | 20 | |
5f8b738e | 21 | #include <OpenGl_GlCore11.hxx> |
7fd59977 | 22 | |
7edf74fd | 23 | #include <OpenGl_FrameBuffer.hxx> |
7edf74fd | 24 | #include <TColStd_Array2OfReal.hxx> |
2166f0fa | 25 | #include <OpenGl_telem_util.hxx> |
7fd59977 | 26 | |
498ce577 | 27 | #ifdef HAVE_CONFIG_H |
28 | # include <config.h> | |
29 | #endif | |
30 | ||
7edf74fd A |
31 | #ifdef HAVE_FREEIMAGE |
32 | #include <NCollection_Handle.hxx> | |
33 | #include <FreeImagePlus.h> | |
34 | #ifdef _MSC_VER | |
35 | #pragma comment( lib, "FreeImage.lib" ) | |
36 | #pragma comment( lib, "FreeImagePlus.lib" ) | |
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 | // --------------------------------------------------------------- | |
55 | static 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 | // --------------------------------------------------------------- | |
66 | static 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); | |
74 | (aVpDim[0] >= aTexDim) ? aMaxX = (GLsizei) aTexDim : | |
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 | // --------------------------------------------------------------- | |
88 | static 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 | |
102 | // Purpose: calculate maximum possible dimensions for framebuffer | |
103 | // in tiling mode according to the view size | |
104 | // --------------------------------------------------------------- | |
105 | static 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 | // --------------------------------------------------------------- | |
123 | static 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 | ||
137 | if ((aWidthRate > 1 && aHeightRate > 1 && aWidthRate >= aHeightRate) || | |
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 | // --------------------------------------------------------------- | |
157 | static 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 |
176 | static 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 | // --------------------------------------------------------------- | |
206 | static bool imagePasteDC(HDC theDstDC, FipHandle theImage, int theOffsetX, | |
207 | int theOffsetY, int theWidth, int theHeight, | |
208 | int theLeft = 0, int theTop = 0) | |
209 | { | |
210 | // get image parameters | |
211 | BITMAPINFO* aBitmapData = theImage->getInfo (); | |
212 | SetStretchBltMode (theDstDC, STRETCH_HALFTONE); | |
213 | ||
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 | // --------------------------------------------------------------- | |
269 | static 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); | |
282 | ||
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; | |
291 | ||
292 | return true; | |
293 | } | |
294 | #endif | |
295 | #endif | |
7fd59977 | 296 | |
7edf74fd | 297 | // --------------------------------------------------------------- |
7edf74fd | 298 | // --------------------------------------------------------------- |
7fd59977 | 299 | |
2166f0fa SK |
300 | //call_togl_print |
301 | Standard_Boolean OpenGl_Workspace::Print | |
302 | (const Graphic3d_CView& ACView, | |
303 | const Aspect_CLayer2d& ACUnderLayer, | |
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 A |
425 | // try to allocate compatible bitmap and necessary resources |
426 | initBitmapBuffer (hMemDC, hViewBitmap, | |
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 | |
496 | initBitmapBuffer (hMemDC, hViewBitmap, | |
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 | ||
7edf74fd A |
518 | // check if there are proper dimensions |
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 A |
535 | // setup printing context and viewport |
536 | GLint aViewPortBack[4]; | |
7edf74fd | 537 | GLint anAlignBack = 1; |
2166f0fa SK |
538 | |
539 | OpenGl_PrinterContext aPrinterContext (myGContext); | |
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 A |
607 | SetStretchBltMode (hPrnDC, STRETCH_HALFTONE); |
608 | isDone = StretchBlt (hPrnDC, aDevOffx, aDevOffy, width, height, | |
609 | hMemDC, 0, 0, aFrameWidth, aFrameHeight, SRCCOPY); | |
7fd59977 | 610 | } |
7edf74fd | 611 | else |
7fd59977 | 612 | { |
7edf74fd A |
613 | isDone = BitBlt (hPrnDC, aDevOffx, aDevOffy, width, height, |
614 | hMemDC, 0, 0, SRCCOPY); | |
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; | |
623 | Standard_Integer aTotalx = | |
624 | (Standard_Integer)floor ((float)width /aFrameWidth); | |
625 | Standard_Integer aTotaly = | |
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 | |
709 | isDone = BitBlt (hPrnDC, aSubLeft, aSubTop, aRight-aLeft, aBottom-aTop, | |
710 | hMemDC, aLeft, aTop, SRCCOPY); | |
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; | |
725 | ||
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 | } | |
745 | ||
746 | // return OpenGl to the previous state | |
747 | aPrinterContext.Deactivate (); | |
748 | glPixelStorei (GL_PACK_ALIGNMENT, anAlignBack); | |
2166f0fa | 749 | aFrameBuffer->UnbindBuffer (GetGlContext()); |
7edf74fd A |
750 | glViewport (aViewPortBack[0], aViewPortBack[1], |
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; | |
779 | #endif | |
7fd59977 | 780 | } |
7edf74fd | 781 | |
2166f0fa SK |
782 | /*----------------------------------------------------------------------*/ |
783 | ||
784 | //redrawView | |
785 | void OpenGl_Workspace::Redraw1 (const Graphic3d_CView& ACView, | |
786 | const Aspect_CLayer2d& ACUnderLayer, | |
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); | |
817 | toClear |= GL_DEPTH_BUFFER_BIT; | |
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); | |
828 | toClear |= GL_DEPTH_BUFFER_BIT; | |
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 | { | |
842 | #ifndef WNT | |
843 | glXSwapBuffers ((Display*)myDisplay->GetDisplay (), myWindow ); | |
844 | #else | |
845 | SwapBuffers ( wglGetCurrentDC () ); | |
846 | glFlush(); | |
847 | #endif /* WNT */ | |
848 | myBackBufferRestored = Standard_False; | |
849 | } | |
850 | else | |
851 | glFlush(); | |
2166f0fa SK |
852 | } |
853 | ||
854 | /*----------------------------------------------------------------------*/ | |
855 | ||
856 | //TelCopyBuffers | |
857 | void OpenGl_Workspace::CopyBuffers (Tint vid, int FrontToBack, Tfloat xm, Tfloat ym, Tfloat zm, Tfloat XM, Tfloat YM, Tfloat ZM, Tint flag) | |
858 | { | |
859 | if (FrontToBack) myBackBufferRestored = Standard_False; | |
860 | ||
861 | glMatrixMode (GL_PROJECTION); | |
862 | glPushMatrix (); | |
863 | glLoadIdentity (); | |
864 | gluOrtho2D ((GLdouble) 0., (GLdouble) myWidth, 0., (GLdouble) myHeight); | |
865 | glMatrixMode (GL_MODELVIEW); | |
866 | glPushMatrix (); | |
867 | glLoadIdentity (); | |
868 | ||
869 | DisableFeatures(); | |
870 | ||
871 | GLsizei width = myWidth+1, height = myHeight+1; | |
872 | Tfloat xmr = 0, ymr = 0; | |
873 | ||
874 | if (flag) | |
875 | { | |
876 | if (!myView.IsNull()) //szvgl: use vid here! | |
877 | { | |
878 | // Calculate bounding box and store the projected rectangle | |
879 | Tfloat xr[8], yr[8]; | |
880 | // Project bounding box | |
881 | if (myView->ProjectObjectToRaster (myWidth, myHeight, xm, ym, zm, xr[0], yr[0]) && | |
882 | myView->ProjectObjectToRaster (myWidth, myHeight, xm, YM, zm, xr[1], yr[1]) && | |
883 | myView->ProjectObjectToRaster (myWidth, myHeight, XM, YM, zm, xr[2], yr[2]) && | |
884 | myView->ProjectObjectToRaster (myWidth, myHeight, XM, ym, zm, xr[3], yr[3]) && | |
885 | myView->ProjectObjectToRaster (myWidth, myHeight, xm, ym, ZM, xr[4], yr[4]) && | |
886 | myView->ProjectObjectToRaster (myWidth, myHeight, xm, YM, ZM, xr[5], yr[5]) && | |
887 | myView->ProjectObjectToRaster (myWidth, myHeight, XM, YM, ZM, xr[6], yr[6]) && | |
888 | myView->ProjectObjectToRaster (myWidth, myHeight, XM, ym, ZM, xr[7], yr[7])) | |
889 | { | |
890 | Tfloat XMR, YMR; | |
891 | xmr = ymr = (float ) shortreallast (); | |
892 | XMR = YMR = (float ) shortrealfirst (); | |
893 | /* | |
894 | * Recherche du rectangle projete | |
895 | */ | |
896 | Tint i; | |
897 | for (i=0; i<8; i++) { | |
898 | if (xmr > xr[i]) xmr = xr[i]; | |
899 | if (ymr > yr[i]) ymr = yr[i]; | |
900 | if (XMR < xr[i]) XMR = xr[i]; | |
901 | if (YMR < yr[i]) YMR = yr[i]; | |
902 | } | |
903 | /* pour eviter les bavures de pixels ! */ | |
904 | xmr--;ymr--; | |
905 | XMR++;YMR++; | |
906 | ||
907 | /* | |
908 | * Ajout CAL : 10/05/96 | |
909 | * Si les MinMax viennent d'un ensemble de markers | |
910 | * on ne tient pas compte du scale factor de ceux-ci | |
911 | * dans les valeurs de MinMax. En effet, ce facteur | |
912 | * est dans l'espace pixel et les MinMax dans l'espace | |
913 | * du modele. Donc ajout d'un delta de pixels | |
914 | * en esperant que les applis n'utilisent pas des | |
915 | * markers tres gros ! | |
916 | */ | |
917 | xmr -= CALL_DEF_DELTA; ymr -= CALL_DEF_DELTA; | |
918 | XMR += CALL_DEF_DELTA; YMR += CALL_DEF_DELTA; | |
919 | ||
920 | /* | |
921 | * Le rectangle projete peut-etre clippe | |
922 | */ | |
923 | width = (GLsizei) (XMR-xmr+1); | |
924 | height = (GLsizei) (YMR-ymr+1); | |
925 | /* | |
926 | * (xmr,ymr) coin inferieur gauche | |
927 | * (XMR,YMR) coin superieur droit | |
928 | */ | |
929 | /* cas ou 1 coin est en dehors de la fenetre */ | |
930 | if (xmr < 0) { width = (GLsizei) (XMR+1); xmr = 0; } | |
931 | if (ymr < 0) { height = (GLsizei) (YMR+1); ymr = 0; } | |
932 | if (XMR > myWidth) { width = (GLsizei) (myWidth-xmr+1); } | |
933 | if (YMR > myHeight) { height = (GLsizei) (myHeight-ymr+1); } | |
934 | ||
935 | /* cas ou les 2 coins sont en dehors de la fenetre */ | |
936 | if (XMR < 0) { xmr = 0; width = height = 1; } | |
937 | if (YMR < 0) { ymr = 0; width = height = 1; } | |
938 | if (xmr > myWidth) { xmr = 0; width = height = 1; } | |
939 | if (ymr > myHeight) { ymr = 0; width = height = 1; } | |
940 | } | |
941 | } | |
942 | } | |
943 | ||
944 | glDrawBuffer (FrontToBack? GL_BACK : GL_FRONT); | |
945 | glReadBuffer (FrontToBack? GL_FRONT : GL_BACK); | |
946 | /* copie complete */ | |
947 | glRasterPos2i ((GLint) xmr, (GLint) ymr); | |
948 | glCopyPixels ((GLint) xmr, (GLint) ymr, width, height, GL_COLOR); | |
949 | ||
950 | EnableFeatures(); | |
951 | ||
952 | glMatrixMode (GL_PROJECTION); | |
953 | glPopMatrix (); | |
954 | glMatrixMode (GL_MODELVIEW); | |
955 | glPopMatrix (); | |
956 | ||
957 | glDrawBuffer (GL_BACK); | |
958 | } | |
959 | ||
960 | /*----------------------------------------------------------------------*/ | |
961 | ||
962 | //call_subr_displayCB | |
963 | void OpenGl_Workspace::DisplayCallback (const Graphic3d_CView& ACView, int reason) | |
964 | { | |
965 | if( ACView.GDisplayCB ) | |
966 | { | |
967 | Aspect_GraphicCallbackStruct callData; | |
968 | callData.reason = reason; | |
969 | callData.display = (DISPLAY*)myDisplay->GetDisplay(); | |
970 | callData.window = (WINDOW)myWindow; | |
971 | callData.wsID = ACView.WsId; | |
972 | callData.viewID = ACView.ViewId; | |
973 | callData.gcontext = myGContext; | |
974 | ||
975 | int status = (*ACView.GDisplayCB)( ACView.DefWindow.XWindow, ACView.GClientData, &callData ); | |
976 | } | |
977 | } | |
978 | ||
979 | /*----------------------------------------------------------------------*/ |