<commit_before>/*=========================================================================

Program:   Visualization Toolkit
Module:    vtkWin32OpenGLRenderWindow.cxx

Copyright (c) <NAME>, <NAME>, <NAME>
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 "vtkWin32RenderWindowInteractor.h"

#include <math.h>
#include <sstream>

#include "vtkOpenGLError.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);

vtkWin32OpenGLRenderWindow::vtkWin32OpenGLRenderWindow()
{
  this->ApplicationInstance =  NULL;
  this->Palette = NULL;
  this->ContextId = 0;
  this->WindowId = 0;
  this->ParentId = 0;
  this->NextWindowId = 0;
  this->DeviceContext = (HDC)0;         // hsr
  this->MFChandledWindow = FALSE;       // hsr
  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()
{
  /* finish OpenGL rendering */
  if (this->OwnContext && this->ContextId)
    {
    this->MakeCurrent();
    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)
  this->ReleaseGraphicsResources(this);
}

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(const int borders, const int x, const int y,
                                const int width, const int height, RECT &r)
{
  DWORD style = WS_CLIPCHILDREN /*| WS_CLIPSIBLINGS*/;
  if (borders)
    {
    style |= WS_OVERLAPPEDWINDOW;
    }
  else
    {
    style |= WS_POPUP;
    }
  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->Modified();
    this->Size[0] = x;
    this->Size[1] = 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->Borders, 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();
    }
}

void vtkWin32OpenGLRenderWindow::VTKRegisterClass()
{
  // has the class been registered ?
  WNDCLASS wndClass;
#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);
    }
}

int vtkWin32OpenGLRenderWindow::SupportsOpenGL()
{
#ifdef GLEW_OK
  this->InitializeApplication();
  this->VTKRegisterClass();

  // 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);

  GLenum result = glewInit();
  bool m_valid = (result == GLEW_OK);
  if (!m_valid)
    {
    return 0;
    }

  if (GLEW_VERSION_3_2 || (GLEW_VERSION_2_1 && GLEW_EXT_gpu_shader4))
    {
    return 1;
    }

#endif

  return 0;
}


