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 { |