/*========================================================================= Program: Visualization Toolkit Module: vtkOSOpenGLRenderWindow.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkOSOpenGLRenderWindow.h" #include "vtkOpenGLRenderer.h" #include "vtkOpenGLProperty.h" #include "vtkOpenGLTexture.h" #include "vtkOpenGLCamera.h" #include "vtkOpenGLLight.h" #include "vtkOpenGLActor.h" #include #include "vtkgl.h" #ifdef VTK_OPENGL_HAS_OSMESA # ifndef GLAPI # define GLAPI extern # endif # ifndef GLAPIENTRY # define GLAPIENTRY # endif # ifndef APIENTRY # define APIENTRY GLAPIENTRY # endif # include #endif // VTK_OPENGL_HAS_OSMESA #include "vtkCommand.h" #include "vtkIdList.h" #include "vtkObjectFactory.h" #include "vtkRendererCollection.h" #include "vtkOpenGLExtensionManager.h" #include "vtksys/SystemTools.hxx" #include class vtkOSOpenGLRenderWindow; class vtkRenderWindow; class vtkOSOpenGLRenderWindowInternal { friend class vtkOSOpenGLRenderWindow; private: vtkOSOpenGLRenderWindowInternal(vtkRenderWindow*); // store previous settings of on screen window int ScreenDoubleBuffer; int ScreenMapped; // OffScreen stuff OSMesaContext OffScreenContextId; void *OffScreenWindow; }; vtkOSOpenGLRenderWindowInternal::vtkOSOpenGLRenderWindowInternal( vtkRenderWindow *rw) { this->ScreenMapped = rw->GetMapped(); this->ScreenDoubleBuffer = rw->GetDoubleBuffer(); // OpenGL specific this->OffScreenContextId = NULL; this->OffScreenWindow = NULL; } vtkStandardNewMacro(vtkOSOpenGLRenderWindow); // a couple of routines for offscreen rendering void vtkOSMesaDestroyWindow(void *Window) { free(Window); } void *vtkOSMesaCreateWindow(int width, int height) { return malloc(width*height*4); } vtkOSOpenGLRenderWindow::vtkOSOpenGLRenderWindow() { // this->ParentId = (Window)NULL; this->ScreenSize[0] = 1280; this->ScreenSize[1] = 1024; this->OwnDisplay = 0; this->CursorHidden = 0; this->ForceMakeCurrent = 0; this->OwnWindow = 0; this->Internal = new vtkOSOpenGLRenderWindowInternal(this); this->Capabilities = 0; } // free up memory & close the window vtkOSOpenGLRenderWindow::~vtkOSOpenGLRenderWindow() { // close-down all system-specific drawing resources this->Finalize(); vtkRenderer *ren; vtkCollectionSimpleIterator rit; this->Renderers->InitTraversal(rit); while ( (ren = this->Renderers->GetNextRenderer(rit)) ) { ren->SetRenderWindow(NULL); } delete this->Internal; } // End the rendering process and display the image. void vtkOSOpenGLRenderWindow::Frame() { this->MakeCurrent(); glFlush(); } // // Set the variable that indicates that we want a stereo capable window // be created. This method can only be called before a window is realized. // void vtkOSOpenGLRenderWindow::SetStereoCapableWindow(int capable) { if (!this->Internal->OffScreenContextId) { vtkOpenGLRenderWindow::SetStereoCapableWindow(capable); } else { vtkWarningMacro(<< "Requesting a StereoCapableWindow must be performed " << "before the window is realized, i.e. before a render."); } } void vtkOSOpenGLRenderWindow::CreateAWindow() { this->CreateOffScreenWindow(this->ScreenSize[0], this->ScreenSize[1]); } void vtkOSOpenGLRenderWindow::DestroyWindow() { this->MakeCurrent(); // tell each of the renderers that this render window/graphics context // is being removed (the RendererCollection is removed by vtkRenderWindow's // destructor) vtkRenderer* ren; this->Renderers->InitTraversal(); for ( ren = vtkOpenGLRenderer::SafeDownCast(this->Renderers->GetNextItemAsObject()); ren != NULL; ren = vtkOpenGLRenderer::SafeDownCast(this->Renderers->GetNextItemAsObject()) ) { ren->SetRenderWindow(NULL); ren->SetRenderWindow(this); } delete[] this->Capabilities; this->Capabilities = 0; this->DestroyOffScreenWindow(); // make sure all other code knows we're not mapped anymore this->Mapped = 0; } void vtkOSOpenGLRenderWindow::CreateOffScreenWindow(int width, int height) { this->DoubleBuffer = 0; if (!this->Internal->OffScreenWindow) { this->Internal->OffScreenWindow = vtkOSMesaCreateWindow(width,height); this->OwnWindow = 1; } if (!this->Internal->OffScreenContextId) { this->Internal->OffScreenContextId = OSMesaCreateContext(GL_RGBA, NULL); } this->MakeCurrent(); this->Mapped = 0; this->Size[0] = width; this->Size[1] = height; this->MakeCurrent(); // tell our renderers about us vtkRenderer* ren; for (this->Renderers->InitTraversal(); (ren = this->Renderers->GetNextItem());) { ren->SetRenderWindow(0); ren->SetRenderWindow(this); } this->OpenGLInit(); } void vtkOSOpenGLRenderWindow::DestroyOffScreenWindow() { // release graphic resources. vtkRenderer *ren; vtkCollectionSimpleIterator rit; this->Renderers->InitTraversal(rit); while ( (ren = this->Renderers->GetNextRenderer(rit)) ) { ren->SetRenderWindow(NULL); ren->SetRenderWindow(this); } if (this->Internal->OffScreenContextId) { OSMesaDestroyContext(this->Internal->OffScreenContextId); this->Internal->OffScreenContextId = NULL; vtkOSMesaDestroyWindow(this->Internal->OffScreenWindow); this->Internal->OffScreenWindow = NULL; } } void vtkOSOpenGLRenderWindow::ResizeOffScreenWindow(int width, int height) { if(this->Internal->OffScreenContextId) { this->DestroyOffScreenWindow(); this->CreateOffScreenWindow(width, height); } } // Initialize the window for rendering. void vtkOSOpenGLRenderWindow::WindowInitialize (void) { this->CreateAWindow(); this->MakeCurrent(); // tell our renderers about us vtkRenderer* ren; for (this->Renderers->InitTraversal(); (ren = this->Renderers->GetNextItem());) { ren->SetRenderWindow(0); ren->SetRenderWindow(this); } this->OpenGLInit(); } // Initialize the rendering window. void vtkOSOpenGLRenderWindow::Initialize (void) { if(! (this->Internal->OffScreenContextId)) { // initialize offscreen window int width = ((this->Size[0] > 0) ? this->Size[0] : 300); int height = ((this->Size[1] > 0) ? this->Size[1] : 300); this->CreateOffScreenWindow(width, height); } } void vtkOSOpenGLRenderWindow::Finalize (void) { // clean up offscreen stuff this->SetOffScreenRendering(0); // clean and destroy window this->DestroyWindow(); } // Change the window to fill the entire screen. void vtkOSOpenGLRenderWindow::SetFullScreen(int arg) { (void)arg; this->Modified(); } // Resize the window. void vtkOSOpenGLRenderWindow::WindowRemap() { // shut everything down this->Finalize(); // set the default windowid // this->WindowId = this->NextWindowId; // this->NextWindowId = (Window)NULL; // set everything up again this->Initialize(); } // Begin the rendering process. void vtkOSOpenGLRenderWindow::Start(void) { this->Initialize(); // set the current window this->MakeCurrent(); } // Specify the size of the rendering window. void vtkOSOpenGLRenderWindow::SetSize(int width,int height) { if ((this->Size[0] != width)||(this->Size[1] != height)) { this->Superclass::SetSize(width, height); this->ResizeOffScreenWindow(width, height); this->Modified(); } } void vtkOSOpenGLRenderWindow::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "OffScreenContextId: " << this->Internal->OffScreenContextId << "\n"; // os << indent << "Color Map: " << this->ColorMap << "\n"; // os << indent << "Next Window Id: " << this->NextWindowId << "\n"; // os << indent << "Window Id: " << this->GetWindowId() << "\n"; } void vtkOSOpenGLRenderWindow::MakeCurrent() { // set the current window if (this->Internal->OffScreenContextId) { if (OSMesaMakeCurrent(this->Internal->OffScreenContextId, this->Internal->OffScreenWindow, GL_UNSIGNED_BYTE, this->Size[0], this->Size[1]) != GL_TRUE) { vtkWarningMacro("failed call to OSMesaMakeCurrent"); } } } // ---------------------------------------------------------------------------- // Description: // Tells if this window is the current OpenGL context for the calling thread. bool vtkOSOpenGLRenderWindow::IsCurrent() { bool result=false; if(this->Internal->OffScreenContextId) { result=this->Internal->OffScreenContextId==OSMesaGetCurrentContext(); } return result; } void vtkOSOpenGLRenderWindow::SetForceMakeCurrent() { this->ForceMakeCurrent = 1; } void *vtkOSOpenGLRenderWindow::GetGenericContext() { return (void *)this->Internal->OffScreenContextId; } int vtkOSOpenGLRenderWindow::GetEventPending() { return 0; } // Get the size of the screen in pixels int *vtkOSOpenGLRenderWindow::GetScreenSize() { this->ScreenSize[0] = 1280; this->ScreenSize[1] = 1024; return this->ScreenSize; } // Get the position in screen coordinates (pixels) of the window. int *vtkOSOpenGLRenderWindow::GetPosition(void) { return this->Position; } // Move the window to a new position on the display. void vtkOSOpenGLRenderWindow::SetPosition(int x, int y) { if ((this->Position[0] != x)||(this->Position[1] != y)) { this->Modified(); } this->Position[0] = x; this->Position[1] = y; } // Set this RenderWindow's X window id to a pre-existing window. void vtkOSOpenGLRenderWindow::SetWindowInfo(char *info) { int tmp; this->OwnDisplay = 1; sscanf(info,"%i",&tmp); } // Set this RenderWindow's X window id to a pre-existing window. void vtkOSOpenGLRenderWindow::SetNextWindowInfo(char *info) { int tmp; sscanf(info,"%i",&tmp); // this->SetNextWindowId((Window)tmp); } // Sets the X window id of the window that WILL BE created. void vtkOSOpenGLRenderWindow::SetParentInfo(char *info) { int tmp; // get the default display connection this->OwnDisplay = 1; sscanf(info,"%i",&tmp); // this->SetParentId(tmp); } void vtkOSOpenGLRenderWindow::SetWindowId(void *arg) { (void)arg; // this->SetWindowId((Window)arg); } void vtkOSOpenGLRenderWindow::SetParentId(void *arg) { (void)arg; // this->SetParentId((Window)arg); } const char* vtkOSOpenGLRenderWindow::ReportCapabilities() { MakeCurrent(); // int scrnum = DefaultScreen(this->DisplayId); const char *glVendor = (const char *) glGetString(GL_VENDOR); const char *glRenderer = (const char *) glGetString(GL_RENDERER); const char *glVersion = (const char *) glGetString(GL_VERSION); const char *glExtensions = (const char *) glGetString(GL_EXTENSIONS); std::ostringstream strm; strm << "OpenGL vendor string: " << glVendor << endl; strm << "OpenGL renderer string: " << glRenderer << endl; strm << "OpenGL version string: " << glVersion << endl; strm << "OpenGL extensions: " << glExtensions << endl; delete[] this->Capabilities; size_t len = strm.str().length(); this->Capabilities = new char[len + 1]; strncpy(this->Capabilities, strm.str().c_str(), len); this->Capabilities[len] = 0; return this->Capabilities; } int vtkOSOpenGLRenderWindow::SupportsOpenGL() { MakeCurrent(); return 1; } int vtkOSOpenGLRenderWindow::IsDirect() { MakeCurrent(); return 0; } void vtkOSOpenGLRenderWindow::SetWindowName(const char * cname) { char *name = new char[ strlen(cname)+1 ]; strcpy(name, cname); vtkOpenGLRenderWindow::SetWindowName( name ); delete [] name; } // Specify the X window id to use if a WindowRemap is done. /*void vtkOSOpenGLRenderWindow::SetNextWindowId(Window arg) { vtkDebugMacro(<< "Setting NextWindowId to " << (void *)arg << "\n"); this->NextWindowId = arg; }*/ void vtkOSOpenGLRenderWindow::SetNextWindowId(void *arg) { (void)arg; // this->SetNextWindowId((Window)arg); } // Set the X display id for this RenderWindow to use to a pre-existing // X display id. /*void vtkOSOpenGLRenderWindow::SetDisplayId(Display *arg) { vtkDebugMacro(<< "Setting DisplayId to " << (void *)arg << "\n"); this->DisplayId = arg; this->OwnDisplay = 0; }*/ /*void vtkOSOpenGLRenderWindow::SetDisplayId(void *arg) { this->SetDisplayId((Display *)arg); this->OwnDisplay = 0; }*/ //============================================================================ // Stuff above this is almost a mirror of vtkOSOpenGLRenderWindow. // The code specific to OpenGL Off-Screen stuff may eventually be // put in a supper class so this whole file could just be included // (mangled) from vtkOSOpenGLRenderWindow like the other OpenGL classes. //============================================================================ void vtkOSOpenGLRenderWindow::SetOffScreenRendering(int i) { if (this->OffScreenRendering == i) { return; } // invoke super this->vtkRenderWindow::SetOffScreenRendering(i); this->Internal->ScreenDoubleBuffer = this->DoubleBuffer; this->DoubleBuffer = 0; if(this->Mapped) { this->DestroyWindow(); } // delay initialization until Render } // This probably has been moved to superclass. void *vtkOSOpenGLRenderWindow::GetGenericWindowId() { return (void *)this->Internal->OffScreenWindow; } void vtkOSOpenGLRenderWindow::SetCurrentCursor(int shape) { if ( this->InvokeEvent(vtkCommand::CursorChangedEvent,&shape) ) { return; } this->Superclass::SetCurrentCursor(shape); }