diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj index 85ea55a..59fbec6 100644 --- a/projects/openttd_vs100.vcxproj +++ b/projects/openttd_vs100.vcxproj @@ -968,6 +968,8 @@ + + @@ -1097,6 +1099,8 @@ + + diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters index 43bb5b6..efabfdd 100644 --- a/projects/openttd_vs100.vcxproj.filters +++ b/projects/openttd_vs100.vcxproj.filters @@ -2127,6 +2127,12 @@ Blitters + + Blitters + + + Blitters + Blitters @@ -2514,6 +2520,12 @@ Video + + Video + + + Video + Video diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj index 896e14b..f1a1689 100644 --- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -3207,6 +3207,14 @@ > + + + + @@ -3763,6 +3771,14 @@ > + + + + diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj index d17c076..44f5da3 100644 --- a/projects/openttd_vs90.vcproj +++ b/projects/openttd_vs90.vcproj @@ -3204,6 +3204,14 @@ > + + + + @@ -3760,6 +3768,14 @@ > + + + + diff --git a/source.list b/source.list index 4a395c4..3755fdc 100644 --- a/source.list +++ b/source.list @@ -748,6 +748,8 @@ blitter/32bpp_anim.cpp blitter/32bpp_anim.hpp blitter/32bpp_base.cpp blitter/32bpp_base.hpp +blitter/32bpp_opengl.hpp +blitter/32bpp_opengl.cpp blitter/32bpp_optimized.cpp blitter/32bpp_optimized.hpp blitter/32bpp_simple.cpp @@ -905,6 +907,8 @@ video/null_v.cpp #if ALLEGRO video/allegro_v.cpp #end +video/opengl_v.cpp +video/opengl_v.h #if SDL video/sdl_v.cpp #end diff --git a/src/blitter/32bpp_anim.hpp b/src/blitter/32bpp_anim.hpp index 862a21c..0841715 100644 --- a/src/blitter/32bpp_anim.hpp +++ b/src/blitter/32bpp_anim.hpp @@ -16,7 +16,7 @@ /** The optimised 32 bpp blitter with palette animation. */ class Blitter_32bppAnim : public Blitter_32bppOptimized { -private: +protected: uint8 *anim_buf; ///< In this buffer we keep track of the 8bpp indexes so we can do palette animation int anim_buf_width; ///< The width of the animation buffer. int anim_buf_height; ///< The height of the animation buffer. diff --git a/src/blitter/base.hpp b/src/blitter/base.hpp index 0a761a1..8b7049c 100644 --- a/src/blitter/base.hpp +++ b/src/blitter/base.hpp @@ -185,6 +185,12 @@ class Blitter { virtual Blitter::PaletteAnimation UsePaletteAnimation() = 0; /** + * Get the pointer to the animation buffer (only useful for 32 bpp blitters). + * @return Pointer to the animation buffer or NULL if the blitter has no anim buffer. + */ + virtual void *GetAnimationBuffer() { return NULL; } + + /** * Get the name of the blitter, the same as the Factory-instance returns. */ virtual const char *GetName() = 0; diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index 93961e4..24dfddb 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -20,6 +20,7 @@ #include "../core/random_func.hpp" #include "../texteff.hpp" #include "win32_v.h" +#include "opengl_v.h" #include static struct { @@ -34,6 +35,8 @@ bool fullscreen; bool has_focus; bool running; + HGLRC gl_rc; + HDC dc; } _wnd; bool _force_full_redraw; @@ -159,21 +162,24 @@ static uint MapWindowsKey(uint sym) static void ClientSizeChanged(int w, int h) { - /* allocate new dib section of the new size */ - if (AllocateDibSection(w, h)) { - /* mark all palette colors dirty */ - _cur_palette.first_dirty = 0; - _cur_palette.count_dirty = 256; + if (_wnd.gl_rc != NULL) { + ResizeGLWindow(w, h); + } else { + /* allocate new dib section of the new size */ + if (!AllocateDibSection(w, h)) return; + } - BlitterFactoryBase::GetCurrentBlitter()->PostResize(); + /* mark all palette colors dirty */ + _cur_palette.first_dirty = 0; + _cur_palette.count_dirty = 256; - GameSizeChanged(); + BlitterFactoryBase::GetCurrentBlitter()->PostResize(); + GameSizeChanged(); - /* redraw screen */ - if (_wnd.running) { - _screen.dst_ptr = _wnd.buffer_bits; - UpdateWindows(); - } + /* redraw screen */ + if (_wnd.running) { + _screen.dst_ptr = _wnd.gl_rc != NULL ? _gl_screen_buffer : _wnd.buffer_bits; + UpdateWindows(); } } @@ -328,6 +334,34 @@ bool VideoDriver_Win32::MakeWindow(bool full_screen) return true; // the request succedded } +void DoPaletteAnimation(HDC dc) +{ + if (_cur_palette.count_dirty != 0) { + Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter(); + + switch (blitter->UsePaletteAnimation()) { + case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND: + if (dc == NULL) { + GLUpdatePalette(_cur_palette.first_dirty, _cur_palette.count_dirty); + } else { + UpdatePalette(dc, _cur_palette.first_dirty, _cur_palette.count_dirty); + } + break; + + case Blitter::PALETTE_ANIMATION_BLITTER: + blitter->PaletteAnimate(_cur_palette); + break; + + case Blitter::PALETTE_ANIMATION_NONE: + break; + + default: + NOT_REACHED(); + } + _cur_palette.count_dirty = 0; + } +} + static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static uint32 keycode = 0; @@ -338,52 +372,41 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, (TIMERPROC)TrackMouseTimerProc); break; - case WM_PAINT: { - PAINTSTRUCT ps; - HDC dc, dc2; - HBITMAP old_bmp; - HPALETTE old_palette; - - BeginPaint(hwnd, &ps); - dc = ps.hdc; - dc2 = CreateCompatibleDC(dc); - old_bmp = (HBITMAP)SelectObject(dc2, _wnd.dib_sect); - old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE); - - if (_cur_palette.count_dirty != 0) { - Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter(); - - switch (blitter->UsePaletteAnimation()) { - case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND: - UpdatePalette(dc2, _cur_palette.first_dirty, _cur_palette.count_dirty); - break; - - case Blitter::PALETTE_ANIMATION_BLITTER: - blitter->PaletteAnimate(_cur_palette); - break; - - case Blitter::PALETTE_ANIMATION_NONE: - break; - - default: - NOT_REACHED(); - } - _cur_palette.count_dirty = 0; + case WM_PAINT: + if (_wnd.gl_rc != NULL) { + /* OpenGL is in use. */ + DoPaletteAnimation(NULL); + GLUpdateDisplay(); + ValidateRect(hwnd, NULL); + } else { + PAINTSTRUCT ps; + HDC dc, dc2; + HBITMAP old_bmp; + HPALETTE old_palette; + + BeginPaint(hwnd, &ps); + dc = ps.hdc; + dc2 = CreateCompatibleDC(dc); + old_bmp = (HBITMAP)SelectObject(dc2, _wnd.dib_sect); + old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE); + + DoPaletteAnimation(dc2); + + BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY); + SelectPalette(dc, old_palette, TRUE); + SelectObject(dc2, old_bmp); + DeleteDC(dc2); + EndPaint(hwnd, &ps); } - - BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY); - SelectPalette(dc, old_palette, TRUE); - SelectObject(dc2, old_bmp); - DeleteDC(dc2); - EndPaint(hwnd, &ps); return 0; - } case WM_PALETTECHANGED: if ((HWND)wParam == hwnd) return 0; /* FALL THROUGH */ case WM_QUERYNEWPALETTE: { + if (_wnd.gl_rc == NULL) return 0; + HDC hDC = GetWindowDC(hwnd); HPALETTE hOldPalette = SelectPalette(hDC, _wnd.gdi_palette, FALSE); UINT nChanged = RealizePalette(hDC); @@ -679,7 +702,7 @@ static void RegisterWndClass() if (!registered) { HINSTANCE hinst = GetModuleHandle(NULL); WNDCLASS wnd = { - 0, + CS_OWNDC, WndProcGdi, 0, 0, @@ -747,7 +770,7 @@ static bool AllocateDibSection(int w, int h, bool force) { 1920, 1200 } }; -static void FindResolutions() +static void FindResolutions(uint8 screen_depth) { uint n = 0; #if defined(WINCE) @@ -761,7 +784,7 @@ static void FindResolutions() * Doesn't really matter since we don't pass a string anyways, but still * a letdown */ for (i = 0; EnumDisplaySettingsA(NULL, i, &dm) != 0; i++) { - if (dm.dmBitsPerPel == BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() && + if (dm.dmBitsPerPel == screen_depth && dm.dmPelsWidth >= 640 && dm.dmPelsHeight >= 480) { uint j; @@ -802,7 +825,7 @@ static void FindResolutions() MakePalette(); - FindResolutions(); + FindResolutions(BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth()); DEBUG(driver, 2, "Resolution for display: %ux%u", _cur_resolution.width, _cur_resolution.height); @@ -907,7 +930,7 @@ void VideoDriver_Win32::MainLoop() #if !defined(WINCE) GdiFlush(); #endif - _screen.dst_ptr = _wnd.buffer_bits; + _screen.dst_ptr = _wnd.gl_rc != NULL ? _gl_screen_buffer : _wnd.buffer_bits; UpdateWindows(); CheckPaletteAnim(); } else { @@ -915,7 +938,7 @@ void VideoDriver_Win32::MainLoop() #if !defined(WINCE) GdiFlush(); #endif - _screen.dst_ptr = _wnd.buffer_bits; + _screen.dst_ptr = _wnd.gl_rc != NULL ? _gl_screen_buffer : _wnd.buffer_bits; NetworkDrawChatMessage(); DrawMouseCursor(); } @@ -937,5 +960,101 @@ bool VideoDriver_Win32::ToggleFullscreen(bool full_screen) bool VideoDriver_Win32::AfterBlitterChange() { - return AllocateDibSection(_screen.width, _screen.height, true) && this->MakeWindow(_fullscreen); + if (_wnd.gl_rc != NULL) { + ResizeGLWindow(_screen.width, _screen.height); + } else { + if (!AllocateDibSection(_screen.width, _screen.height, true)) return false; + } + return this->MakeWindow(_fullscreen); +} + + +/* Implementation of OpenGL video driver. */ + +#ifndef PFD_SUPPORT_COMPOSITION +#define PFD_SUPPORT_COMPOSITION 0x00008000 +#endif + +static const char *AllocateOpenGLContext() +{ + static const 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_DEPTH_DONTCARE | + PFD_SUPPORT_COMPOSITION, // Make OpenTTD compatible with Aero. + 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. + }; + + _wnd.dc = GetDC(_wnd.main_wnd); + + /* Choose a suitable pixel format. */ + int format = ChoosePixelFormat(_wnd.dc, &pfd); + if (format == 0) return "No suitable pixel format found"; + if (!SetPixelFormat(_wnd.dc, format, &pfd)) return "Can't set pixel format"; + + PIXELFORMATDESCRIPTOR temp; + DescribePixelFormat(_wnd.dc, format, sizeof(PIXELFORMATDESCRIPTOR), &temp); + + /* Create OpenGL device context. */ + _wnd.gl_rc = wglCreateContext(_wnd.dc); + if (_wnd.gl_rc == 0) return "Can't create OpenGL context"; + if (!wglMakeCurrent(_wnd.dc, _wnd.gl_rc)) return "Can't active GL context"; + + /* Load needed extension functions. */ + if (!CheckOpenGLExtensions() || !BindOpenGLExtensions()) return "Driver doesn't support fragment programs"; + + /* Initialize the drawing context. */ + if (!InitOpenGL()) return "OpenGL init failed"; + + return NULL; +} + +static FVideoDriver_Win32OpenGL iFVideoDriver_Win32OpenGL; + +const char *VideoDriver_Win32OpenGL::Start(const char * const *parm) +{ + memset(&_wnd, 0, sizeof(_wnd)); + + RegisterWndClass(); + + FindResolutions(32); // OpenGL is always 32 bpp. + + DEBUG(driver, 2, "Resolution for display: %ux%u", _cur_resolution.width, _cur_resolution.height); + + _wnd.width = _wnd.width_org = _cur_resolution.width; + _wnd.height = _wnd.height_org = _cur_resolution.height; + + this->MakeWindow(_fullscreen); + + const char *err = AllocateOpenGLContext(); + if (err != NULL) { + this->Stop(); + return err; + } + + MarkWholeScreenDirty(); + + return NULL; +} + +void VideoDriver_Win32OpenGL::Stop() +{ + wglMakeCurrent(NULL, NULL); + if (_wnd.gl_rc != NULL) wglDeleteContext(_wnd.gl_rc); + if (_wnd.dc != NULL) ReleaseDC(_wnd.main_wnd, _wnd.dc); + if (_wnd.main_wnd != NULL) DestroyWindow(_wnd.main_wnd); + +#if !defined(WINCE) + if (_wnd.fullscreen) ChangeDisplaySettings(NULL, 0); +#endif + MyShowCursor(true); } diff --git a/src/video/win32_v.h b/src/video/win32_v.h index 0706c0e..470ba82 100644 --- a/src/video/win32_v.h +++ b/src/video/win32_v.h @@ -38,13 +38,31 @@ class VideoDriver_Win32: public VideoDriver { bool MakeWindow(bool full_screen); }; +/** OpenGL video driver for windows. */ +class VideoDriver_Win32OpenGL: public VideoDriver_Win32 { + /* virtual */ const char *Start(const char * const *param); + + /* virtual */ void Stop(); + + /* virtual */ const char *GetName() const { return "win32-opengl"; } +}; + /** The factory for Windows' video driver. */ class FVideoDriver_Win32: public VideoDriverFactory { public: - static const int priority = 10; + static const int priority = 9; /* virtual */ const char *GetName() { return "win32"; } /* virtual */ const char *GetDescription() { return "Win32 GDI Video Driver"; } /* virtual */ Driver *CreateInstance() { return new VideoDriver_Win32(); } }; +/** The factory for Windows' video driver. */ +class FVideoDriver_Win32OpenGL: public VideoDriverFactory { +public: + static const int priority = 10; + /* virtual */ const char *GetName() { return "win32-opengl"; } + /* virtual */ const char *GetDescription() { return "Win32 OpenGL Video Driver"; } + /* virtual */ Driver *CreateInstance() { return new VideoDriver_Win32OpenGL(); } +}; + #endif /* VIDEO_WIN32_H */