src/video/win32_v.cpp
branchgamebalance
changeset 9913 e79cd19772dd
parent 9911 0b8b245a2391
equal deleted inserted replaced
9912:1ac8aac92385 9913:e79cd19772dd
     7 #include "../macros.h"
     7 #include "../macros.h"
     8 #include "../network/network.h"
     8 #include "../network/network.h"
     9 #include "../variables.h"
     9 #include "../variables.h"
    10 #include "../win32.h"
    10 #include "../win32.h"
    11 #include "../window.h"
    11 #include "../window.h"
       
    12 #include "../blitter/factory.hpp"
    12 #include "win32_v.h"
    13 #include "win32_v.h"
    13 #include <windows.h>
    14 #include <windows.h>
    14 #include <tchar.h>
    15 #include <tchar.h>
    15 
    16 
    16 static struct {
    17 static struct {
    17 	HWND main_wnd;
    18 	HWND main_wnd;
    18 	HBITMAP dib_sect;
    19 	HBITMAP dib_sect;
    19 	Pixel *bitmap_bits;
    20 	void *buffer_bits;
    20 	Pixel *buffer_bits;
       
    21 	Pixel *alloced_bits;
       
    22 	HPALETTE gdi_palette;
    21 	HPALETTE gdi_palette;
    23 	int width;
    22 	int width;
    24 	int height;
    23 	int height;
    25 	int width_org;
    24 	int width_org;
    26 	int height_org;
    25 	int height_org;
       
    26 	bool minimized;
    27 	bool fullscreen;
    27 	bool fullscreen;
    28 	bool double_size;
       
    29 	bool has_focus;
    28 	bool has_focus;
    30 	bool running;
    29 	bool running;
    31 } _wnd;
    30 } _wnd;
    32 
    31 
    33 bool _force_full_redraw;
    32 bool _force_full_redraw;
    34 bool _double_size;
       
    35 bool _window_maximize;
    33 bool _window_maximize;
    36 uint _display_hz;
    34 uint _display_hz;
    37 uint _fullscreen_bpp;
    35 uint _fullscreen_bpp;
    38 static uint16 _bck_resolution[2];
    36 static uint16 _bck_resolution[2];
       
    37 #if !defined(WINCE)
       
    38 static DEVMODE _fullscreen_dm;
       
    39 #endif
    39 #if !defined(UNICODE)
    40 #if !defined(UNICODE)
    40 uint _codepage;
    41 uint _codepage;
    41 #endif
    42 #endif
    42 
    43 
    43 static void MakePalette()
    44 static void MakePalette()
    61 	if (_wnd.gdi_palette == NULL) error("CreatePalette failed!\n");
    62 	if (_wnd.gdi_palette == NULL) error("CreatePalette failed!\n");
    62 }
    63 }
    63 
    64 
    64 static void UpdatePalette(HDC dc, uint start, uint count)
    65 static void UpdatePalette(HDC dc, uint start, uint count)
    65 {
    66 {
       
    67 	/* We can only update the palette in 8bpp for now */
       
    68 	/* TODO -- We need support for other bpps too! */
       
    69 	if (BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() != 8) return;
       
    70 
    66 	RGBQUAD rgb[256];
    71 	RGBQUAD rgb[256];
    67 	uint i;
    72 	uint i;
    68 
    73 
    69 	for (i = 0; i != count; i++) {
    74 	for (i = 0; i != count; i++) {
    70 		rgb[i].rgbRed   = _cur_palette[start + i].r;
    75 		rgb[i].rgbRed   = _cur_palette[start + i].r;
   134 
   139 
   135 static bool AllocateDibSection(int w, int h);
   140 static bool AllocateDibSection(int w, int h);
   136 
   141 
   137 static void ClientSizeChanged(int w, int h)
   142 static void ClientSizeChanged(int w, int h)
   138 {
   143 {
   139 	if (_wnd.double_size) {
       
   140 		w /= 2;
       
   141 		h /= 2;
       
   142 	}
       
   143 
       
   144 	// allocate new dib section of the new size
   144 	// allocate new dib section of the new size
   145 	if (AllocateDibSection(w, h)) {
   145 	if (AllocateDibSection(w, h)) {
   146 		// mark all palette colors dirty
   146 		// mark all palette colors dirty
   147 		_pal_first_dirty = 0;
   147 		_pal_first_dirty = 0;
   148 		_pal_last_dirty = 255;
   148 		_pal_last_dirty = 255;
   317 				SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, (TIMERPROC)TrackMouseTimerProc);
   317 				SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, (TIMERPROC)TrackMouseTimerProc);
   318 
   318 
   319 				DrawMouseCursor();
   319 				DrawMouseCursor();
   320 			}
   320 			}
   321 
   321 
   322 			if (_wnd.double_size) {
       
   323 				x /= 2;
       
   324 				y /= 2;
       
   325 			}
       
   326 
       
   327 			if (_cursor.fix_at) {
   322 			if (_cursor.fix_at) {
   328 				int dx = x - _cursor.pos.x;
   323 				int dx = x - _cursor.pos.x;
   329 				int dy = y - _cursor.pos.y;
   324 				int dy = y - _cursor.pos.y;
   330 				if (dx != 0 || dy != 0) {
   325 				if (dx != 0 || dy != 0) {
   331 					_cursor.delta.x += dx;
   326 					_cursor.delta.x += dx;
   332 					_cursor.delta.y += dy;
   327 					_cursor.delta.y += dy;
   333 
   328 
   334 					pt.x = _cursor.pos.x;
   329 					pt.x = _cursor.pos.x;
   335 					pt.y = _cursor.pos.y;
   330 					pt.y = _cursor.pos.y;
   336 
   331 
   337 					if (_wnd.double_size) {
       
   338 						pt.x *= 2;
       
   339 						pt.y *= 2;
       
   340 					}
       
   341 					ClientToScreen(hwnd, &pt);
   332 					ClientToScreen(hwnd, &pt);
   342 					SetCursorPos(pt.x, pt.y);
   333 					SetCursorPos(pt.x, pt.y);
   343 				}
   334 				}
   344 			} else {
   335 			} else {
   345 				_cursor.delta.x += x - _cursor.pos.x;
   336 				_cursor.delta.x += x - _cursor.pos.x;
   398 
   389 
   399 			/* Silently drop all text messages as those will be handled by WM_CHAR
   390 			/* Silently drop all text messages as those will be handled by WM_CHAR
   400 			 * WM_KEYDOWN only handles CTRL+ commands and special keys like VK_LEFT, etc. */
   391 			 * WM_KEYDOWN only handles CTRL+ commands and special keys like VK_LEFT, etc. */
   401 			if (keycode == 0 || (keycode > WKC_PAUSE && GB(keycode, 13, 4) == 0)) return 0;
   392 			if (keycode == 0 || (keycode > WKC_PAUSE && GB(keycode, 13, 4) == 0)) return 0;
   402 
   393 
   403 			if (keycode == ('D' | WKC_CTRL) && !_wnd.fullscreen) {
       
   404 				_double_size ^= 1;
       
   405 				_wnd.double_size = _double_size;
       
   406 				ClientSizeChanged(_wnd.width, _wnd.height);
       
   407 				MarkWholeScreenDirty();
       
   408 			}
       
   409 
       
   410 			HandleKeypress(0 | (keycode << 16));
   394 			HandleKeypress(0 | (keycode << 16));
   411 			return 0;
   395 			return 0;
   412 		}
   396 		}
   413 
   397 
   414 		case WM_SYSKEYDOWN: /* user presses F10 or Alt, both activating the title-menu */
   398 		case WM_SYSKEYDOWN: /* user presses F10 or Alt, both activating the title-menu */
   430 					break;
   414 					break;
   431 			}
   415 			}
   432 			break;
   416 			break;
   433 
   417 
   434 		case WM_SIZE:
   418 		case WM_SIZE:
   435 			if (wParam != SIZE_MINIMIZED) {
   419 			_wnd.minimized = (wParam == SIZE_MINIMIZED);
       
   420 			if (!_wnd.minimized) {
   436 				/* Set maximized flag when we maximize (obviously), but also when we
   421 				/* Set maximized flag when we maximize (obviously), but also when we
   437 				 * switched to fullscreen from a maximized state */
   422 				 * switched to fullscreen from a maximized state */
   438 				_window_maximize = (wParam == SIZE_MAXIMIZED || (_window_maximize && _fullscreen));
   423 				_window_maximize = (wParam == SIZE_MAXIMIZED || (_window_maximize && _fullscreen));
   439 				if (_window_maximize) {
   424 				if (_window_maximize) {
   440 					_bck_resolution[0] = _cur_resolution[0];
   425 					_bck_resolution[0] = _cur_resolution[0];
   453 			SetRect(&r2, 0, 0, 0, 0);
   438 			SetRect(&r2, 0, 0, 0, 0);
   454 			AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
   439 			AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
   455 
   440 
   456 			w = r->right - r->left - (r2.right - r2.left);
   441 			w = r->right - r->left - (r2.right - r2.left);
   457 			h = r->bottom - r->top - (r2.bottom - r2.top);
   442 			h = r->bottom - r->top - (r2.bottom - r2.top);
   458 			if (_wnd.double_size) {
       
   459 				w /= 2;
       
   460 				h /= 2;
       
   461 			}
       
   462 			w = clamp(w, 64, MAX_SCREEN_WIDTH);
   443 			w = clamp(w, 64, MAX_SCREEN_WIDTH);
   463 			h = clamp(h, 64, MAX_SCREEN_HEIGHT);
   444 			h = clamp(h, 64, MAX_SCREEN_HEIGHT);
   464 			if (_wnd.double_size) {
       
   465 				w *= 2;
       
   466 				h *= 2;
       
   467 			}
       
   468 			SetRect(&r2, 0, 0, w, h);
   445 			SetRect(&r2, 0, 0, w, h);
   469 
   446 
   470 			AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
   447 			AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
   471 			w = r2.right - r2.left;
   448 			w = r2.right - r2.left;
   472 			h = r2.bottom - r2.top;
   449 			h = r2.bottom - r2.top;
   532 			return 0;
   509 			return 0;
   533 		}
   510 		}
   534 
   511 
   535 		case WM_ACTIVATEAPP:
   512 		case WM_ACTIVATEAPP:
   536 			_wnd.has_focus = (wParam != 0);
   513 			_wnd.has_focus = (wParam != 0);
       
   514 #if !defined(WINCE)
       
   515 			if (_wnd.fullscreen) {
       
   516 				if (_wnd.has_focus && _wnd.minimized) {
       
   517 					/* Restore the game window */
       
   518 					ShowWindow(hwnd, SW_RESTORE);
       
   519 					ChangeDisplaySettings(&_fullscreen_dm, CDS_FULLSCREEN);
       
   520 					/* Force palette update */
       
   521 					SendMessage(hwnd, WM_QUERYNEWPALETTE, 0, 0);
       
   522 				} else if (!_wnd.has_focus && !_wnd.minimized) {
       
   523 					/* Minimise the window and restore desktop */
       
   524 					ShowWindow(hwnd, SW_MINIMIZE);
       
   525 					ChangeDisplaySettings(NULL, 0);
       
   526 				}
       
   527 			}
       
   528 #endif
   537 			break;
   529 			break;
   538 	}
   530 	}
   539 	return DefWindowProc(hwnd, msg, wParam, lParam);
   531 	return DefWindowProc(hwnd, msg, wParam, lParam);
   540 }
   532 }
   541 
   533 
   565 
   557 
   566 static void MakeWindow(bool full_screen)
   558 static void MakeWindow(bool full_screen)
   567 {
   559 {
   568 	_fullscreen = full_screen;
   560 	_fullscreen = full_screen;
   569 
   561 
   570 	_wnd.double_size = _double_size && !full_screen;
       
   571 
       
   572 	// recreate window?
   562 	// recreate window?
   573 	if ((full_screen || _wnd.fullscreen) && _wnd.main_wnd) {
   563 	if ((full_screen || _wnd.fullscreen) && _wnd.main_wnd) {
   574 		DestroyWindow(_wnd.main_wnd);
   564 		DestroyWindow(_wnd.main_wnd);
   575 		_wnd.main_wnd = 0;
   565 		_wnd.main_wnd = 0;
   576 	}
   566 	}
   577 
   567 
   578 #if defined(WINCE)
   568 #if defined(WINCE)
   579 	/* WinCE is always fullscreen */
   569 	/* WinCE is always fullscreen */
   580 #else
   570 #else
   581 	if (full_screen) {
   571 	if (full_screen) {
   582 		DEVMODE settings;
   572 		/* Make sure we are always at least the screen-depth of the blitter */
   583 
   573 		if (_fullscreen_bpp < BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth()) _fullscreen_bpp = BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth();
   584 		memset(&settings, 0, sizeof(settings));
   574 
   585 		settings.dmSize = sizeof(settings);
   575 		memset(&_fullscreen_dm, 0, sizeof(_fullscreen_dm));
   586 		settings.dmFields =
   576 		_fullscreen_dm.dmSize = sizeof(_fullscreen_dm);
       
   577 		_fullscreen_dm.dmFields =
   587 			(_fullscreen_bpp != 0 ? DM_BITSPERPEL : 0) |
   578 			(_fullscreen_bpp != 0 ? DM_BITSPERPEL : 0) |
   588 			DM_PELSWIDTH |
   579 			DM_PELSWIDTH |
   589 			DM_PELSHEIGHT |
   580 			DM_PELSHEIGHT |
   590 			(_display_hz != 0 ? DM_DISPLAYFREQUENCY : 0);
   581 			(_display_hz != 0 ? DM_DISPLAYFREQUENCY : 0);
   591 		settings.dmBitsPerPel = _fullscreen_bpp;
   582 		_fullscreen_dm.dmBitsPerPel = _fullscreen_bpp;
   592 		settings.dmPelsWidth  = _wnd.width_org;
   583 		_fullscreen_dm.dmPelsWidth  = _wnd.width_org;
   593 		settings.dmPelsHeight = _wnd.height_org;
   584 		_fullscreen_dm.dmPelsHeight = _wnd.height_org;
   594 		settings.dmDisplayFrequency = _display_hz;
   585 		_fullscreen_dm.dmDisplayFrequency = _display_hz;
   595 
   586 
   596 		if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
   587 		if (ChangeDisplaySettings(&_fullscreen_dm, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
   597 			MakeWindow(false);
   588 			MakeWindow(false);
   598 			return;
   589 			return;
   599 		}
   590 		}
   600 	} else if (_wnd.fullscreen) {
   591 	} else if (_wnd.fullscreen) {
   601 		// restore display?
   592 		// restore display?
   647 
   638 
   648 static bool AllocateDibSection(int w, int h)
   639 static bool AllocateDibSection(int w, int h)
   649 {
   640 {
   650 	BITMAPINFO *bi;
   641 	BITMAPINFO *bi;
   651 	HDC dc;
   642 	HDC dc;
       
   643 	int bpp = BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth();
   652 
   644 
   653 	w = clamp(w, 64, MAX_SCREEN_WIDTH);
   645 	w = clamp(w, 64, MAX_SCREEN_WIDTH);
   654 	h = clamp(h, 64, MAX_SCREEN_HEIGHT);
   646 	h = clamp(h, 64, MAX_SCREEN_HEIGHT);
       
   647 
       
   648 	if (bpp == 0) error("Can't use a blitter that blits 0 bpp for normal visuals");
   655 
   649 
   656 	if (w == _screen.width && h == _screen.height)
   650 	if (w == _screen.width && h == _screen.height)
   657 		return false;
   651 		return false;
   658 
   652 
   659 	_screen.width = w;
   653 	_screen.width = w;
   660 	_screen.pitch = ALIGN(w, 4);
   654 	_screen.pitch = ALIGN(w, 4);
   661 	_screen.height = h;
   655 	_screen.height = h;
   662 
       
   663 	if (_wnd.alloced_bits) {
       
   664 		free(_wnd.alloced_bits);
       
   665 		_wnd.alloced_bits = NULL;
       
   666 	}
       
   667 
       
   668 	bi = (BITMAPINFO*)alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);
   656 	bi = (BITMAPINFO*)alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);
   669 	memset(bi, 0, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);
   657 	memset(bi, 0, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);
   670 	bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
   658 	bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
   671 
   659 
   672 	if (_wnd.double_size) {
       
   673 		w = ALIGN(w, 4);
       
   674 		_wnd.alloced_bits = _wnd.buffer_bits = (Pixel *)malloc(w * h * sizeof(Pixel));
       
   675 		w *= 2;
       
   676 		h *= 2;
       
   677 	}
       
   678 
       
   679 	bi->bmiHeader.biWidth = _wnd.width = w;
   660 	bi->bmiHeader.biWidth = _wnd.width = w;
   680 	bi->bmiHeader.biHeight = -(_wnd.height = h);
   661 	bi->bmiHeader.biHeight = -(_wnd.height = h);
   681 
   662 
   682 	bi->bmiHeader.biPlanes = 1;
   663 	bi->bmiHeader.biPlanes = 1;
   683 	bi->bmiHeader.biBitCount = 8;
   664 	bi->bmiHeader.biBitCount = BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth();
   684 	bi->bmiHeader.biCompression = BI_RGB;
   665 	bi->bmiHeader.biCompression = BI_RGB;
   685 
   666 
   686 	if (_wnd.dib_sect) DeleteObject(_wnd.dib_sect);
   667 	if (_wnd.dib_sect) DeleteObject(_wnd.dib_sect);
   687 
   668 
   688 	dc = GetDC(0);
   669 	dc = GetDC(0);
   689 	_wnd.dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID**)&_wnd.bitmap_bits, NULL, 0);
   670 	_wnd.dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID**)&_wnd.buffer_bits, NULL, 0);
   690 	if (_wnd.dib_sect == NULL) error("CreateDIBSection failed");
   671 	if (_wnd.dib_sect == NULL) error("CreateDIBSection failed");
   691 	ReleaseDC(0, dc);
   672 	ReleaseDC(0, dc);
   692 
       
   693 	if (!_wnd.double_size) _wnd.buffer_bits = _wnd.bitmap_bits;
       
   694 
   673 
   695 	return true;
   674 	return true;
   696 }
   675 }
   697 
   676 
   698 static const uint16 default_resolutions[][2] = {
   677 static const uint16 default_resolutions[][2] = {
   721 
   700 
   722 	/* XXX - EnumDisplaySettingsW crashes with unicows.dll on Windows95
   701 	/* XXX - EnumDisplaySettingsW crashes with unicows.dll on Windows95
   723 	 * Doesn't really matter since we don't pass a string anyways, but still
   702 	 * Doesn't really matter since we don't pass a string anyways, but still
   724 	 * a letdown */
   703 	 * a letdown */
   725 	for (i = 0; EnumDisplaySettingsA(NULL, i, &dm) != 0; i++) {
   704 	for (i = 0; EnumDisplaySettingsA(NULL, i, &dm) != 0; i++) {
   726 		if (dm.dmBitsPerPel == 8 && IS_INT_INSIDE(dm.dmPelsWidth, 640, MAX_SCREEN_WIDTH + 1) &&
   705 		if (dm.dmBitsPerPel == BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() && IS_INT_INSIDE(dm.dmPelsWidth, 640, MAX_SCREEN_WIDTH + 1) &&
   727 				IS_INT_INSIDE(dm.dmPelsHeight, 480, MAX_SCREEN_HEIGHT + 1)) {
   706 				IS_INT_INSIDE(dm.dmPelsHeight, 480, MAX_SCREEN_HEIGHT + 1)) {
   728 			uint j;
   707 			uint j;
   729 
   708 
   730 			for (j = 0; j < n; j++) {
   709 			for (j = 0; j < n; j++) {
   731 				if (_resolutions[j][0] == dm.dmPelsWidth && _resolutions[j][1] == dm.dmPelsHeight) break;
   710 				if (_resolutions[j][0] == dm.dmPelsWidth && _resolutions[j][1] == dm.dmPelsHeight) break;
   784 	DestroyWindow(_wnd.main_wnd);
   763 	DestroyWindow(_wnd.main_wnd);
   785 
   764 
   786 #if !defined(WINCE)
   765 #if !defined(WINCE)
   787 	if (_wnd.fullscreen) ChangeDisplaySettings(NULL, 0);
   766 	if (_wnd.fullscreen) ChangeDisplaySettings(NULL, 0);
   788 #endif
   767 #endif
   789 	if (_wnd.double_size) {
       
   790 		_cur_resolution[0] *= 2;
       
   791 		_cur_resolution[1] *= 2;
       
   792 	}
       
   793 
       
   794 	MyShowCursor(true);
   768 	MyShowCursor(true);
   795 }
   769 }
   796 
   770 
   797 // simple upscaler by 2
       
   798 static void filter(int left, int top, int width, int height)
       
   799 {
       
   800 	uint p = _screen.pitch;
       
   801 	const Pixel *s = _wnd.buffer_bits + top * p + left;
       
   802 	Pixel *d = _wnd.bitmap_bits + top * p * 4 + left * 2;
       
   803 
       
   804 	for (; height > 0; height--) {
       
   805 		int i;
       
   806 
       
   807 		for (i = 0; i != width; i++) {
       
   808 			d[i * 2] = d[i * 2 + 1] = d[i * 2 + p * 2] = d[i * 2 + 1 + p * 2] = s[i];
       
   809 		}
       
   810 		s += p;
       
   811 		d += p * 4;
       
   812 	}
       
   813 }
       
   814 
       
   815 static void Win32GdiMakeDirty(int left, int top, int width, int height)
   771 static void Win32GdiMakeDirty(int left, int top, int width, int height)
   816 {
   772 {
   817 	RECT r = { left, top, left + width, top + height };
   773 	RECT r = { left, top, left + width, top + height };
   818 
   774 
   819 	if (_wnd.double_size) {
       
   820 		filter(left, top, width, height);
       
   821 		r.left *= 2;
       
   822 		r.top *= 2;
       
   823 		r.right *= 2;
       
   824 		r.bottom *= 2;
       
   825 	}
       
   826 	InvalidateRect(_wnd.main_wnd, &r, FALSE);
   775 	InvalidateRect(_wnd.main_wnd, &r, FALSE);
   827 }
   776 }
   828 
   777 
   829 static void CheckPaletteAnim()
   778 static void CheckPaletteAnim()
   830 {
   779 {