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 */