diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -1114,6 +1114,7 @@ float VideoDriver_Win32Base::GetDPIScale bool VideoDriver_Win32Base::LockVideoBuffer() { if (_draw_threaded) this->draw_lock.lock(); + _screen.dst_ptr = _wnd.buffer_bits; return true; } @@ -1319,3 +1320,155 @@ void VideoDriver_Win32GDI::PaintThread() return _fooctr++; } #endif + +#ifdef WITH_OPENGL + +#include +#include "../3rdparty/opengl/glext.h" +#include "opengl.h" + +#ifndef PFD_SUPPORT_COMPOSITION +# define PFD_SUPPORT_COMPOSITION 0x00008000 +#endif + +static FVideoDriver_Win32OpenGL iFVideoDriver_Win32OpenGL; + +const char *VideoDriver_Win32OpenGL::Start(const StringList ¶m) +{ + if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32) return "Only 32bpp blitters supported"; + + Dimension old_res = _cur_resolution; // Save current screen resolution in case of errors, as MakeWindow invalidates it. + + this->Initialize(); + this->MakeWindow(_fullscreen); + + /* Create and initialize OpenGL context. */ + const char *err = this->AllocateContext(); + if (err != nullptr) { + this->Stop(); + _cur_resolution = old_res; + return err; + } + + this->ClientSizeChanged(_wnd.width, _wnd.height); + + _draw_threaded = false; + MarkWholeScreenDirty(); + + return nullptr; +} + +void VideoDriver_Win32OpenGL::Stop() +{ + this->DestroyContext(); + this->VideoDriver_Win32Base::Stop(); +} + +void VideoDriver_Win32OpenGL::DestroyContext() +{ + OpenGLBackend::Destroy(); + + wglMakeCurrent(nullptr, nullptr); + if (this->gl_rc != nullptr) { + wglDeleteContext(this->gl_rc); + this->gl_rc = nullptr; + } + if (this->dc != nullptr) { + ReleaseDC(this->main_wnd, this->dc); + this->dc = nullptr; + } +} + +const char *VideoDriver_Win32OpenGL::AllocateContext() +{ + PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), // Size of this struct. + 1, // Version of this struct. + PFD_DRAW_TO_WINDOW | // Require window support. + PFD_SUPPORT_OPENGL | // Require OpenGL support. + PFD_DOUBLEBUFFER | // Use double buffering. + PFD_DEPTH_DONTCARE, + PFD_TYPE_RGBA, // Request RGBA format. + 24, // 24 bpp (excluding alpha). + 0, 0, 0, 0, 0, 0, 0, 0, // Colour bits and shift ignored. + 0, 0, 0, 0, 0, // No accumulation buffer. + 0, 0, // No depth/stencil buffer. + 0, // No aux buffers. + PFD_MAIN_PLANE, // Main layer. + 0, 0, 0, 0 // Ignored/reserved. + }; + + if (IsWindowsVistaOrGreater()) pfd.dwFlags |= PFD_SUPPORT_COMPOSITION; // Make OpenTTD compatible with Aero. + + this->dc = GetDC(this->main_wnd); + + /* Choose a suitable pixel format. */ + int format = ChoosePixelFormat(this->dc, &pfd); + if (format == 0) return "No suitable pixel format found"; + if (!SetPixelFormat(this->dc, format, &pfd)) return "Can't set pixel format"; + + /* Create OpenGL device context. */ + this->gl_rc = wglCreateContext(this->dc); + if (this->gl_rc == 0) return "Can't create OpenGL context"; + if (!wglMakeCurrent(this->dc, this->gl_rc)) return "Can't active GL context"; + + return OpenGLBackend::Create(); +} + +bool VideoDriver_Win32OpenGL::ToggleFullscreen(bool full_screen) +{ + this->DestroyContext(); + bool res = this->VideoDriver_Win32Base::ToggleFullscreen(full_screen); + res &= this->AllocateContext() == nullptr; + this->ClientSizeChanged(_wnd.width, _wnd.height); + return res; +} + +bool VideoDriver_Win32OpenGL::AfterBlitterChange() +{ + assert(BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 0); + this->ClientSizeChanged(_wnd.width, _wnd.height); + return true; +} + +bool VideoDriver_Win32OpenGL::AllocateBackingStore(int w, int h, bool force) +{ + if (!force && w == _screen.width && h == _screen.height) return false; + + _wnd.width = w = std::max(w, 64); + _wnd.height = h = std::max(h, 64); + + if (this->gl_rc == nullptr) return false; + + bool res = OpenGLBackend::Get()->Resize(w, h); + _wnd.buffer_bits = OpenGLBackend::Get()->GetVideoBuffer(); + return res; +} + +void VideoDriver_Win32OpenGL::Paint() +{ + PerformanceMeasurer framerate(PFE_VIDEO); + + if (_cur_palette.count_dirty != 0) { + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + + switch (blitter->UsePaletteAnimation()) { + case Blitter::PALETTE_ANIMATION_BLITTER: + blitter->PaletteAnimate(_local_palette); + break; + + case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND: + case Blitter::PALETTE_ANIMATION_NONE: + break; + + default: + NOT_REACHED(); + } + _cur_palette.count_dirty = 0; + } + + OpenGLBackend::Get()->Paint(); + SwapBuffers(this->dc); +} + +#endif /* WITH_OPENGL */