int vtkWin32OpenGLRenderWindow::IsDirect()
{
  this->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()
{
  this->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);

std::ostringstream strm;
  if(glVendor)
    strm << "OpenGL vendor string:  " << glVendor << endl;
  if(glRenderer)
    strm << "OpenGL renderer string:  " << glRenderer << endl;
  if(glVersion)
    strm << "OpenGL version string:  " << glVersion << endl;

  strm << "OpenGL extensions:  " << endl;
  GLint n, i;
  glGetIntegerv(GL_NUM_EXTENSIONS, &n);
  for (i = 0; i < n; i++)
    {
    const char *ext = (const char *)glGetStringi(GL_EXTENSIONS, i);
    strm << "  " << ext << 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*);

void vtkWin32OpenGLRenderWindow::SetupPixelFormatPaletteAndContext(
  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);

  // make sure glew is initialized with fake window
  this->OpenGLInit();

  // First we try to use the newer wglChoosePixelFormatARB which enables
  // features like multisamples.
  PIXELFORMATDESCRIPTOR pfd;
  int pixelFormat = 0;
  if (wglChoosePixelFormatARB)
    {
    int attrib[] = {
      WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
      WGL_SUPPORT_OPENGL_ARB, TRUE,
      WGL_DRAW_TO_WINDOW_ARB, TRUE,
      WGL_DOUBLE_BUFFER_ARB, TRUE,
      WGL_COLOR_BITS_ARB, bpp/4*3,
      WGL_DEPTH_BITS_ARB, zbpp/4*3,
      WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    unsigned int n = 14;
    if (this->AlphaBitPlanes)
      {
      attrib[n] = WGL_ALPHA_BITS_ARB;
      attrib[n+1] = bpp/4;
      n += 2;
      }
    if (this->StencilCapable)
      {
      attrib[n] = WGL_STENCIL_BITS_ARB;
      attrib[n+1] = 8;
      n += 2;
      }
    if (dwFlags & PFD_STEREO)
      {
      attrib[n] = WGL_STEREO_ARB;
      attrib[n+1] = TRUE;
      n += 2;
      }
    unsigned int multiSampleAttributeIndex = 0;
    if (this->MultiSamples > 1 &&
        wglewIsSupported("WGL_ARB_multisample"))
      {
      attrib[n] = WGL_SAMPLE_BUFFERS_ARB;
      attrib[n+1] = 1;
      attrib[n+2] = WGL_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);
          }
        }
      }

    DescribePixelFormat(hDC, pixelFormat, sizeof(pfd), &pfd);
    if (!SetPixelFormat(hDC, pixelFormat, &pfd))
      {
      pixelFormat = 0;
      }
    else
      {
      if (debug && (dwFlags & PFD_STEREO) && !(pfd.dwFlags & PFD_STEREO))
        {
        vtkGenericWarningMacro("No Stereo Available!");
        this->StereoCapableWindow = 0;
        }
      }
    }
  else
    {
    vtkErrorMacro("failed to get wglChoosePixelFormatARB");
    }

  // see if we can get a 3.2 context
  if (pixelFormat)
    {
    this->SetupPalette(hDC);
<commit_msg>Fix handling of failed pixel formats<commit_after>/*=========================================================================

Program:   Visualization Toolkit
Module:    vtkWin32OpenGLRenderWindow.cxx

Copyright (c) <NAME>, <NAME>, <NAME>
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 "vtkWin32RenderWindowInteractor.h"

#include <math.h>
#include <sstream>

#include "vtkOpenGLError.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);

vtkWin32OpenGLRenderWindow::vtkWin32OpenGLRenderWindow()
{
  this->ApplicationInstance =  NULL;
  this->Palette = NULL;
  this->ContextId = 0;
  this->WindowId = 0;
  this->ParentId = 0;
  this->NextWindowId = 0;
  this->DeviceContext = (HDC)0;         // hsr
  this->MFChandledWindow = FALSE;       // hsr
  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()
{
  /* finish OpenGL rendering */
  if (this->OwnContext && this->ContextId)
    {
    this->MakeCurrent();
    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)
  this->ReleaseGraphicsResources(this);
}

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(const int borders, const int x, const int y,
                                const int width, const int height, RECT &r)
{
  DWORD style = WS_CLIPCHILDREN /*| WS_CLIPSIBLINGS*/;
  if (borders)
    {
    style |= WS_OVERLAPPEDWINDOW;
    }
  else
    {
    style |= WS_POPUP;
    }
  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->Modified();
    this->Size[0] = x;
    this->Size[1] = 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->Borders, 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();
    }
}

void vtkWin32OpenGLRenderWindow::VTKRegisterClass()
{
  // has the class been registered ?
  WNDCLASS wndClass;
#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);
    }
}

int vtkWin32OpenGLRenderWindow::SupportsOpenGL()
{
#ifdef GLEW_OK
  this->InitializeApplication();
  this->VTKRegisterClass();

  // 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);

  GLenum result = glewInit();
  bool m_valid = (result == GLEW_OK);
  if (!m_valid)
    {
    return 0;
    }

  if (GLEW_VERSION_3_2 || (GLEW_VERSION_2_1 && GLEW_EXT_gpu_shader4))
    {
    return 1;
    }

#endif

  return 0;
}


