You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1772 lines
48 KiB
C++
1772 lines
48 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkWin32OpenGLRenderWindow.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 "vtkWin32OpenGLRenderWindow.h"
|
|
|
|
#include "vtkIdList.h"
|
|
#include "vtkCommand.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkOpenGLRenderer.h"
|
|
#include "vtkOpenGLRenderWindow.h"
|
|
#include "vtkOpenGLError.h"
|
|
#include "vtkRendererCollection.h"
|
|
#include "vtkTypeTraits.h"
|
|
#include "vtkWin32RenderWindowInteractor.h"
|
|
|
|
#include <cmath>
|
|
#include <sstream>
|
|
|
|
#include "vtkOpenGL.h"
|
|
#include "vtkOpenGLError.h"
|
|
#include "vtkgl.h"
|
|
|
|
// Mouse wheel support
|
|
// In an ideal world we would just have to include <zmouse.h>, but it is not
|
|
// always available with all compilers/headers
|
|
#ifndef WM_MOUSEWHEEL
|
|
# define WM_MOUSEWHEEL 0x020A
|
|
#endif //WM_MOUSEWHEEL
|
|
|
|
vtkStandardNewMacro(vtkWin32OpenGLRenderWindow);
|
|
|
|
#define VTK_MAX_LIGHTS 8
|
|
|
|
vtkWin32OpenGLRenderWindow::vtkWin32OpenGLRenderWindow()
|
|
{
|
|
this->ApplicationInstance = NULL;
|
|
this->Palette = NULL;
|
|
this->ContextId = 0;
|
|
this->WindowId = 0;
|
|
this->ParentId = 0;
|
|
this->NextWindowId = 0;
|
|
this->DeviceContext = (HDC)0;
|
|
this->MFChandledWindow = FALSE;
|
|
this->StereoType = VTK_STEREO_CRYSTAL_EYES;
|
|
this->CursorHidden = 0;
|
|
this->Capabilities = 0;
|
|
|
|
this->ScreenDeviceContext = (HDC)0;
|
|
this->MemoryHdc = (HDC)0;
|
|
this->CreatingOffScreenWindow = 0;
|
|
this->WindowIdReferenceCount = 0;
|
|
|
|
this->ScreenMapped = this->Mapped;
|
|
this->ScreenWindowSize[0] = this->Size[0];
|
|
this->ScreenWindowSize[1] = this->Size[1];
|
|
this->ScreenDeviceContext = this->DeviceContext;
|
|
this->ScreenDoubleBuffer = this->DoubleBuffer;
|
|
this->ScreenContextId = this->ContextId;
|
|
}
|
|
|
|
vtkWin32OpenGLRenderWindow::~vtkWin32OpenGLRenderWindow()
|
|
{
|
|
this->Finalize();
|
|
|
|
vtkRenderer *ren;
|
|
vtkCollectionSimpleIterator rit;
|
|
this->Renderers->InitTraversal(rit);
|
|
while ((ren = this->Renderers->GetNextRenderer(rit)))
|
|
{
|
|
ren->SetRenderWindow(NULL);
|
|
}
|
|
|
|
delete[] this->Capabilities;
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::Clean()
|
|
{
|
|
GLuint id;
|
|
|
|
/* finish OpenGL rendering */
|
|
if (this->OwnContext && this->ContextId)
|
|
{
|
|
this->MakeCurrent();
|
|
vtkOpenGLClearErrorMacro();
|
|
|
|
/* first delete all the old lights */
|
|
for (short cur_light = GL_LIGHT0; cur_light < GL_LIGHT0+VTK_MAX_LIGHTS; cur_light++)
|
|
{
|
|
glDisable((GLenum)cur_light);
|
|
}
|
|
|
|
/* now delete all textures */
|
|
glDisable(GL_TEXTURE_2D);
|
|
for (int i = 1; i < this->TextureResourceIds->GetNumberOfIds(); i++)
|
|
{
|
|
id = (GLuint)this->TextureResourceIds->GetId(i);
|
|
#ifdef GL_VERSION_1_1
|
|
if (glIsTexture(id))
|
|
{
|
|
glDeleteTextures(1, &id);
|
|
}
|
|
#else
|
|
if (glIsList(id))
|
|
{
|
|
glDeleteLists(id,1);
|
|
}
|
|
#endif
|
|
}
|
|
vtkOpenGLCheckErrorMacro("failed in Clean");
|
|
|
|
this->CleanUpRenderers();
|
|
|
|
// Note: wglMakeCurrent(NULL,NULL) is valid according to the documentation
|
|
// and works with nVidia and ATI but not with Intel. Passing an existing
|
|
// device context works in any case.
|
|
// see VTK Bug 7119.
|
|
if (wglMakeCurrent(this->DeviceContext,NULL)!=TRUE)
|
|
{
|
|
vtkErrorMacro("wglMakeCurrent failed in Clean(), error: " << GetLastError());
|
|
}
|
|
if (wglDeleteContext(this->ContextId) != TRUE)
|
|
{
|
|
vtkErrorMacro("wglDeleteContext failed in Clean(), error: " << GetLastError());
|
|
}
|
|
}
|
|
this->ContextId = NULL;
|
|
|
|
if (this->Palette)
|
|
{
|
|
SelectPalette(this->DeviceContext, this->OldPalette, FALSE); // SVA delete the old palette
|
|
DeleteObject(this->Palette);
|
|
this->Palette = NULL;
|
|
}
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::CleanUpRenderers()
|
|
{
|
|
// tell each of the renderers that this render window/graphics context
|
|
// is being removed (the RendererCollection is removed by vtkRenderWindow's
|
|
// destructor)
|
|
vtkRenderer *ren;
|
|
vtkCollectionSimpleIterator rsit;
|
|
for (this->Renderers->InitTraversal(rsit);
|
|
(ren = this->Renderers->GetNextRenderer(rsit));)
|
|
{
|
|
ren->SetRenderWindow(NULL);
|
|
}
|
|
}
|
|
|
|
LRESULT APIENTRY vtkWin32OpenGLRenderWindow::WndProc(HWND hWnd, UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
LRESULT res;
|
|
|
|
vtkWin32OpenGLRenderWindow *me =
|
|
(vtkWin32OpenGLRenderWindow *)vtkGetWindowLong(hWnd, sizeof(vtkLONG));
|
|
|
|
if (me && me->GetReferenceCount()>0)
|
|
{
|
|
me->Register(me);
|
|
res = me->MessageProc(hWnd, message, wParam, lParam);
|
|
me->UnRegister(me);
|
|
}
|
|
else
|
|
{
|
|
res = DefWindowProc(hWnd, message, wParam, lParam);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::SetWindowName(const char * _arg)
|
|
{
|
|
vtkWindow::SetWindowName(_arg);
|
|
if (this->WindowId)
|
|
{
|
|
#ifdef UNICODE
|
|
wchar_t *wname = new wchar_t [mbstowcs(NULL, this->WindowName, 32000)+1];
|
|
mbstowcs(wname, this->WindowName, 32000);
|
|
SetWindowText(this->WindowId, wname);
|
|
delete [] wname;
|
|
#else
|
|
SetWindowText(this->WindowId, this->WindowName);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
int vtkWin32OpenGLRenderWindow::GetEventPending()
|
|
{
|
|
MSG msg;
|
|
if (PeekMessage(&msg, this->WindowId, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE))
|
|
{
|
|
if (msg.message == WM_MOUSEMOVE)
|
|
{
|
|
PeekMessage(&msg, this->WindowId, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE);
|
|
}
|
|
if ((msg.message == WM_LBUTTONDOWN) ||
|
|
(msg.message == WM_RBUTTONDOWN) ||
|
|
(msg.message == WM_MBUTTONDOWN) ||
|
|
(msg.message == WM_MOUSEWHEEL))
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool vtkWin32OpenGLRenderWindow::InitializeFromCurrentContext()
|
|
{
|
|
HGLRC currentContext = wglGetCurrentContext();
|
|
if (currentContext != NULL)
|
|
{
|
|
this->SetWindowId(WindowFromDC(wglGetCurrentDC()));
|
|
this->SetDeviceContext(wglGetCurrentDC());
|
|
this->SetContextId(currentContext);
|
|
this->OpenGLInit();
|
|
this->OwnContext = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
void vtkWin32OpenGLRenderWindow::MakeCurrent()
|
|
{
|
|
// Try to avoid doing anything (for performance).
|
|
HGLRC current = wglGetCurrentContext();
|
|
if (this->ContextId != current)
|
|
{
|
|
if (this->IsPicking && current)
|
|
{
|
|
vtkErrorMacro("Attempting to call MakeCurrent for a different window"
|
|
" than the one doing the picking, this can causes crashes"
|
|
" and/or bad pick results");
|
|
}
|
|
else
|
|
{
|
|
if (wglMakeCurrent(this->DeviceContext, this->ContextId) != TRUE)
|
|
{
|
|
LPVOID lpMsgBuf;
|
|
::FormatMessage(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL,
|
|
GetLastError(),
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
|
(LPTSTR) &lpMsgBuf,
|
|
0,
|
|
NULL
|
|
);
|
|
if (lpMsgBuf)
|
|
{
|
|
#ifdef UNICODE
|
|
wchar_t *wmsg = new wchar_t [mbstowcs(NULL, (const char*)lpMsgBuf, 32000)+1];
|
|
wchar_t *wtemp = new wchar_t [mbstowcs(NULL, "wglMakeCurrent failed in MakeCurrent(), error: ", 32000)+1];
|
|
mbstowcs(wmsg, (const char*)lpMsgBuf, 32000);
|
|
mbstowcs(wtemp, "wglMakeCurrent failed in MakeCurrent(), error: ", 32000);
|
|
vtkErrorMacro(<< wcscat(wtemp, wmsg));
|
|
delete [] wmsg;
|
|
delete [] wtemp;
|
|
#else
|
|
vtkErrorMacro("wglMakeCurrent failed in MakeCurrent(), error: "
|
|
<< (LPCTSTR)lpMsgBuf);
|
|
#endif
|
|
::LocalFree(lpMsgBuf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Description:
|
|
// Tells if this window is the current OpenGL context for the calling thread.
|
|
bool vtkWin32OpenGLRenderWindow::IsCurrent()
|
|
{
|
|
return this->ContextId != 0 && this->ContextId == wglGetCurrentContext();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
void AdjustWindowRectForBorders(HWND hwnd, DWORD style, const int x, const int y,
|
|
const int width, const int height, RECT &r)
|
|
{
|
|
if (!style && hwnd)
|
|
{
|
|
style = GetWindowLong(hwnd, GWL_STYLE);
|
|
}
|
|
r.left = x;
|
|
r.top = y;
|
|
r.right = r.left + width;
|
|
r.bottom = r.top + height;
|
|
BOOL result = AdjustWindowRect(&r, style, FALSE);
|
|
if (!result)
|
|
{
|
|
vtkGenericWarningMacro("AdjustWindowRect failed, error: "
|
|
<< GetLastError());
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
void vtkWin32OpenGLRenderWindow::SetSize(int x, int y)
|
|
{
|
|
static int resizing = 0;
|
|
if ((this->Size[0] != x) || (this->Size[1] != y))
|
|
{
|
|
this->Superclass::SetSize(x, y);
|
|
|
|
if (this->Interactor)
|
|
{
|
|
this->Interactor->SetSize(x, y);
|
|
}
|
|
|
|
if (this->OffScreenRendering)
|
|
{
|
|
if (!this->CreatingOffScreenWindow)
|
|
{
|
|
if (!resizing)
|
|
{
|
|
resizing = 1;
|
|
this->CleanUpOffScreenRendering();
|
|
this->CreateOffScreenWindow(x,y);
|
|
resizing = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
else if (this->Mapped)
|
|
{
|
|
if (!resizing)
|
|
{
|
|
resizing = 1;
|
|
|
|
if (this->ParentId)
|
|
{
|
|
SetWindowExtEx(this->DeviceContext, x, y, NULL);
|
|
SetViewportExtEx(this->DeviceContext, x, y, NULL);
|
|
SetWindowPos(this->WindowId, HWND_TOP, 0, 0,
|
|
x, y, SWP_NOMOVE | SWP_NOZORDER);
|
|
}
|
|
else
|
|
{
|
|
RECT r;
|
|
AdjustWindowRectForBorders(this->WindowId, 0, 0, 0, x, y, r);
|
|
SetWindowPos(this->WindowId, HWND_TOP, 0, 0,
|
|
r.right - r.left,
|
|
r.bottom - r.top,
|
|
SWP_NOMOVE | SWP_NOZORDER);
|
|
}
|
|
resizing = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::SetPosition(int x, int y)
|
|
{
|
|
static int resizing = 0;
|
|
|
|
if ((this->Position[0] != x) || (this->Position[1] != y))
|
|
{
|
|
this->Modified();
|
|
this->Position[0] = x;
|
|
this->Position[1] = y;
|
|
if (this->Mapped)
|
|
{
|
|
if (!resizing)
|
|
{
|
|
resizing = 1;
|
|
|
|
SetWindowPos(this->WindowId, HWND_TOP, x, y,
|
|
0, 0, SWP_NOSIZE | SWP_NOZORDER);
|
|
resizing = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// End the rendering process and display the image.
|
|
void vtkWin32OpenGLRenderWindow::Frame(void)
|
|
{
|
|
this->MakeCurrent();
|
|
if (!this->AbortRender && this->DoubleBuffer && this->SwapBuffers)
|
|
{
|
|
// If this check is not enforced, we crash in offscreen rendering
|
|
if (this->DeviceContext)
|
|
{
|
|
// use global scope to get Win32 API SwapBuffers and not be
|
|
// confused with this->SwapBuffers
|
|
::SwapBuffers(this->DeviceContext);
|
|
vtkDebugMacro(<< " SwapBuffers\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
glFlush();
|
|
}
|
|
}
|
|
|
|
int vtkWin32OpenGLRenderWindow::SupportsOpenGL()
|
|
{
|
|
MakeCurrent();
|
|
if (!this->DeviceContext)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int pixelFormat = GetPixelFormat(this->DeviceContext);
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
DescribePixelFormat(this->DeviceContext, pixelFormat,
|
|
sizeof(PIXELFORMATDESCRIPTOR), &pfd);
|
|
|
|
return (pfd.dwFlags & PFD_SUPPORT_OPENGL) ? 1 : 0;
|
|
}
|
|
|
|
|
|
int vtkWin32OpenGLRenderWindow::IsDirect()
|
|
{
|
|
MakeCurrent();
|
|
if (!this->DeviceContext)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int pixelFormat = GetPixelFormat(this->DeviceContext);
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
DescribePixelFormat(this->DeviceContext, pixelFormat,
|
|
sizeof(PIXELFORMATDESCRIPTOR), &pfd);
|
|
|
|
return (pfd.dwFlags & PFD_GENERIC_FORMAT) ? 0 : 1;
|
|
}
|
|
|
|
|
|
const char* vtkWin32OpenGLRenderWindow::ReportCapabilities()
|
|
{
|
|
MakeCurrent();
|
|
|
|
if (!this->DeviceContext)
|
|
{
|
|
return "no device context";
|
|
}
|
|
|
|
int pixelFormat = GetPixelFormat(this->DeviceContext);
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
DescribePixelFormat(this->DeviceContext, pixelFormat,
|
|
sizeof(PIXELFORMATDESCRIPTOR), &pfd);
|
|
|
|
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;
|
|
strm << "PixelFormat Descriptor:" << endl;
|
|
strm << "depth: " << static_cast<int>(pfd.cDepthBits) << endl;
|
|
if (pfd.cColorBits <= 8)
|
|
{
|
|
strm << "class: PseudoColor" << endl;
|
|
}
|
|
else
|
|
{
|
|
strm << "class: TrueColor" << endl;
|
|
}
|
|
strm << "buffer size: " << static_cast<int>(pfd.cColorBits) << endl;
|
|
strm << "level: " << static_cast<int>(pfd.bReserved) << endl;
|
|
if (pfd.iPixelType == PFD_TYPE_RGBA)
|
|
{
|
|
strm << "renderType: rgba" << endl;
|
|
}
|
|
else
|
|
{
|
|
strm <<"renderType: ci" << endl;
|
|
}
|
|
if (pfd.dwFlags & PFD_DOUBLEBUFFER) {
|
|
strm << "double buffer: True" << endl;
|
|
} else {
|
|
strm << "double buffer: False" << endl;
|
|
}
|
|
if (pfd.dwFlags & PFD_STEREO) {
|
|
strm << "stereo: True" << endl;
|
|
} else {
|
|
strm << "stereo: False" << endl;
|
|
}
|
|
if (pfd.dwFlags & PFD_GENERIC_FORMAT) {
|
|
strm << "hardware acceleration: False" << endl;
|
|
} else {
|
|
strm << "hardware acceleration: True" << endl;
|
|
}
|
|
strm << "rgba: redSize=" << static_cast<int>(pfd.cRedBits) <<
|
|
" greenSize=" << static_cast<int>(pfd.cGreenBits) <<
|
|
"blueSize=" << static_cast<int>(pfd.cBlueBits) <<
|
|
"alphaSize=" << static_cast<int>(pfd.cAlphaBits) << endl;
|
|
strm << "aux buffers: " << static_cast<int>(pfd.cAuxBuffers)<< endl;
|
|
strm << "depth size: " << static_cast<int>(pfd.cDepthBits) << endl;
|
|
strm << "stencil size: " << static_cast<int>(pfd.cStencilBits) << endl;
|
|
strm << "accum: redSize=" << static_cast<int>(pfd.cAccumRedBits) <<
|
|
" greenSize=" << static_cast<int>(pfd.cAccumGreenBits) <<
|
|
"blueSize=" << static_cast<int>(pfd.cAccumBlueBits) <<
|
|
"alphaSize=" << static_cast<int>(pfd.cAccumAlphaBits) << endl;
|
|
|
|
delete[] this->Capabilities;
|
|
|
|
size_t len = strm.str().length() + 1;
|
|
this->Capabilities = new char[len];
|
|
strncpy(this->Capabilities, strm.str().c_str(), len);
|
|
|
|
return this->Capabilities;
|
|
}
|
|
|
|
typedef bool (APIENTRY *wglChoosePixelFormatARBType)(HDC, const int*, const float*, unsigned int, int*, unsigned int*);
|
|
|
|
bool WGLisExtensionSupported(const char *extension)
|
|
{
|
|
const size_t extlen = strlen(extension);
|
|
const char *supported = NULL;
|
|
|
|
// Try To Use wglGetExtensionStringARB On Current DC, If Possible
|
|
PROC wglGetExtString = wglGetProcAddress("wglGetExtensionsStringARB");
|
|
|
|
if (wglGetExtString)
|
|
{
|
|
supported = ((char*(__stdcall*)(HDC))wglGetExtString)(wglGetCurrentDC());
|
|
}
|
|
|
|
// If That Failed, Try Standard Opengl Extensions String
|
|
if (supported == NULL)
|
|
{
|
|
supported = (char*)glGetString(GL_EXTENSIONS);
|
|
}
|
|
|
|
// If That Failed Too, Must Be No Extensions Supported
|
|
if (supported == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Begin Examination At Start Of String, Increment By 1 On False Match
|
|
for (const char* p = supported; ; p++)
|
|
{
|
|
// Advance p Up To The Next Possible Match
|
|
p = strstr(p, extension);
|
|
|
|
if (p == NULL)
|
|
{
|
|
return false; // No Match
|
|
}
|
|
|
|
// Make Sure That Match Is At The Start Of The String Or That
|
|
// The Previous Char Is A Space, Or Else We Could Accidentally
|
|
// Match "wglFunkywglExtension" With "wglExtension"
|
|
|
|
// Also, Make Sure That The Following Character Is Space Or NULL
|
|
// Or Else "wglExtensionTwo" Might Match "wglExtension"
|
|
if ((p==supported || p[-1]==' ') && (p[extlen]=='\0' || p[extlen]==' '))
|
|
{
|
|
return true; // Match
|
|
}
|
|
}
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::SetupPixelFormat(HDC hDC, DWORD dwFlags,
|
|
int debug, int bpp,
|
|
int zbpp)
|
|
{
|
|
// Create a dummy window, needed for calling wglGetProcAddress.
|
|
#ifdef UNICODE
|
|
HWND tempId = CreateWindow(L"vtkOpenGL", 0, 0, 0, 0, 1, 1, 0, 0, this->ApplicationInstance, 0);
|
|
#else
|
|
HWND tempId = CreateWindow("vtkOpenGL", 0, 0, 0, 0, 1, 1, 0, 0, this->ApplicationInstance, 0);
|
|
#endif
|
|
HDC tempDC = GetDC(tempId);
|
|
PIXELFORMATDESCRIPTOR tempPfd;
|
|
memset(&tempPfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
|
|
tempPfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
|
tempPfd.nVersion = 1;
|
|
tempPfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
|
|
tempPfd.iPixelType = PFD_TYPE_RGBA;
|
|
int tempPixelFormat = ChoosePixelFormat(tempDC, &tempPfd);
|
|
SetPixelFormat(tempDC, tempPixelFormat, &tempPfd);
|
|
HGLRC tempContext = wglCreateContext(tempDC);
|
|
wglMakeCurrent(tempDC, tempContext);
|
|
|
|
// First we try to use the newer wglChoosePixelFormatARB which enables
|
|
// features like multisamples.
|
|
int pixelFormat = 0;
|
|
wglChoosePixelFormatARBType wglChoosePixelFormatARB =
|
|
reinterpret_cast<wglChoosePixelFormatARBType>(wglGetProcAddress("wglChoosePixelFormatARB"));
|
|
if ((dwFlags & PFD_DRAW_TO_WINDOW) && wglChoosePixelFormatARB)
|
|
{
|
|
int attrib[] = {
|
|
vtkwgl::ACCELERATION_ARB, vtkwgl::FULL_ACCELERATION_ARB,
|
|
vtkwgl::SUPPORT_OPENGL_ARB, TRUE,
|
|
vtkwgl::DRAW_TO_WINDOW_ARB, TRUE,
|
|
vtkwgl::DOUBLE_BUFFER_ARB, TRUE,
|
|
vtkwgl::COLOR_BITS_ARB, bpp/4*3,
|
|
vtkwgl::DEPTH_BITS_ARB, zbpp/4*3,
|
|
vtkwgl::PIXEL_TYPE_ARB, vtkwgl::TYPE_RGBA_ARB,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
unsigned int n = 14;
|
|
if (this->AlphaBitPlanes)
|
|
{
|
|
attrib[n] = vtkwgl::ALPHA_BITS_ARB;
|
|
attrib[n+1] = bpp/4;
|
|
n += 2;
|
|
}
|
|
if (this->StencilCapable)
|
|
{
|
|
attrib[n] = vtkwgl::STENCIL_BITS_ARB;
|
|
attrib[n+1] = 8;
|
|
n += 2;
|
|
}
|
|
if (dwFlags & PFD_STEREO)
|
|
{
|
|
attrib[n] = vtkwgl::STEREO_ARB;
|
|
attrib[n+1] = TRUE;
|
|
n += 2;
|
|
}
|
|
unsigned int multiSampleAttributeIndex = 0;
|
|
if (this->MultiSamples > 1 && WGLisExtensionSupported("WGL_ARB_multisample"))
|
|
{
|
|
attrib[n] = vtkwgl::SAMPLE_BUFFERS_ARB;
|
|
attrib[n+1] = 1;
|
|
attrib[n+2] = vtkwgl::SAMPLES_ARB;
|
|
attrib[n+3] = this->MultiSamples;
|
|
multiSampleAttributeIndex = n+3;
|
|
n += 4;
|
|
}
|
|
unsigned int numFormats;
|
|
if (!wglChoosePixelFormatARB(hDC, attrib, 0, 1, &pixelFormat, &numFormats))
|
|
{
|
|
// If the requested number of multisamples does not work, try
|
|
// scaling down the number of multisamples a few times.
|
|
if (multiSampleAttributeIndex)
|
|
{
|
|
attrib[multiSampleAttributeIndex] /= 2;
|
|
if (!wglChoosePixelFormatARB(hDC, attrib, 0, 1, &pixelFormat, &numFormats))
|
|
{
|
|
attrib[multiSampleAttributeIndex] /= 2;
|
|
wglChoosePixelFormatARB(hDC, attrib, 0, 1, &pixelFormat, &numFormats);
|
|
}
|
|
}
|
|
}
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
DescribePixelFormat(hDC, pixelFormat, sizeof(pfd), &pfd);
|
|
if (!SetPixelFormat(hDC, pixelFormat, &pfd))
|
|
{
|
|
pixelFormat = 0;
|
|
}
|
|
}
|
|
|
|
// Delete the dummy window
|
|
wglMakeCurrent(tempDC, 0);
|
|
wglDeleteContext(tempContext);
|
|
ReleaseDC(tempId, tempDC);
|
|
::DestroyWindow(tempId); // windows api
|
|
|
|
// If we got a valid pixel format in the process, we are done.
|
|
// Otherwise, we use the old approach of using ChoosePixelFormat.
|
|
if (pixelFormat)
|
|
{
|
|
return;
|
|
}
|
|
|
|
BYTE bpp_byte = static_cast<BYTE>(bpp);
|
|
BYTE zbpp_byte = static_cast<BYTE>(zbpp);
|
|
PIXELFORMATDESCRIPTOR pfd = {
|
|
sizeof(PIXELFORMATDESCRIPTOR), /* size */
|
|
1, /* version */
|
|
dwFlags , /* support double-buffering */
|
|
PFD_TYPE_RGBA, /* color type */
|
|
bpp_byte, /* preferred color depth */
|
|
0, 0, 0, 0, 0, 0, /* color bits (ignored) */
|
|
static_cast<BYTE>(this->AlphaBitPlanes ? bpp/4 : 0), /* no alpha buffer */
|
|
0, /* alpha bits (ignored) */
|
|
0, /* no accumulation buffer */
|
|
0, 0, 0, 0, /* accum bits (ignored) */
|
|
zbpp_byte, /* depth buffer */
|
|
static_cast<BYTE>(this->StencilCapable), /* stencil buffer */
|
|
0, /* no auxiliary buffers */
|
|
PFD_MAIN_PLANE, /* main layer */
|
|
0, /* reserved */
|
|
0, 0, 0, /* no layer, visible, damage masks */
|
|
};
|
|
// Only try to set pixel format if we do not currently have one
|
|
int currentPixelFormat = GetPixelFormat(hDC);
|
|
// if there is a current pixel format, then make sure it
|
|
// supports OpenGL
|
|
if (currentPixelFormat != 0)
|
|
{
|
|
DescribePixelFormat(hDC, currentPixelFormat, sizeof(pfd), &pfd);
|
|
if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL))
|
|
{
|
|
#ifdef UNICODE
|
|
MessageBox(WindowFromDC(hDC),
|
|
L"Invalid pixel format, no OpenGL support",
|
|
L"Error",
|
|
MB_ICONERROR | MB_OK);
|
|
#else
|
|
MessageBox(WindowFromDC(hDC),
|
|
"Invalid pixel format, no OpenGL support",
|
|
"Error",
|
|
MB_ICONERROR | MB_OK);
|
|
#endif
|
|
if (this->HasObserver(vtkCommand::ExitEvent))
|
|
{
|
|
this->InvokeEvent(vtkCommand::ExitEvent, NULL);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// hDC has no current PixelFormat, so
|
|
pixelFormat = ChoosePixelFormat(hDC, &pfd);
|
|
if (pixelFormat == 0)
|
|
{
|
|
#ifdef UNICODE
|
|
MessageBox(WindowFromDC(hDC), L"ChoosePixelFormat failed.", L"Error",
|
|
MB_ICONERROR | MB_OK);
|
|
#else
|
|
MessageBox(WindowFromDC(hDC), "ChoosePixelFormat failed.", "Error",
|
|
MB_ICONERROR | MB_OK);
|
|
#endif
|
|
if (this->HasObserver(vtkCommand::ExitEvent))
|
|
{
|
|
this->InvokeEvent(vtkCommand::ExitEvent, NULL);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
exit(1);
|
|
}
|
|
}
|
|
DescribePixelFormat(hDC, pixelFormat, sizeof(pfd), &pfd);
|
|
if (SetPixelFormat(hDC, pixelFormat, &pfd) != TRUE)
|
|
{
|
|
// int err = GetLastError();
|
|
#ifdef UNICODE
|
|
MessageBox(WindowFromDC(hDC), L"SetPixelFormat failed.", L"Error",
|
|
MB_ICONERROR | MB_OK);
|
|
#else
|
|
MessageBox(WindowFromDC(hDC), "SetPixelFormat failed.", "Error",
|
|
MB_ICONERROR | MB_OK);
|
|
#endif
|
|
if (this->HasObserver(vtkCommand::ExitEvent))
|
|
{
|
|
this->InvokeEvent(vtkCommand::ExitEvent, NULL);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
if (debug && (dwFlags & PFD_STEREO) && !(pfd.dwFlags & PFD_STEREO))
|
|
{
|
|
vtkGenericWarningMacro("No Stereo Available!");
|
|
this->StereoCapableWindow = 0;
|
|
}
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::SetupPalette(HDC hDC)
|
|
{
|
|
int pixelFormat = GetPixelFormat(hDC);
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
DescribePixelFormat(hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
|
|
|
|
int paletteSize;
|
|
if (pfd.dwFlags & PFD_NEED_PALETTE)
|
|
{
|
|
paletteSize = 1 << pfd.cColorBits;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
LOGPALETTE* pPal = (LOGPALETTE*)
|
|
malloc(sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY));
|
|
pPal->palVersion = 0x300;
|
|
pPal->palNumEntries = paletteSize;
|
|
|
|
// build a simple RGB color palette
|
|
int redMask = (1 << pfd.cRedBits) - 1;
|
|
int greenMask = (1 << pfd.cGreenBits) - 1;
|
|
int blueMask = (1 << pfd.cBlueBits) - 1;
|
|
|
|
for (int i = 0; i < paletteSize; ++i)
|
|
{
|
|
pPal->palPalEntry[i].peRed =
|
|
(((i >> pfd.cRedShift) & redMask) * 255) / redMask;
|
|
pPal->palPalEntry[i].peGreen =
|
|
(((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask;
|
|
pPal->palPalEntry[i].peBlue =
|
|
(((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask;
|
|
pPal->palPalEntry[i].peFlags = 0;
|
|
}
|
|
|
|
this->Palette = CreatePalette(pPal);
|
|
free(pPal);
|
|
|
|
if (this->Palette)
|
|
{
|
|
this->OldPalette = SelectPalette(hDC, this->Palette, FALSE);
|
|
RealizePalette(hDC);
|
|
}
|
|
}
|
|
|
|
|
|
LRESULT vtkWin32OpenGLRenderWindow::MessageProc(HWND hWnd, UINT message,
|
|
WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (message)
|
|
{
|
|
case WM_CREATE:
|
|
{
|
|
// nothing to be done here, opengl is initilized after the call to
|
|
// create now
|
|
return 0;
|
|
}
|
|
case WM_DESTROY:
|
|
this->Clean();
|
|
if (this->DeviceContext)
|
|
{
|
|
ReleaseDC(this->WindowId, this->DeviceContext);
|
|
this->DeviceContext = NULL;
|
|
this->WindowId = NULL;
|
|
}
|
|
return 0;
|
|
case WM_SIZE:
|
|
// track window size changes
|
|
if (this->ContextId)
|
|
{
|
|
this->SetSize((int)LOWORD(lParam),(int)HIWORD(lParam));
|
|
return 0;
|
|
}
|
|
case WM_PALETTECHANGED:
|
|
// realize palette if this is *not* the current window
|
|
if (this->ContextId && this->Palette && (HWND) wParam != hWnd)
|
|
{
|
|
SelectPalette(this->DeviceContext, this->OldPalette, FALSE);
|
|
UnrealizeObject(this->Palette);
|
|
this->OldPalette = SelectPalette(this->DeviceContext,
|
|
this->Palette, FALSE);
|
|
RealizePalette(this->DeviceContext);
|
|
this->Render();
|
|
}
|
|
break;
|
|
case WM_QUERYNEWPALETTE:
|
|
// realize palette if this is the current window
|
|
if (this->ContextId && this->Palette)
|
|
{
|
|
SelectPalette(this->DeviceContext, this->OldPalette, FALSE);
|
|
UnrealizeObject(this->Palette);
|
|
this->OldPalette = SelectPalette(this->DeviceContext,
|
|
this->Palette, FALSE);
|
|
RealizePalette(this->DeviceContext);
|
|
this->Render();
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case WM_PAINT:
|
|
{
|
|
PAINTSTRUCT ps;
|
|
BeginPaint(hWnd, &ps);
|
|
if (this->ContextId)
|
|
{
|
|
this->Render();
|
|
}
|
|
EndPaint(hWnd, &ps);
|
|
return 0;
|
|
}
|
|
break;
|
|
case WM_ERASEBKGND:
|
|
return TRUE;
|
|
case WM_SETCURSOR:
|
|
if (HTCLIENT == LOWORD(lParam))
|
|
{
|
|
this->SetCurrentCursor(this->GetCurrentCursor());
|
|
return TRUE;
|
|
}
|
|
break;
|
|
default:
|
|
this->InvokeEvent(vtkCommand::RenderWindowMessageEvent, &message);
|
|
break;
|
|
}
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::InitializeApplication()
|
|
{
|
|
// get the application instance if we don't have one already
|
|
if (!this->ApplicationInstance)
|
|
{
|
|
// if we have a parent window get the app instance from it
|
|
if (this->ParentId)
|
|
{
|
|
this->ApplicationInstance =
|
|
(HINSTANCE)vtkGetWindowLong(this->ParentId, vtkGWL_HINSTANCE);
|
|
}
|
|
else
|
|
{
|
|
this->ApplicationInstance = GetModuleHandle(NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::CreateAWindow()
|
|
{
|
|
WNDCLASS wndClass;
|
|
// has the class been registered ?
|
|
#ifdef UNICODE
|
|
if (!GetClassInfo(this->ApplicationInstance, L"vtkOpenGL", &wndClass))
|
|
#else
|
|
if (!GetClassInfo(this->ApplicationInstance, "vtkOpenGL", &wndClass))
|
|
#endif
|
|
{
|
|
wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
|
|
wndClass.lpfnWndProc = vtkWin32OpenGLRenderWindow::WndProc;
|
|
wndClass.cbClsExtra = 0;
|
|
wndClass.hInstance = this->ApplicationInstance;
|
|
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
|
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
|
wndClass.lpszMenuName = NULL;
|
|
#ifdef UNICODE
|
|
wndClass.lpszClassName = L"vtkOpenGL";
|
|
#else
|
|
wndClass.lpszClassName = "vtkOpenGL";
|
|
#endif
|
|
// vtk doesn't use the first extra vtkLONG's worth of bytes,
|
|
// but app writers may want them, so we provide them. VTK
|
|
// does use the second vtkLONG's worth of bytes of extra space.
|
|
wndClass.cbWndExtra = 2 * sizeof(vtkLONG);
|
|
RegisterClass(&wndClass);
|
|
}
|
|
|
|
if (this->WindowIdReferenceCount == 0)
|
|
{
|
|
if (!this->WindowId)
|
|
{
|
|
this->DeviceContext = 0;
|
|
|
|
// Check if the user has changed the window name
|
|
// ("Visualization toolkit - OpenGL" is vtkOpenGLRenderWindow's default)
|
|
if (!strcmp(this->GetWindowName(), "Visualization Toolkit - OpenGL"))
|
|
{
|
|
static int count = 1;
|
|
std::stringstream windowName;
|
|
windowName << "Visualization Toolkit - Win32OpenGL #" << count++;
|
|
this->SetWindowName(windowName.str().c_str());
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
wchar_t *wname = new wchar_t [mbstowcs(NULL, this->WindowName, 32000)+1];
|
|
mbstowcs(wname, this->WindowName, 32000);
|
|
#endif
|
|
int x = ((this->Position[0] >= 0) ? this->Position[0] : 5);
|
|
int y = ((this->Position[1] >= 0) ? this->Position[1] : 5);
|
|
int height = ((this->Size[1] > 0) ? this->Size[1] : 300);
|
|
int width = ((this->Size[0] > 0) ? this->Size[0] : 300);
|
|
|
|
/* create window */
|
|
if (this->ParentId)
|
|
{
|
|
#ifdef UNICODE
|
|
this->WindowId = CreateWindow(
|
|
L"vtkOpenGL", wname,
|
|
WS_CHILD | WS_CLIPCHILDREN /*| WS_CLIPSIBLINGS*/,
|
|
x, y, width, height,
|
|
this->ParentId, NULL, this->ApplicationInstance, NULL);
|
|
#else
|
|
this->WindowId = CreateWindow(
|
|
"vtkOpenGL", this->WindowName,
|
|
WS_CHILD | WS_CLIPCHILDREN /*| WS_CLIPSIBLINGS*/,
|
|
x, y, width, height,
|
|
this->ParentId, NULL, this->ApplicationInstance, NULL);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
DWORD style = WS_CLIPCHILDREN /*| WS_CLIPSIBLINGS*/;
|
|
if (this->Borders)
|
|
{
|
|
style |= WS_OVERLAPPEDWINDOW;
|
|
}
|
|
else
|
|
{
|
|
style |= WS_POPUP;
|
|
}
|
|
RECT r;
|
|
AdjustWindowRectForBorders(0, style, x, y, width, height, r);
|
|
#ifdef UNICODE
|
|
this->WindowId = CreateWindow(
|
|
L"vtkOpenGL", wname, style,
|
|
x, y, r.right-r.left, r.bottom-r.top,
|
|
NULL, NULL, this->ApplicationInstance, NULL);
|
|
#else
|
|
this->WindowId = CreateWindow(
|
|
"vtkOpenGL", this->WindowName, style,
|
|
x, y, r.right-r.left, r.bottom-r.top,
|
|
NULL, NULL, this->ApplicationInstance, NULL);
|
|
#endif
|
|
}
|
|
#ifdef UNICODE
|
|
delete [] wname;
|
|
#endif
|
|
|
|
if (!this->WindowId)
|
|
{
|
|
vtkErrorMacro("Could not create window, error: " << GetLastError());
|
|
return;
|
|
}
|
|
// extract the create info
|
|
|
|
// display window
|
|
if (!this->OffScreenRendering)
|
|
{
|
|
ShowWindow(this->WindowId, SW_SHOW);
|
|
}
|
|
//UpdateWindow(this->WindowId);
|
|
this->OwnWindow = 1;
|
|
vtkSetWindowLong(this->WindowId, sizeof(vtkLONG), (intptr_t)this);
|
|
}
|
|
if (!this->DeviceContext)
|
|
{
|
|
this->DeviceContext = GetDC(this->WindowId);
|
|
}
|
|
DWORD flags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
|
|
if (this->StereoCapableWindow)
|
|
{
|
|
flags |= PFD_STEREO;
|
|
}
|
|
this->SetupPixelFormat(this->DeviceContext, flags, this->GetDebug(), 32, 32);
|
|
this->SetupPalette(this->DeviceContext);
|
|
this->ContextId = wglCreateContext(this->DeviceContext);
|
|
if (this->ContextId == NULL)
|
|
{
|
|
vtkErrorMacro("wglCreateContext failed in CreateAWindow(), error: " << GetLastError());
|
|
}
|
|
this->MakeCurrent();
|
|
|
|
// wipe out any existing display lists
|
|
vtkRenderer* ren;
|
|
vtkCollectionSimpleIterator rsit;
|
|
for (this->Renderers->InitTraversal(rsit);
|
|
(ren = this->Renderers->GetNextRenderer(rsit));)
|
|
{
|
|
ren->SetRenderWindow(0);
|
|
ren->SetRenderWindow(this);
|
|
}
|
|
this->OpenGLInit();
|
|
this->Mapped = 1;
|
|
this->WindowIdReferenceCount = 1;
|
|
}
|
|
else
|
|
{
|
|
++this->WindowIdReferenceCount;
|
|
}
|
|
}
|
|
|
|
// Initialize the window for rendering.
|
|
void vtkWin32OpenGLRenderWindow::WindowInitialize()
|
|
{
|
|
// create our own window if not already set
|
|
this->OwnWindow = 0;
|
|
if (!this->MFChandledWindow)
|
|
{
|
|
this->InitializeApplication();
|
|
this->CreateAWindow();
|
|
}
|
|
else
|
|
{
|
|
this->MakeCurrent();
|
|
this->OpenGLInit();
|
|
}
|
|
}
|
|
|
|
// Initialize the rendering window.
|
|
void vtkWin32OpenGLRenderWindow::Initialize (void)
|
|
{
|
|
// make sure we havent already been initialized
|
|
if (!this->OffScreenRendering && !this->ContextId)
|
|
{
|
|
this->WindowInitialize();
|
|
}
|
|
else
|
|
{
|
|
if (this->OffScreenRendering && !(this->ContextId ||
|
|
this->OffScreenUseFrameBuffer))
|
|
{
|
|
this->InitializeApplication();
|
|
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 vtkWin32OpenGLRenderWindow::Finalize(void)
|
|
{
|
|
if (this->CursorHidden)
|
|
{
|
|
this->ShowCursor();
|
|
}
|
|
|
|
if (this->OffScreenRendering)
|
|
{
|
|
this->CleanUpOffScreenRendering();
|
|
}
|
|
this->DestroyWindow();
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::DestroyWindow()
|
|
{
|
|
if (this->WindowIdReferenceCount > 0)
|
|
{
|
|
--this->WindowIdReferenceCount;
|
|
if (this->WindowIdReferenceCount == 0)
|
|
{
|
|
this->Clean();
|
|
if (this->WindowId)
|
|
{
|
|
ReleaseDC(this->WindowId, this->DeviceContext);
|
|
// can't set WindowId=NULL, needed for DestroyWindow
|
|
this->DeviceContext = NULL;
|
|
|
|
// clear the extra data before calling destroy
|
|
vtkSetWindowLong(this->WindowId, sizeof(vtkLONG), (vtkLONG)0);
|
|
if (this->OwnWindow)
|
|
{
|
|
::DestroyWindow(this->WindowId); // windows api
|
|
this->WindowId = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get the current size of the window.
|
|
int *vtkWin32OpenGLRenderWindow::GetSize(void)
|
|
{
|
|
// if we aren't mapped then just return the ivar
|
|
if (this->Mapped)
|
|
{
|
|
RECT rect;
|
|
|
|
// Find the current window size
|
|
if (GetClientRect(this->WindowId, &rect))
|
|
{
|
|
this->Size[0] = rect.right;
|
|
this->Size[1] = rect.bottom;
|
|
}
|
|
else
|
|
{
|
|
this->Size[0] = 0;
|
|
this->Size[1] = 0;
|
|
}
|
|
}
|
|
|
|
return this->vtkOpenGLRenderWindow::GetSize();
|
|
}
|
|
|
|
// Get the size of the whole screen.
|
|
int *vtkWin32OpenGLRenderWindow::GetScreenSize(void)
|
|
{
|
|
if (this->OffScreenRendering)
|
|
{
|
|
return this->Size;
|
|
}
|
|
|
|
HDC hDC = ::GetDC(NULL);
|
|
if (hDC)
|
|
{
|
|
// This technique yields the screen size of the primary monitor
|
|
// only in a multi-monitor configuration...
|
|
this->Size[0] = ::GetDeviceCaps(hDC, HORZRES);
|
|
this->Size[1] = ::GetDeviceCaps(hDC, VERTRES);
|
|
::ReleaseDC(NULL, hDC);
|
|
}
|
|
else
|
|
{
|
|
// This technique gets the "work area" (the whole screen except
|
|
// for the bit covered by the Windows task bar) -- use it as a
|
|
// fallback if there's an error calling GetDC.
|
|
RECT rect;
|
|
SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
|
|
|
|
this->Size[0] = rect.right - rect.left;
|
|
this->Size[1] = rect.bottom - rect.top;
|
|
}
|
|
|
|
return this->Size;
|
|
}
|
|
|
|
// Get the position in screen coordinates of the window.
|
|
int *vtkWin32OpenGLRenderWindow::GetPosition(void)
|
|
{
|
|
return this->Position;
|
|
}
|
|
|
|
// Change the window to fill the entire screen.
|
|
void vtkWin32OpenGLRenderWindow::SetFullScreen(int arg)
|
|
{
|
|
if (this->FullScreen == arg)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!this->Mapped)
|
|
{
|
|
this->PrefFullScreen();
|
|
return;
|
|
}
|
|
|
|
// set the mode
|
|
this->FullScreen = arg;
|
|
if (this->FullScreen <= 0)
|
|
{
|
|
this->Position[0] = this->OldScreen[0];
|
|
this->Position[1] = this->OldScreen[1];
|
|
this->Size[0] = this->OldScreen[2];
|
|
this->Size[1] = this->OldScreen[3];
|
|
this->Borders = this->OldScreen[4];
|
|
}
|
|
else
|
|
{
|
|
// if window already up get its values
|
|
if (this->WindowId)
|
|
{
|
|
int *temp = this->GetPosition();
|
|
this->OldScreen[0] = temp[0];
|
|
this->OldScreen[1] = temp[1];
|
|
this->OldScreen[4] = this->Borders;
|
|
this->PrefFullScreen();
|
|
}
|
|
}
|
|
|
|
// remap the window
|
|
this->WindowRemap();
|
|
|
|
this->Modified();
|
|
}
|
|
|
|
//
|
|
// 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 vtkWin32OpenGLRenderWindow::SetStereoCapableWindow(int capable)
|
|
{
|
|
if (this->ContextId == 0)
|
|
{
|
|
vtkRenderWindow::SetStereoCapableWindow(capable);
|
|
}
|
|
else
|
|
{
|
|
vtkWarningMacro(<< "Requesting a StereoCapableWindow must be performed "
|
|
<< "before the window is realized, i.e. before a render.");
|
|
}
|
|
}
|
|
|
|
|
|
// Set the preferred window size to full screen.
|
|
void vtkWin32OpenGLRenderWindow::PrefFullScreen()
|
|
{
|
|
int *size = this->GetScreenSize();
|
|
|
|
// don't show borders
|
|
this->Borders = 0;
|
|
|
|
RECT r;
|
|
AdjustWindowRectForBorders(this->WindowId, 0, 0, 0, size[0], size[1], r);
|
|
|
|
// use full screen
|
|
this->Position[0] = 0;
|
|
this->Position[1] = 0;
|
|
this->Size[0] = r.right - r.left;
|
|
this->Size[1] = r.bottom - r.top;
|
|
}
|
|
|
|
// Remap the window.
|
|
void vtkWin32OpenGLRenderWindow::WindowRemap()
|
|
{
|
|
// close everything down
|
|
this->Finalize();
|
|
|
|
// set the default windowid
|
|
this->WindowId = this->NextWindowId;
|
|
this->NextWindowId = 0;
|
|
|
|
// and set it up!
|
|
this->Initialize();
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
os << indent << "ContextId: " << this->ContextId << "\n";
|
|
os << indent << "Next Window Id: " << this->NextWindowId << "\n";
|
|
os << indent << "Window Id: " << this->WindowId << "\n";
|
|
}
|
|
|
|
// Get the window id.
|
|
HWND vtkWin32OpenGLRenderWindow::GetWindowId()
|
|
{
|
|
vtkDebugMacro(<< "Returning WindowId of " << this->WindowId << "\n");
|
|
|
|
return this->WindowId;
|
|
}
|
|
|
|
// Set the window id to a pre-existing window.
|
|
void vtkWin32OpenGLRenderWindow::SetWindowId(HWND arg)
|
|
{
|
|
vtkDebugMacro(<< "Setting WindowId to " << arg << "\n");
|
|
|
|
if (arg != this->WindowId)
|
|
{
|
|
this->WindowId = arg;
|
|
if (this->ContextId)
|
|
{
|
|
wglDeleteContext(this->ContextId);
|
|
}
|
|
this->ContextId = 0;
|
|
this->DeviceContext = 0;
|
|
}
|
|
}
|
|
|
|
// Set this RenderWindow's X window id to a pre-existing window.
|
|
void vtkWin32OpenGLRenderWindow::SetWindowInfo(char *info)
|
|
{
|
|
size_t tmp;
|
|
sscanf(info, vtkTypeTraits<size_t>::ParseFormat(), &tmp);
|
|
|
|
this->WindowId = reinterpret_cast<HWND>(tmp);
|
|
vtkDebugMacro(<< "Setting WindowId to " << this->WindowId << "\n");
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::SetNextWindowInfo(char *info)
|
|
{
|
|
size_t tmp;
|
|
sscanf(info, vtkTypeTraits<size_t>::ParseFormat(), &tmp);
|
|
|
|
this->SetNextWindowId(reinterpret_cast<HWND>(tmp));
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::SetDisplayId(void * arg)
|
|
{
|
|
this->DeviceContext = (HDC)arg;
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::SetContextId(HGLRC arg)
|
|
{
|
|
this->ContextId = arg;
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::SetDeviceContext(HDC arg)
|
|
{
|
|
this->DeviceContext = arg;
|
|
this->MFChandledWindow = TRUE;
|
|
}
|
|
|
|
// Sets the HWND id of the window that WILL BE created.
|
|
void vtkWin32OpenGLRenderWindow::SetParentInfo(char *info)
|
|
{
|
|
size_t tmp;
|
|
sscanf(info, vtkTypeTraits<size_t>::ParseFormat(), &tmp);
|
|
|
|
this->ParentId = reinterpret_cast<HWND>(tmp);
|
|
vtkDebugMacro(<< "Setting ParentId to " << this->ParentId << "\n");
|
|
}
|
|
|
|
// Set the window id to a pre-existing window.
|
|
void vtkWin32OpenGLRenderWindow::SetParentId(HWND arg)
|
|
{
|
|
vtkDebugMacro(<< "Setting ParentId to " << arg << "\n");
|
|
|
|
this->ParentId = arg;
|
|
}
|
|
|
|
// Set the window id of the new window once a WindowRemap is done.
|
|
void vtkWin32OpenGLRenderWindow::SetNextWindowId(HWND arg)
|
|
{
|
|
vtkDebugMacro(<< "Setting NextWindowId to " << arg << "\n");
|
|
|
|
this->NextWindowId = arg;
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::SetNextWindowId(void *arg)
|
|
{
|
|
this->SetNextWindowId((HWND)arg);
|
|
}
|
|
|
|
// Begin the rendering process.
|
|
void vtkWin32OpenGLRenderWindow::Start(void)
|
|
{
|
|
// if the renderer has not been initialized, do so now
|
|
if (!this->ContextId)
|
|
{
|
|
this->Initialize();
|
|
}
|
|
|
|
// set the current window
|
|
this->MakeCurrent();
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::SetOffScreenRendering(int offscreen)
|
|
{
|
|
if (offscreen == this->OffScreenRendering)
|
|
{
|
|
return;
|
|
}
|
|
|
|
this->vtkRenderWindow::SetOffScreenRendering(offscreen);
|
|
|
|
if (offscreen)
|
|
{
|
|
int size[2];
|
|
size[0] = (this->Size[0] > 0) ? this->Size[0] : 300;
|
|
size[1] = (this->Size[1] > 0) ? this->Size[1] : 300;
|
|
this->SaveScreenRendering();
|
|
this->CreateOffScreenWindow(size[0], size[1]);
|
|
}
|
|
else
|
|
{
|
|
this->CleanUpOffScreenRendering();
|
|
if (!this->WindowId)
|
|
{
|
|
this->WindowInitialize();
|
|
this->OpenGLInit();
|
|
if (this->Interactor)
|
|
{
|
|
this->Interactor->ReInitialize();
|
|
}
|
|
this->DoubleBuffer = 1;
|
|
}
|
|
else
|
|
{
|
|
this->ResumeScreenRendering();
|
|
}
|
|
}
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::SaveScreenRendering()
|
|
{
|
|
this->ScreenMapped = this->Mapped;
|
|
this->ScreenWindowSize[0] = this->Size[0];
|
|
this->ScreenWindowSize[1] = this->Size[1];
|
|
this->ScreenDeviceContext = this->DeviceContext;
|
|
this->ScreenDoubleBuffer = this->DoubleBuffer;
|
|
this->ScreenContextId = this->ContextId;
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::CreateOffScreenWindow(int width,
|
|
int height)
|
|
{
|
|
int status = this->CreatingOffScreenWindow;
|
|
this->CreatingOffScreenWindow = 1;
|
|
if (!this->CreateHardwareOffScreenWindow(width, height))
|
|
{
|
|
#ifdef UNICODE
|
|
HDC dc = CreateDC(L"DISPLAY", 0, 0, 0);
|
|
#else
|
|
HDC dc = CreateDC("DISPLAY", 0, 0, 0);
|
|
#endif
|
|
this->CreateOffScreenDC(width, height, dc);
|
|
DeleteDC(dc);
|
|
}
|
|
else
|
|
{
|
|
this->Mapped = 0;
|
|
}
|
|
this->CreatingOffScreenWindow = status;
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::CreateOffScreenDC(int xsize, int ysize,
|
|
HDC aHdc)
|
|
{
|
|
int dataWidth = ((xsize * 3 + 3) / 4) * 4;
|
|
|
|
this->MemoryDataHeader.bmiHeader.biSize = 40;
|
|
this->MemoryDataHeader.bmiHeader.biWidth = xsize;
|
|
this->MemoryDataHeader.bmiHeader.biHeight = ysize;
|
|
this->MemoryDataHeader.bmiHeader.biPlanes = 1;
|
|
this->MemoryDataHeader.bmiHeader.biBitCount = 24;
|
|
this->MemoryDataHeader.bmiHeader.biCompression = BI_RGB;
|
|
this->MemoryDataHeader.bmiHeader.biClrUsed = 0;
|
|
this->MemoryDataHeader.bmiHeader.biClrImportant = 0;
|
|
this->MemoryDataHeader.bmiHeader.biSizeImage = dataWidth * ysize;
|
|
this->MemoryDataHeader.bmiHeader.biXPelsPerMeter = 10000;
|
|
this->MemoryDataHeader.bmiHeader.biYPelsPerMeter = 10000;
|
|
|
|
HBITMAP dib = CreateDIBSection(aHdc,
|
|
&this->MemoryDataHeader, DIB_RGB_COLORS,
|
|
(void **)(&(this->MemoryData)), NULL, 0);
|
|
SIZE oldSize;
|
|
SetBitmapDimensionEx(dib, xsize, ysize, &oldSize);
|
|
// try using a DIBsection
|
|
this->CreateOffScreenDC(dib, aHdc);
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::CreateOffScreenDC(HBITMAP hbmp, HDC aHdc)
|
|
{
|
|
BITMAP bm;
|
|
GetObject(hbmp, sizeof(BITMAP), &bm);
|
|
|
|
// Renderers will need to redraw anything cached in display lists
|
|
vtkRenderer *ren;
|
|
vtkCollectionSimpleIterator rsit;
|
|
this->Renderers->InitTraversal(rsit);
|
|
while ((ren = this->Renderers->GetNextRenderer(rsit)))
|
|
{
|
|
ren->SetRenderWindow(NULL);
|
|
ren->SetRenderWindow(this);
|
|
}
|
|
|
|
this->MemoryBuffer = hbmp;
|
|
|
|
// Create a compatible device context
|
|
this->MemoryHdc = (HDC)CreateCompatibleDC(aHdc);
|
|
|
|
// Put the bitmap into the device context
|
|
SelectObject(this->MemoryHdc, this->MemoryBuffer);
|
|
|
|
// adjust settings for renderwindow
|
|
this->Mapped = 0;
|
|
this->Size[0] = bm.bmWidth;
|
|
this->Size[1] = bm.bmHeight;
|
|
|
|
this->DeviceContext = this->MemoryHdc;
|
|
this->DoubleBuffer = 0;
|
|
this->SetupPixelFormat(this->DeviceContext,
|
|
PFD_SUPPORT_OPENGL | PFD_SUPPORT_GDI |
|
|
PFD_DRAW_TO_BITMAP, this->GetDebug(), 24, 32);
|
|
this->SetupPalette(this->DeviceContext);
|
|
|
|
this->ContextId = wglCreateContext(this->DeviceContext);
|
|
if (this->ContextId == NULL)
|
|
{
|
|
vtkErrorMacro("wglCreateContext failed in CreateOffScreenDC(), error: " << GetLastError());
|
|
}
|
|
this->MakeCurrent();
|
|
this->OpenGLInit();
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::SetupMemoryRendering(int xsize, int ysize,
|
|
HDC aHdc)
|
|
{
|
|
// save the current state
|
|
this->ScreenMapped = this->Mapped;
|
|
this->ScreenWindowSize[0] = this->Size[0];
|
|
this->ScreenWindowSize[1] = this->Size[1];
|
|
this->ScreenDeviceContext = this->DeviceContext;
|
|
this->ScreenDoubleBuffer = this->DoubleBuffer;
|
|
this->ScreenContextId = this->ContextId;
|
|
|
|
this->CreateOffScreenDC(xsize, ysize, aHdc);
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::SetupMemoryRendering(HBITMAP hbmp)
|
|
{
|
|
#ifdef UNICODE
|
|
HDC dc = CreateDC(L"DISPLAY", 0, 0, 0);
|
|
#else
|
|
HDC dc = CreateDC("DISPLAY", 0, 0, 0);
|
|
#endif
|
|
|
|
// save the current state
|
|
this->ScreenMapped = this->Mapped;
|
|
this->ScreenWindowSize[0] = this->Size[0];
|
|
this->ScreenWindowSize[1] = this->Size[1];
|
|
this->ScreenDeviceContext = this->DeviceContext;
|
|
this->ScreenDoubleBuffer = this->DoubleBuffer;
|
|
this->ScreenContextId = this->ContextId;
|
|
|
|
this->CreateOffScreenDC(hbmp, dc);
|
|
DeleteDC(dc);
|
|
}
|
|
|
|
HDC vtkWin32OpenGLRenderWindow::GetMemoryDC()
|
|
{
|
|
return this->MemoryHdc;
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::CleanUpOffScreenRendering(void)
|
|
{
|
|
if (this->OffScreenUseFrameBuffer)
|
|
{
|
|
this->DestroyHardwareOffScreenWindow();
|
|
}
|
|
else
|
|
{
|
|
if (!this->MemoryHdc)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GdiFlush();
|
|
|
|
// we need to release resources
|
|
this->CleanUpRenderers();
|
|
DeleteDC(this->MemoryHdc);
|
|
this->MemoryHdc = (HDC)0;
|
|
DeleteObject(this->MemoryBuffer);
|
|
if (wglDeleteContext(this->ContextId) != TRUE)
|
|
{
|
|
vtkErrorMacro("wglDeleteContext failed in CleanUpOffScreenRendering(), error: " << GetLastError());
|
|
}
|
|
this->ContextId = 0;
|
|
}
|
|
}
|
|
|
|
void vtkWin32OpenGLRenderWindow::ResumeScreenRendering(void)
|
|
{
|
|
// release OpenGL graphics resources before switch back to on-screen.
|
|
if (this->ContextId!=0)
|
|
{
|
|
this->MakeCurrent();
|
|
// Renderers will need to redraw anything cached in display lists
|
|
vtkRenderer *ren;
|
|
vtkCollectionSimpleIterator rsit;
|
|
this->Renderers->InitTraversal(rsit);
|
|
while ((ren = this->Renderers->GetNextRenderer(rsit)))
|
|
{
|
|
ren->SetRenderWindow(NULL);
|
|
ren->SetRenderWindow(this);
|
|
}
|
|
}
|
|
|
|
if (this->MemoryBuffer)
|
|
{
|
|
DeleteObject(this->MemoryBuffer);
|
|
this->MemoryBuffer = 0;
|
|
}
|
|
if (this->MemoryHdc)
|
|
{
|
|
DeleteDC(this->MemoryHdc);
|
|
this->MemoryHdc = 0;
|
|
}
|
|
if (this->ContextId && wglDeleteContext(this->ContextId) != TRUE)
|
|
{
|
|
vtkErrorMacro("wglDeleteContext failed in CleanUpOffScreenRendering(), error: " << GetLastError());
|
|
}
|
|
|
|
this->Mapped = this->ScreenMapped;
|
|
this->Size[0] = this->ScreenWindowSize[0];
|
|
this->Size[1] = this->ScreenWindowSize[1];
|
|
this->DeviceContext = this->ScreenDeviceContext;
|
|
this->DoubleBuffer = this->ScreenDoubleBuffer;
|
|
this->ContextId = this->ScreenContextId;
|
|
this->MakeCurrent();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkWin32OpenGLRenderWindow::HideCursor()
|
|
{
|
|
if (this->CursorHidden)
|
|
{
|
|
return;
|
|
}
|
|
this->CursorHidden = 1;
|
|
::ShowCursor(0);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkWin32OpenGLRenderWindow::ShowCursor()
|
|
{
|
|
if (!this->CursorHidden)
|
|
{
|
|
return;
|
|
}
|
|
this->CursorHidden = 0;
|
|
::ShowCursor(1);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkWin32OpenGLRenderWindow::SetCursorPosition(int x, int y)
|
|
{
|
|
int *size = this->GetSize();
|
|
|
|
POINT point;
|
|
point.x = x;
|
|
point.y = size[1] - y - 1;
|
|
|
|
if (ClientToScreen(this->WindowId, &point))
|
|
{
|
|
SetCursorPos(point.x, point.y);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkWin32OpenGLRenderWindow::SetCurrentCursor(int shape)
|
|
{
|
|
if (this->InvokeEvent(vtkCommand::CursorChangedEvent, &shape))
|
|
{
|
|
return;
|
|
}
|
|
this->Superclass::SetCurrentCursor(shape);
|
|
LPCTSTR cursorName = 0;
|
|
switch (shape)
|
|
{
|
|
case VTK_CURSOR_DEFAULT:
|
|
case VTK_CURSOR_ARROW:
|
|
cursorName = IDC_ARROW;
|
|
break;
|
|
case VTK_CURSOR_SIZENE:
|
|
case VTK_CURSOR_SIZESW:
|
|
cursorName = IDC_SIZENESW;
|
|
break;
|
|
case VTK_CURSOR_SIZENW:
|
|
case VTK_CURSOR_SIZESE:
|
|
cursorName = IDC_SIZENWSE;
|
|
break;
|
|
case VTK_CURSOR_SIZENS:
|
|
cursorName = IDC_SIZENS;
|
|
break;
|
|
case VTK_CURSOR_SIZEWE:
|
|
cursorName = IDC_SIZEWE;
|
|
break;
|
|
case VTK_CURSOR_SIZEALL:
|
|
cursorName = IDC_SIZEALL;
|
|
break;
|
|
case VTK_CURSOR_HAND:
|
|
#if (WINVER >= 0x0500)
|
|
cursorName = IDC_HAND;
|
|
#else
|
|
cursorName = IDC_ARROW;
|
|
#endif
|
|
break;
|
|
case VTK_CURSOR_CROSSHAIR:
|
|
cursorName = IDC_CROSS;
|
|
break;
|
|
}
|
|
|
|
if (cursorName)
|
|
{
|
|
HANDLE cursor =
|
|
LoadImage(0, cursorName, IMAGE_CURSOR, 0, 0, LR_SHARED | LR_DEFAULTSIZE);
|
|
SetCursor((HCURSOR)cursor);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool vtkWin32OpenGLRenderWindow::DetectDPI()
|
|
{
|
|
this->SetDPI(GetDeviceCaps(this->DeviceContext, LOGPIXELSY));
|
|
return true;
|
|
}
|