1 /*=========================================================================
2 
3 Program:   Visualization Toolkit
4 Module:    vtkOSOpenGLRenderWindow.cxx
5 
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkOSOpenGLRenderWindow.h"
16 #include "vtkOpenGLRenderer.h"
17 #include "vtkOpenGLProperty.h"
18 #include "vtkOpenGLTexture.h"
19 #include "vtkOpenGLCamera.h"
20 #include "vtkOpenGLLight.h"
21 #include "vtkOpenGLActor.h"
22 #include <GL/gl.h>
23 #include "vtkgl.h"
24 
25 #ifdef VTK_OPENGL_HAS_OSMESA
26 # include <GL/osmesa.h>
27 #endif
28 
29 #include "vtkCommand.h"
30 #include "vtkIdList.h"
31 #include "vtkObjectFactory.h"
32 #include "vtkRendererCollection.h"
33 #include "vtkOpenGLExtensionManager.h"
34 
35 #include "vtksys/SystemTools.hxx"
36 #include "vtksys/ios/sstream"
37 
38 class vtkOSOpenGLRenderWindow;
39 class vtkRenderWindow;
40 
41 class vtkOSOpenGLRenderWindowInternal
42 {
43   friend class vtkOSOpenGLRenderWindow;
44 private:
45   vtkOSOpenGLRenderWindowInternal(vtkRenderWindow*);
46 
47   // store previous settings of on screen window
48   int ScreenDoubleBuffer;
49   int ScreenMapped;
50 
51   // OffScreen stuff
52   OSMesaContext OffScreenContextId;
53   void *OffScreenWindow;
54 };
55 
vtkOSOpenGLRenderWindowInternal(vtkRenderWindow * rw)56 vtkOSOpenGLRenderWindowInternal::vtkOSOpenGLRenderWindowInternal(
57   vtkRenderWindow *rw)
58 {
59 
60   this->ScreenMapped = rw->GetMapped();
61   this->ScreenDoubleBuffer = rw->GetDoubleBuffer();
62 
63   // OpenGL specific
64   this->OffScreenContextId = NULL;
65   this->OffScreenWindow = NULL;
66 }
67 
68 
69 vtkStandardNewMacro(vtkOSOpenGLRenderWindow);
70 
71 // a couple of routines for offscreen rendering
vtkOSMesaDestroyWindow(void * Window)72 void vtkOSMesaDestroyWindow(void *Window)
73 {
74   free(Window);
75 }
76 
vtkOSMesaCreateWindow(int width,int height)77 void *vtkOSMesaCreateWindow(int width, int height)
78 {
79   return malloc(width*height*4);
80 }
81 
vtkOSOpenGLRenderWindow()82 vtkOSOpenGLRenderWindow::vtkOSOpenGLRenderWindow()
83 {
84 //   this->ParentId = (Window)NULL;
85   this->ScreenSize[0] = 1280;
86   this->ScreenSize[1] = 1024;
87   this->OwnDisplay = 0;
88   this->CursorHidden = 0;
89   this->ForceMakeCurrent = 0;
90   this->OwnWindow = 0;
91 
92   this->Internal = new vtkOSOpenGLRenderWindowInternal(this);
93 
94   this->Capabilities = 0;
95 
96 }
97 
98 // free up memory & close the window
~vtkOSOpenGLRenderWindow()99 vtkOSOpenGLRenderWindow::~vtkOSOpenGLRenderWindow()
100 {
101   // close-down all system-specific drawing resources
102   this->Finalize();
103 
104   vtkRenderer *ren;
105   vtkCollectionSimpleIterator rit;
106   this->Renderers->InitTraversal(rit);
107   while ( (ren = this->Renderers->GetNextRenderer(rit)) )
108     {
109     ren->SetRenderWindow(NULL);
110     }
111 
112   delete this->Internal;
113 }
114 
115 // End the rendering process and display the image.
Frame()116 void vtkOSOpenGLRenderWindow::Frame()
117 {
118   this->MakeCurrent();
119   glFlush();
120 }
121 
122 //
123 // Set the variable that indicates that we want a stereo capable window
124 // be created. This method can only be called before a window is realized.
125 //
SetStereoCapableWindow(int capable)126 void vtkOSOpenGLRenderWindow::SetStereoCapableWindow(int capable)
127 {
128   if (!this->Internal->OffScreenContextId)
129     {
130     vtkOpenGLRenderWindow::SetStereoCapableWindow(capable);
131     }
132   else
133     {
134     vtkWarningMacro(<< "Requesting a StereoCapableWindow must be performed "
135                     << "before the window is realized, i.e. before a render.");
136     }
137 }
138 
CreateAWindow()139 void vtkOSOpenGLRenderWindow::CreateAWindow()
140 {
141   this->CreateOffScreenWindow(this->ScreenSize[0], this->ScreenSize[1]);
142 }
143 
DestroyWindow()144 void vtkOSOpenGLRenderWindow::DestroyWindow()
145 {
146   this->MakeCurrent();
147 
148   // tell each of the renderers that this render window/graphics context
149   // is being removed (the RendererCollection is removed by vtkRenderWindow's
150   // destructor)
151   vtkRenderer* ren;
152   this->Renderers->InitTraversal();
153   for ( ren = vtkOpenGLRenderer::SafeDownCast(this->Renderers->GetNextItemAsObject());
154         ren != NULL;
155         ren = vtkOpenGLRenderer::SafeDownCast(this->Renderers->GetNextItemAsObject())  )
156     {
157     ren->SetRenderWindow(NULL);
158     ren->SetRenderWindow(this);
159     }
160 
161 
162   if (this->Capabilities)
163     {
164     delete[] this->Capabilities;
165     this->Capabilities = 0;
166     }
167 
168   this->DestroyOffScreenWindow();
169 
170   // make sure all other code knows we're not mapped anymore
171   this->Mapped = 0;
172 
173 }
174 
CreateOffScreenWindow(int width,int height)175 void vtkOSOpenGLRenderWindow::CreateOffScreenWindow(int width, int height)
176 {
177 
178   this->DoubleBuffer = 0;
179 
180   if (!this->Internal->OffScreenWindow)
181     {
182     this->Internal->OffScreenWindow = vtkOSMesaCreateWindow(width,height);
183     this->OwnWindow = 1;
184     }
185   if (!this->Internal->OffScreenContextId)
186     {
187     this->Internal->OffScreenContextId = OSMesaCreateContext(GL_RGBA, NULL);
188     }
189   this->MakeCurrent();
190 
191   this->Mapped = 0;
192   this->Size[0] = width;
193   this->Size[1] = height;
194 
195   this->MakeCurrent();
196 
197   // tell our renderers about us
198   vtkRenderer* ren;
199   for (this->Renderers->InitTraversal();
200        (ren = this->Renderers->GetNextItem());)
201     {
202     ren->SetRenderWindow(0);
203     ren->SetRenderWindow(this);
204     }
205 
206   this->OpenGLInit();
207 }
208 
DestroyOffScreenWindow()209 void vtkOSOpenGLRenderWindow::DestroyOffScreenWindow()
210 {
211 
212   // release graphic resources.
213   vtkRenderer *ren;
214   vtkCollectionSimpleIterator rit;
215   this->Renderers->InitTraversal(rit);
216   while ( (ren = this->Renderers->GetNextRenderer(rit)) )
217     {
218     ren->SetRenderWindow(NULL);
219     ren->SetRenderWindow(this);
220     }
221 
222 
223   if (this->Internal->OffScreenContextId)
224     {
225     OSMesaDestroyContext(this->Internal->OffScreenContextId);
226     this->Internal->OffScreenContextId = NULL;
227     vtkOSMesaDestroyWindow(this->Internal->OffScreenWindow);
228     this->Internal->OffScreenWindow = NULL;
229     }
230 }
231 
ResizeOffScreenWindow(int width,int height)232 void vtkOSOpenGLRenderWindow::ResizeOffScreenWindow(int width, int height)
233 {
234   if(this->Internal->OffScreenContextId)
235     {
236     this->DestroyOffScreenWindow();
237     this->CreateOffScreenWindow(width, height);
238     }
239 }
240 
241 
242 // Initialize the window for rendering.
WindowInitialize(void)243 void vtkOSOpenGLRenderWindow::WindowInitialize (void)
244 {
245   this->CreateAWindow();
246 
247   this->MakeCurrent();
248 
249   // tell our renderers about us
250   vtkRenderer* ren;
251   for (this->Renderers->InitTraversal();
252        (ren = this->Renderers->GetNextItem());)
253     {
254     ren->SetRenderWindow(0);
255     ren->SetRenderWindow(this);
256     }
257 
258   this->OpenGLInit();
259 }
260 
261 // Initialize the rendering window.
Initialize(void)262 void vtkOSOpenGLRenderWindow::Initialize (void)
263 {
264   if(! (this->Internal->OffScreenContextId))
265     {
266     // initialize offscreen window
267     int width = ((this->Size[0] > 0) ? this->Size[0] : 300);
268     int height = ((this->Size[1] > 0) ? this->Size[1] : 300);
269     this->CreateOffScreenWindow(width, height);
270     }
271 }
272 
Finalize(void)273 void vtkOSOpenGLRenderWindow::Finalize (void)
274 {
275 
276   // clean up offscreen stuff
277   this->SetOffScreenRendering(0);
278 
279   // clean and destroy window
280   this->DestroyWindow();
281 
282 }
283 
284 // Change the window to fill the entire screen.
SetFullScreen(int arg)285 void vtkOSOpenGLRenderWindow::SetFullScreen(int arg)
286 {
287   (void)arg;
288   this->Modified();
289 }
290 
291 // Resize the window.
WindowRemap()292 void vtkOSOpenGLRenderWindow::WindowRemap()
293 {
294   // shut everything down
295   this->Finalize();
296 
297   // set the default windowid
298 //   this->WindowId = this->NextWindowId;
299 //   this->NextWindowId = (Window)NULL;
300 
301   // set everything up again
302   this->Initialize();
303 }
304 
305 // Begin the rendering process.
Start(void)306 void vtkOSOpenGLRenderWindow::Start(void)
307 {
308   this->Initialize();
309 
310   // set the current window
311   this->MakeCurrent();
312 }
313 
314 
315 // Specify the size of the rendering window.
SetSize(int width,int height)316 void vtkOSOpenGLRenderWindow::SetSize(int width,int height)
317 {
318   if ((this->Size[0] != width)||(this->Size[1] != height))
319     {
320     this->Size[0] = width;
321     this->Size[1] = height;
322     this->ResizeOffScreenWindow(width,height);
323     this->Modified();
324     }
325 }
326 
PrintSelf(ostream & os,vtkIndent indent)327 void vtkOSOpenGLRenderWindow::PrintSelf(ostream& os, vtkIndent indent)
328 {
329   this->Superclass::PrintSelf(os,indent);
330 
331   os << indent << "OffScreenContextId: " << this->Internal->OffScreenContextId << "\n";
332 //   os << indent << "Color Map: " << this->ColorMap << "\n";
333 //   os << indent << "Next Window Id: " << this->NextWindowId << "\n";
334 //   os << indent << "Window Id: " << this->GetWindowId() << "\n";
335 }
336 
MakeCurrent()337 void vtkOSOpenGLRenderWindow::MakeCurrent()
338 {
339   // set the current window
340   if (this->Internal->OffScreenContextId)
341     {
342     if (OSMesaMakeCurrent(this->Internal->OffScreenContextId,
343                           this->Internal->OffScreenWindow, GL_UNSIGNED_BYTE,
344                           this->Size[0], this->Size[1]) != GL_TRUE)
345       {
346       vtkWarningMacro("failed call to OSMesaMakeCurrent");
347       }
348     }
349 }
350 
351 // ----------------------------------------------------------------------------
352 // Description:
353 // Tells if this window is the current OpenGL context for the calling thread.
IsCurrent()354 bool vtkOSOpenGLRenderWindow::IsCurrent()
355 {
356   bool result=false;
357   if(this->Internal->OffScreenContextId)
358     {
359     result=this->Internal->OffScreenContextId==OSMesaGetCurrentContext();
360     }
361   return result;
362 }
363 
364 
SetForceMakeCurrent()365 void vtkOSOpenGLRenderWindow::SetForceMakeCurrent()
366 {
367   this->ForceMakeCurrent = 1;
368 }
369 
GetGenericContext()370 void *vtkOSOpenGLRenderWindow::GetGenericContext()
371 {
372   return (void *)this->Internal->OffScreenContextId;
373 }
374 
GetEventPending()375 int vtkOSOpenGLRenderWindow::GetEventPending()
376 {
377   return 0;
378 }
379 
380 // Get the size of the screen in pixels
GetScreenSize()381 int *vtkOSOpenGLRenderWindow::GetScreenSize()
382 {
383 
384   this->ScreenSize[0] = 1280;
385   this->ScreenSize[1] = 1024;
386   return this->ScreenSize;
387 }
388 
389 // Get the position in screen coordinates (pixels) of the window.
GetPosition(void)390 int *vtkOSOpenGLRenderWindow::GetPosition(void)
391 {
392   return this->Position;
393 }
394 
395 // Move the window to a new position on the display.
SetPosition(int x,int y)396 void vtkOSOpenGLRenderWindow::SetPosition(int x, int y)
397 {
398   if ((this->Position[0] != x)||(this->Position[1] != y))
399     {
400     this->Modified();
401     }
402   this->Position[0] = x;
403   this->Position[1] = y;
404 }
405 
406 // Set this RenderWindow's X window id to a pre-existing window.
SetWindowInfo(char * info)407 void vtkOSOpenGLRenderWindow::SetWindowInfo(char *info)
408 {
409   int tmp;
410 
411   this->OwnDisplay = 1;
412 
413   sscanf(info,"%i",&tmp);
414 
415 }
416 
417 // Set this RenderWindow's X window id to a pre-existing window.
SetNextWindowInfo(char * info)418 void vtkOSOpenGLRenderWindow::SetNextWindowInfo(char *info)
419 {
420   int tmp;
421   sscanf(info,"%i",&tmp);
422 
423 //   this->SetNextWindowId((Window)tmp);
424 }
425 
426 // Sets the X window id of the window that WILL BE created.
SetParentInfo(char * info)427 void vtkOSOpenGLRenderWindow::SetParentInfo(char *info)
428 {
429   int tmp;
430 
431   // get the default display connection
432   this->OwnDisplay = 1;
433 
434   sscanf(info,"%i",&tmp);
435 
436 //   this->SetParentId(tmp);
437 }
438 
SetWindowId(void * arg)439 void vtkOSOpenGLRenderWindow::SetWindowId(void *arg)
440 {
441   (void)arg;
442 //   this->SetWindowId((Window)arg);
443 }
SetParentId(void * arg)444 void vtkOSOpenGLRenderWindow::SetParentId(void *arg)
445 {
446   (void)arg;
447 //   this->SetParentId((Window)arg);
448 }
449 
ReportCapabilities()450 const char* vtkOSOpenGLRenderWindow::ReportCapabilities()
451 {
452   MakeCurrent();
453 
454 //   int scrnum = DefaultScreen(this->DisplayId);
455 
456   const char *glVendor = (const char *) glGetString(GL_VENDOR);
457   const char *glRenderer = (const char *) glGetString(GL_RENDERER);
458   const char *glVersion = (const char *) glGetString(GL_VERSION);
459   const char *glExtensions = (const char *) glGetString(GL_EXTENSIONS);
460 
461   vtksys_ios::ostringstream strm;
462   strm << "OpenGL vendor string:  " << glVendor << endl;
463   strm << "OpenGL renderer string:  " << glRenderer << endl;
464   strm << "OpenGL version string:  " << glVersion << endl;
465   strm << "OpenGL extensions:  " << glExtensions << endl;
466   delete[] this->Capabilities;
467   size_t len = strm.str().length();
468   this->Capabilities = new char[len + 1];
469   strncpy(this->Capabilities, strm.str().c_str(), len);
470   this->Capabilities[len] = 0;
471   return this->Capabilities;
472 }
473 
SupportsOpenGL()474 int vtkOSOpenGLRenderWindow::SupportsOpenGL()
475 {
476   MakeCurrent();
477   return 1;
478 }
479 
480 
IsDirect()481 int vtkOSOpenGLRenderWindow::IsDirect()
482 {
483   MakeCurrent();
484   return 0;
485 }
486 
487 
SetWindowName(const char * cname)488 void vtkOSOpenGLRenderWindow::SetWindowName(const char * cname)
489 {
490   char *name = new char[ strlen(cname)+1 ];
491   strcpy(name, cname);
492   vtkOpenGLRenderWindow::SetWindowName( name );
493   delete [] name;
494 }
495 
496 // Specify the X window id to use if a WindowRemap is done.
497 /*void vtkOSOpenGLRenderWindow::SetNextWindowId(Window arg)
498 {
499   vtkDebugMacro(<< "Setting NextWindowId to " << (void *)arg << "\n");
500 
501   this->NextWindowId = arg;
502 }*/
503 
SetNextWindowId(void * arg)504 void vtkOSOpenGLRenderWindow::SetNextWindowId(void *arg)
505 {
506   (void)arg;
507 //   this->SetNextWindowId((Window)arg);
508 }
509 
510 
511 // Set the X display id for this RenderWindow to use to a pre-existing
512 // X display id.
513 /*void vtkOSOpenGLRenderWindow::SetDisplayId(Display  *arg)
514 {
515   vtkDebugMacro(<< "Setting DisplayId to " << (void *)arg << "\n");
516 
517   this->DisplayId = arg;
518   this->OwnDisplay = 0;
519 
520 }*/
521 
522 /*void vtkOSOpenGLRenderWindow::SetDisplayId(void *arg)
523 {
524   this->SetDisplayId((Display *)arg);
525   this->OwnDisplay = 0;
526 }*/
527 
528 //============================================================================
529 // Stuff above this is almost a mirror of vtkOSOpenGLRenderWindow.
530 // The code specific to OpenGL Off-Screen stuff may eventually be
531 // put in a supper class so this whole file could just be included
532 // (mangled) from vtkOSOpenGLRenderWindow like the other OpenGL classes.
533 //============================================================================
534 
SetOffScreenRendering(int i)535 void vtkOSOpenGLRenderWindow::SetOffScreenRendering(int i)
536 {
537   if (this->OffScreenRendering == i)
538     {
539     return;
540     }
541 
542   // invoke super
543   this->vtkRenderWindow::SetOffScreenRendering(i);
544 
545   this->Internal->ScreenDoubleBuffer = this->DoubleBuffer;
546   this->DoubleBuffer = 0;
547   if(this->Mapped)
548     {
549     this->DestroyWindow();
550     }
551 
552   // delay initialization until Render
553 }
554 
555 // This probably has been moved to superclass.
GetGenericWindowId()556 void *vtkOSOpenGLRenderWindow::GetGenericWindowId()
557 {
558   return (void *)this->Internal->OffScreenWindow;
559 }
560 
SetCurrentCursor(int shape)561 void vtkOSOpenGLRenderWindow::SetCurrentCursor(int shape)
562 {
563   if ( this->InvokeEvent(vtkCommand::CursorChangedEvent,&shape) )
564     {
565     return;
566     }
567   this->Superclass::SetCurrentCursor(shape);
568 }
569