//-----------------------------------------------------------------------------
bool Win32Context::initWin32GLContext(HGLRC share_context, const vl::String& title, const vl::OpenGLContextFormat& fmt, int x, int y, int width, int height)
{
    class InOutContract
    {
        Win32Context* mContext;

    public:
        bool mOK;

        InOutContract(Win32Context* context): mContext(context), mOK(true)
        {
            cleanup();
        }

        ~InOutContract()
        {
            if (!mOK)
                cleanup();
        }

        void cleanup()
        {
            // delete HDC
            if (mContext->mHDC)
            {
                DeleteDC(mContext->mHDC);
                mContext->mHDC = NULL;
            }

            // delete HGLRC
            if (mContext->mHGLRC)
            {
                if ( wglDeleteContext(mContext->mHGLRC) == FALSE )
                {
                    MessageBox(NULL, L"OpenGL context cleanup failed.\n"
                               L"The handle either doesn't specify a valid context or the context is being used by another thread.",
                               L"Win32Context::init() error!", MB_OK);
                    mOK = false;
                }
                mContext->mHGLRC = NULL;
            }
        }
    } contract(this);

    if (!contract.mOK)
        return false;

    framebuffer()->setWidth(width);
    framebuffer()->setHeight(height);

    if (!hwnd())
    {
        MessageBox(NULL, L"Cannot create OpenGL context: null HWND.", L"Win32Context::init() error!", MB_OK);
        return contract.mOK = false;
    }

    setWindowTitle(title);

    VL_CHECK(mHDC == NULL);
    mHDC = ::GetDC(hwnd());
    if (!mHDC)
    {
        MessageBox(NULL, L"Device context acquisition failed.", L"Win32Context::init() error!", MB_OK);
        return contract.mOK = false;
    }

    int pixel_format_index = vlWin32::choosePixelFormat(fmt);
    if (pixel_format_index == -1)
    {
        MessageBox(NULL, L"No suitable pixel fmt found.", L"Win32Context::init() error!", MB_OK);
        return contract.mOK = false;
    }

    if (SetPixelFormat(mHDC, pixel_format_index, NULL) == FALSE)
    {
        MessageBox(NULL, L"Pixel fmt setup failed.", L"Win32Context::init() error!", MB_OK);
        return contract.mOK = false;
    }

    // OpenGL rendering context creation

    if (wglCreateContextAttribsARB && mContextAttribs.size() > 1)
    {
        // must be 0-terminated list
        VL_CHECK(mContextAttribs.back() == 0);
        // Creates an OpenGL 3.x / 4.x context with the specified attributes.
        mHGLRC = wglCreateContextAttribsARB(mHDC, 0, &mContextAttribs[0]);
    }
    else
    {
        // Creates default OpenGL context
        mHGLRC = wglCreateContext(mHDC);
    }

    if (!mHGLRC)
    {
        MessageBox(NULL, L"OpenGL rendering context creation failed.", L"Win32Context::init() error!", MB_OK);
        return contract.mOK = false;
    }

    // init GL context and makes it current
    // mic fixme: check this also on all the other GUI bindings.
    if( !initGLContext() )
        return contract.mOK = false;

    if (fmt.multisample() && !Has_GL_ARB_multisample)
        vl::Log::error("WGL_ARB_multisample not supported.\n");

    dispatchInitEvent();

    setPosition(x, y);

    setSize(width, height);

    if (Has_GL_EXT_swap_control)
        wglSwapIntervalEXT( fmt.vSync() ? 1 : 0 );

    if (share_context)
        shareOpenGLResources(share_context);

    if (fmt.fullscreen())
        setFullscreen(true);

    return contract.mOK = true;
}
//-----------------------------------------------------------------------------
int vlWin32::choosePixelFormat(const vl::OpenGLContextFormat& fmt, bool verbose)
{
    if (!registerClass())
        return false;

    // this is true only under Win32
    // VL_CHECK( sizeof(wchar_t) == sizeof(short int) )

    HWND hWnd = CreateWindowEx(
                    WS_EX_APPWINDOW | WS_EX_ACCEPTFILES,
                    gWin32WindowClassName,
                    L"Temp GL Window",
                    WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
                    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                    NULL, NULL, GetModuleHandle(NULL), NULL);

    if (!hWnd)
    {
        if (verbose) MessageBox(NULL, L"choosePixelFormat() critical failure: could not create window.", L"Visualization Library error", MB_OK);
        return -1;
    }

    HDC hDC = GetDC(hWnd);
    if (!hDC)
    {
        if (verbose) MessageBox(NULL, L"choosePixelFormat() critical failure: could not create HDC.", L"Visualization Library error", MB_OK);
        DestroyWindow(hWnd);
        return -1;
    }

    PIXELFORMATDESCRIPTOR pfd;
    memset(&pfd, 0, sizeof(pfd));
    pfd.nSize           = sizeof(pfd);
    pfd.nVersion        = 1;
    pfd.dwFlags         = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
    pfd.dwFlags         |= fmt.doubleBuffer() ? PFD_DOUBLEBUFFER : 0;
    pfd.dwFlags         |= fmt.stereo() ? PFD_STEREO : 0;
    pfd.iPixelType      = PFD_TYPE_RGBA;
    pfd.cColorBits      = 0;
    pfd.cRedBits        = (BYTE)fmt.rgbaBits().r();
    pfd.cGreenBits      = (BYTE)fmt.rgbaBits().g();
    pfd.cBlueBits       = (BYTE)fmt.rgbaBits().b();
    pfd.cAlphaBits      = (BYTE)fmt.rgbaBits().a();
    pfd.cAccumRedBits   = (BYTE)fmt.accumRGBABits().r();
    pfd.cAccumGreenBits = (BYTE)fmt.accumRGBABits().g();
    pfd.cAccumBlueBits  = (BYTE)fmt.accumRGBABits().b();
    pfd.cAccumAlphaBits = (BYTE)fmt.accumRGBABits().a();
    pfd.cDepthBits      = (BYTE)fmt.depthBufferBits();
    pfd.cStencilBits    = (BYTE)fmt.stencilBufferBits();
    pfd.iLayerType      = PFD_MAIN_PLANE;

    int pixel_format_index = ChoosePixelFormat(hDC, &pfd);

    if (pixel_format_index == 0)
    {
        if (verbose) MessageBox(NULL, L"choosePixelFormat() critical failure: could not choose temporary format.", L"Visualization Library error", MB_OK);
        DeleteDC(hDC);
        DestroyWindow(hWnd);
        return -1;
    }

    if (SetPixelFormat(hDC, pixel_format_index, &pfd) == FALSE)
    {
        if (verbose) MessageBox(NULL, L"choosePixelFormat() critical failure: could not set temporary format.", L"Visualization Library error", MB_OK);
        DeleteDC(hDC);
        DestroyWindow(hWnd);
        return -1;
    }

    // OpenGL Rendering Context
    HGLRC hGLRC = wglCreateContext(hDC);
    if (!hGLRC)
    {
        if (verbose) MessageBox(NULL, L"choosePixelFormat() critical failure: could not create temporary OpenGL context.", L"Visualization Library error", MB_OK);
        DeleteDC(hDC);
        DestroyWindow(hWnd);
        return -1;
    }

    wglMakeCurrent(hDC, hGLRC);

    if (!initializeOpenGL())
    {
        fprintf(stderr, "Error initializing OpenGL!\n");
        DeleteDC(hDC);
        DestroyWindow(hWnd);
        return -1;
    }

    // if this is not supported we use the current 'pixel_format_index' returned by ChoosePixelFormat above.

    int samples = 0;
    if(Has_WGL_ARB_pixel_format && fmt.multisample())
    {
        float fAttributes[] = { 0, 0 };
        int iAttributes[] =
        {
            // multi sampling
            WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
            WGL_SAMPLES_ARB,        -1, // this is set below
            // generic
            WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
            WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
            WGL_ACCELERATION_ARB,   WGL_FULL_ACCELERATION_ARB,
            // color buffer
            WGL_RED_BITS_ARB,         pfd.cRedBits,
            WGL_GREEN_BITS_ARB,       pfd.cGreenBits,
            WGL_BLUE_BITS_ARB,        pfd.cBlueBits,
            WGL_ALPHA_BITS_ARB,       pfd.cAlphaBits,
            // accumulation buffer
            WGL_ACCUM_RED_BITS_ARB,   pfd.cAccumRedBits,
            WGL_ACCUM_GREEN_BITS_ARB, pfd.cAccumGreenBits,
            WGL_ACCUM_BLUE_BITS_ARB,  pfd.cAccumBlueBits,
            WGL_ACCUM_ALPHA_BITS_ARB, pfd.cAccumAlphaBits,
            // depth buffer
            WGL_DEPTH_BITS_ARB,       pfd.cDepthBits,
            WGL_DOUBLE_BUFFER_ARB,    fmt.doubleBuffer() ? GL_TRUE : GL_FALSE,
            // stencil buffer
            WGL_STENCIL_BITS_ARB,     pfd.cStencilBits,
            // stereo
            WGL_STEREO_ARB,           fmt.stereo() ? GL_TRUE : GL_FALSE,
            0,0
        };

        for(samples = fmt.multisampleSamples(); samples > 1; samples/=2)
        {
            // sets WGL_SAMPLES_ARB value
            iAttributes[3] = samples;
            pixel_format_index = -1;
            UINT num_formats  = 0;
            if ( wglChoosePixelFormatARB(hDC,iAttributes,fAttributes,1,&pixel_format_index,&num_formats) && num_formats >= 1 )
                break;
            else
                pixel_format_index = -1;
        }
    }

    // destroy temporary HWND, HDC, HGLRC
    if ( wglDeleteContext(hGLRC) == FALSE )
        if (verbose) MessageBox(NULL, L"Error deleting temporary OpenGL context, wglDeleteContext(hGLRC) failed.", L"Visualization Library error", MB_OK);
    DeleteDC(hDC);
    DestroyWindow(hWnd);

    if (verbose)
    {
        if(pixel_format_index == -1)
            vl::Log::error("No suitable pixel format found.\n");
        else
        {
            // check the returned pixel format
#if defined(DEBUG) || !defined(NDEBUG)
            DescribePixelFormat(hDC, pixel_format_index, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
            vl::Log::debug(" --- vlWin32::choosePixelFormat() ---\n");
            // This one returns "not supported" even when its supported...
            // vl::Log::print( vl::Say("  OpenGL        = %s\n") << (pfd.dwFlags & PFD_SUPPORT_OPENGL ? "Supported" : "Not supported") );
            vl::Log::debug( vl::Say("RGBA Bits     = %n %n %n %n\n") << pfd.cRedBits << pfd.cGreenBits << pfd.cBlueBits << pfd.cAlphaBits);
            vl::Log::debug( vl::Say("Depth Bits    = %n\n")  << pfd.cDepthBits );
            vl::Log::debug( vl::Say("Stencil Bits  = %n \n") << pfd.cStencilBits);
            vl::Log::debug( vl::Say("Double Buffer = %s\n")  << (pfd.dwFlags & PFD_DOUBLEBUFFER ? "Yes" : "No") );
            vl::Log::debug( vl::Say("Stereo        = %s\n")  << (pfd.dwFlags & PFD_STEREO ? "Yes" : "No") );
            vl::Log::debug( vl::Say("Samples       = %n\n")  << samples );
            vl::Log::debug("\n");
#endif
        }
    }

    return pixel_format_index;
}
//-----------------------------------------------------------------------------
bool SDLWindow::initSDLWindow(const vl::String& title, const vl::OpenGLContextFormat& info, int x, int y, int width, int height)
{
  if (mScreen || mSDLWindow)
  {
    vl::Log::error("SDL supports only one window at a time.\n");
    VL_TRAP();
    return false;
  }

  framebuffer()->setWidth(width);
  framebuffer()->setHeight(height);
  mSDLWindow = this;

  // init key translation map
  for(int i=0; key_translation_vec[i]; i+=2)
    key_translation_map[ key_translation_vec[i] ] = (vl::EKey)key_translation_vec[i+1];

  // SDL_VIDEO_WINDOW_POS

  char win_pos[32] = {0};
  sprintf ( win_pos, "SDL_VIDEO_WINDOW_POS=%d,%d", x, y );
  SDL_putenv(win_pos);
  // setenv("SDL_VIDEO_CENTERED", "YES", 0);

  // init SDL

  if ( SDL_Init(SDL_INIT_VIDEO) < 0 )
	{
    printf("Unable to init SDL: %s\n", SDL_GetError());
    return false;
  }

  SDL_GL_SetAttribute(SDL_GL_RED_SIZE,   info.rgbaBits().r());
  SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, info.rgbaBits().g());
  SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,  info.rgbaBits().b());
  SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, info.rgbaBits().a());

  SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE,   info.accumRGBABits().r());
  SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, info.accumRGBABits().g());
  SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE,  info.accumRGBABits().b());
  SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, info.accumRGBABits().a());

  SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, info.depthBufferBits());
  SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, info.stencilBufferBits());

  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, info.doubleBuffer()?1:0);
  SDL_GL_SetAttribute(SDL_GL_STEREO, info.stereo());
  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, info.multisample()?1:0);
  if (info.multisample())
    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, info.multisampleSamples());
  SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, info.vSync());

  int bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
  Uint32 flags = SDL_OPENGL | (info.fullscreen() ? SDL_FULLSCREEN : 0);
  width  = width  !=0 ? width  : SDL_GetVideoInfo()->current_w;
  height = height !=0 ? height : SDL_GetVideoInfo()->current_h;
  mScreen = SDL_SetVideoMode( width, height, bpp, flags );
  if (mScreen == 0)
  {
    vl::Log::print( vl::Say("\n  error: SDL_SetVideoMode(%n, %n, %n, %hn) failed: %s\n") << width << height << bpp << flags << SDL_GetError() );
    exit(1);
  }

  // window size problem

  int viewport[4];
  glGetIntegerv(GL_VIEWPORT,  viewport);
  VL_CHECK(viewport[0] == 0);
  VL_CHECK(viewport[1] == 0);
  if (viewport[2] != mScreen->w || viewport[3] != mScreen->h)
  {
    vl::Log::print( vl::Say("\n  warning: OpenGL reported %nx%n as video size but SDL says %nx%n\n") << viewport[2] << viewport[3] << mScreen->w << mScreen->h );
    VL_TRAP()
  }