int vtkWin32OpenGLRenderWindow::IsDirect()
{
  this->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()
{
  this->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);

std::ostringstream strm;
  if(glVendor)
    strm << "OpenGL vendor string:  " << glVendor << endl;
  if(glRenderer)
    strm << "OpenGL renderer string:  " << glRenderer << endl;
  if(glVersion)
    strm << "OpenGL version string:  " << glVersion << endl;

  strm << "OpenGL extensions:  " << endl;
  GLint n, i;
  glGetIntegerv(GL_NUM_EXTENSIONS, &n);
  for (i = 0; i < n; i++)
    {
    const char *ext = (const char *)glGetStringi(GL_EXTENSIONS, i);
    strm << "  " << ext << 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*);

void vtkWin32OpenGLRenderWindow::SetupPixelFormatPaletteAndContext(
  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);

  // make sure glew is initialized with fake window
  this->OpenGLInit();

  // First we try to use the newer wglChoosePixelFormatARB which enables
  // features like multisamples.
  PIXELFORMATDESCRIPTOR pfd;
  int pixelFormat = 0;
  if (wglChoosePixelFormatARB)
    {
    int attrib[] = {
      WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
      WGL_SUPPORT_OPENGL_ARB, TRUE,
      WGL_DRAW_TO_WINDOW_ARB, TRUE,
      WGL_DOUBLE_BUFFER_ARB, TRUE,
      WGL_COLOR_BITS_ARB, bpp/4*3,
      WGL_DEPTH_BITS_ARB, zbpp/4*3,
      WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    unsigned int n = 14;
    if (this->AlphaBitPlanes)
      {
      attrib[n] = WGL_ALPHA_BITS_ARB;
      attrib[n+1] = bpp/4;
      n += 2;
      }
    if (this->StencilCapable)
      {
      attrib[n] = WGL_STENCIL_BITS_ARB;
      attrib[n+1] = 8;
      n += 2;
      }
    unsigned int stereoAttributeIndex = 0;
    if (dwFlags & PFD_STEREO)
      {
      attrib[n] = WGL_STEREO_ARB;
      attrib[n+1] = TRUE;
      stereoAttributeIndex = n+1;
      n += 2;
      }
    unsigned int multiSampleAttributeIndex = 0;
    if (this->MultiSamples > 1 &&
        wglewIsSupported("WGL_ARB_multisample"))
      {
      attrib[n] = WGL_SAMPLE_BUFFERS_ARB;
      attrib[n+1] = 1;
      attrib[n+2] = WGL_SAMPLES_ARB;
      attrib[n+3] = this->MultiSamples;
      multiSampleAttributeIndex = n+3;
      n += 4;
      }
    unsigned int numFormats;
    if (!wglChoosePixelFormatARB(hDC, attrib, 0, 1, &pixelFormat, &numFormats)
      || numFormats == 0)
      {
      // 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) || numFormats == 0)
          {
          attrib[multiSampleAttributeIndex] /= 2;
          wglChoosePixelFormatARB(hDC, attrib, 0, 1, &pixelFormat, &numFormats);
          }
        }
      // try dropping stereo
      if (stereoAttributeIndex && numFormats == 0)
        {
        attrib[stereoAttributeIndex] = FALSE;
        wglChoosePixelFormatARB(hDC, attrib, 0, 1, &pixelFormat, &numFormats);
        }
      }

    DescribePixelFormat(hDC, pixelFormat, sizeof(pfd), &pfd);
    if (!SetPixelFormat(hDC, pixelFormat, &pfd))
      {
      pixelFormat = 0;
      }
    else
      {
      if (debug && (dwFlags & PFD_STEREO) && !(pfd.dwFlags & PFD_STEREO))
        {
        vtkGenericWarningMacro("No Stereo Available!");
        this->StereoCapableWindow = 0;
        }
      }
    }
  else
    {
    vtkErrorMacro("failed to get wglChoosePixelFormatARB");
    }

  // see if we can get a 3.2 context
  if (pixelFormat)
    {
    this->SetupPalette(hDC);

{'fraction_non_alphanumeric': 0.14977406406987606, 'fraction_numerical': 0.012495897811324565, 'mean_word_length': 2.799904076738609, 'pattern_counts': {'":': 0, '<': 359, '<?xml version=': 0, '>': 309, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '127332', 'n_tokens_mistral': 13998, 'n_tokens_neox': 13515, 'n_words': 2814}