diff options
author | Aki <please@ignore.pl> | 2022-04-01 21:23:39 +0200 |
---|---|---|
committer | Aki <please@ignore.pl> | 2022-04-01 21:23:39 +0200 |
commit | 3c487c5cd69c53d6fea948643c0a76df03516605 (patch) | |
tree | 72730c7b8b26a5ef8fc9a987ec4c16129efd5aac /StarsEx/GameWinDX9.cpp | |
parent | 8f353abd0bfe18baddd8a8250ab7c4f2d1c83a6e (diff) | |
download | starshatter-3c487c5cd69c53d6fea948643c0a76df03516605.zip starshatter-3c487c5cd69c53d6fea948643c0a76df03516605.tar.gz starshatter-3c487c5cd69c53d6fea948643c0a76df03516605.tar.bz2 |
Moved Stars45 to StarsEx
Diffstat (limited to 'StarsEx/GameWinDX9.cpp')
-rw-r--r-- | StarsEx/GameWinDX9.cpp | 662 |
1 files changed, 662 insertions, 0 deletions
diff --git a/StarsEx/GameWinDX9.cpp b/StarsEx/GameWinDX9.cpp new file mode 100644 index 0000000..5d04c97 --- /dev/null +++ b/StarsEx/GameWinDX9.cpp @@ -0,0 +1,662 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. +*/ + +#include "GameWinDX9.h" + +#include <stdio.h> +#include <string.h> + +#include "Bitmap.h" +#include "Clock.h" +#include "Color.h" +#include "DataLoader.h" +#include "Game.h" +#include "MachineInfo.h" +#include "Panic.h" +#include "Screen.h" +#include "Types.h" +#include "Utils.h" +#include "VideoFactory.h" +#include "Video.h" + + +GameWinDX9* GameWinDX9::instance = nullptr; + + +GameWinDX9* +GameWinDX9::GetInstance() +{ + return instance; +} + + +GameWinDX9::GameWinDX9() : + max_tex_size {2048}, + screen_color {Color::Black}, + hInst{nullptr}, + hwnd{nullptr}, + is_windowed {false}, + is_active {false}, + is_device_lost {false}, + is_minimized {false}, + is_maximized {false}, + ignore_size_change {false}, + is_device_initialized {false}, + is_device_restored {false} +{ + if (instance != nullptr) + Panic::Panic("Multiple instances of GameWinDX9"); + instance = this; +} + + +GameWinDX9::~GameWinDX9() +{ + if (instance != nullptr) + instance = nullptr; +} + + +bool +GameWinDX9::Init(HINSTANCE hi, HINSTANCE hpi, LPSTR cmdline, int nCmdShow) +{ + status = OK; + hInst = hi; + + Print(" Initializing Game\n"); + + stats.Clear(); + + if (!InitApplication(hInst)) { // Initialize shared things + Panic::Panic("Could not initialize the application."); + status = INIT_FAILED; + } + + if (status == OK && !video_settings) { + Panic::Panic("No video settings specified"); + status = INIT_FAILED; + } + + if (status == OK) { + static int os_version = MachineInfo::GetPlatform(); + + if (os_version == MachineInfo::OS_WIN95 || os_version == MachineInfo::OS_WIN98) { + Panic::Panic(" Windows 95 and 98 are no longer supported. Please update to Windows XP or higher."); + status = INIT_FAILED; + } else if (os_version == MachineInfo::OS_WINNT) { + Panic::Panic(" D3D not available under WinNT 4"); + status = INIT_FAILED; + } else if (MachineInfo::GetDirectXVersion() < MachineInfo::DX_9) { + Panic::Panic(" Insufficient DirectX detected (Dx9 IS REQUIRED)"); + status = INIT_FAILED; + } + } + + if (status == OK) { + Print("\n Initializing instance...\n"); + // Perform initializations that apply to a specific instance + if (!InitInstance(hInst, nCmdShow)) { + Panic::Panic("Could not initialize the instance."); + status = INIT_FAILED; + } + } + + if (status != OK) + return false; + return Game::Init(hi, hpi, cmdline, nCmdShow); +} + + +bool +GameWinDX9::InitApplication(HINSTANCE hInstance) +{ + WNDCLASS wc; + LOGBRUSH brush = { BS_SOLID, RGB(0,0,0), 0 }; + + if (server) + brush.lbColor = RGB(255,255,255); + + // Fill in window class structure with parameters that + // describe the main window. + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = (WNDPROC) WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(100)); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + + wc.hbrBackground = CreateBrushIndirect(&brush); + wc.lpszMenuName = app_name; + wc.lpszClassName = app_name; + + // Register the window class and return success/failure code. + if (RegisterClass(&wc) == 0) { + DWORD err = GetLastError(); + + if (err == 1410) // class already exists, this is OK + return true; + + else + Print("WARNING: Register Window Class: %08x\n", err); + } + + return true; +} + + +bool +GameWinDX9::InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + hInst = hInstance; + + // center window on display: + int screenx = GetSystemMetrics(SM_CXSCREEN); + int screeny = GetSystemMetrics(SM_CYSCREEN); + int x_offset = 0; + int y_offset = 0; + int s_width = 800; + int s_height = 600; + + if (server) { + s_width = 320; + s_height = 200; + } + + else if (video_settings) { + s_width = video_settings->window_width; + s_height = video_settings->window_height; + } + + if (s_width < screenx) + x_offset = (screenx - s_width) / 2; + + if (s_height < screeny) + y_offset = (screeny - s_height) / 2; + + // Create a main window for this application instance + RECT rctmp; + rctmp.left = x_offset; + rctmp.top = y_offset; + rctmp.right = x_offset + s_width; + rctmp.bottom = y_offset + s_height; + + window_style = + WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | + WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE; + + AdjustWindowRect(&rctmp, window_style, 1); + + hwnd = CreateWindow( + app_name, // Class name + app_name, // Caption + window_style, + x_offset, // Position + y_offset, + rctmp.right - rctmp.left, // Size + rctmp.bottom - rctmp.top, + 0, // Parent window (no parent) + 0, // use class menu + hInst, // handle to window instance + 0); // no params to pass on + + // If window could not be created, return "failure" + if (!hwnd) { + Panic::Panic("Could not create window\n"); + return false; + } + + Print(" Window created.\n"); + + // Make the window visible and draw it + ShowWindow(hwnd, nCmdShow); // Show the window + UpdateWindow(hwnd); // Sends WM_PAINT message + + // Save window properties + window_style = GetWindowLong(hwnd, GWL_STYLE); + GetWindowRect(hwnd, &bounds_rect); + GetClientRect(hwnd, &client_rect); + + // Use client area to set video window size + video_settings->window_width = client_rect.right - client_rect.left; + video_settings->window_height = client_rect.bottom - client_rect.top; + + Print(" Instance initialized.\n"); + return true; +} + + +bool +GameWinDX9::InitGame() +{ + if (server) return true; + if (!SetupPalette()) { + Panic::Panic("Could not set up the palette."); + return false; + } + Print(" Palette laoded\n"); + if (!InitVideo() || !video || video->Status() != Video::VIDEO_OK) { + Panic::Panic("Could not create the Video Interface"); + return false; + } + Print(" Created video object.\n"); + Color::UseVideo(video); + screen = new Screen(video); + if (!screen) { + Panic::Panic("Could not create the Screen object."); + return false; + } + Print(" Created screen object.\n"); + if (!screen->SetBackgroundColor(Color::Black)) + Print(" WARNING: Could not set video background color to Black.\n"); + screen->ClearAllFrames(true); + Print("Established requested video parameters.\n\n"); + return Game::InitGame(); +} + + +bool +GameWinDX9::InitVideo() +{ + if (server) return true; + + // create a video factory, and video object: + video_factory = new VideoFactory(hwnd); + + if (video_factory) { + Print(" Init Video...\n"); + Print(" Request %s mode\n", video_settings->GetModeDescription()); + + video = video_factory->CreateVideo(video_settings); + + if (video) { + if (!video->IsHardware()) { + video_factory->DestroyVideo(video); + video = 0; + + Panic::Panic("3D Hardware Not Found"); + } + + // save a copy of the device-specific video settings: + else if (video->GetVideoSettings()) { + *video_settings = *video->GetVideoSettings(); + is_windowed = video_settings->IsWindowed(); + } + } + + soundcard = video_factory->CreateSoundCard(); + } + + return (video && video->Status() == Video::VIDEO_OK); +} + + +bool +GameWinDX9::ResetVideo() +{ + if (server) return true; + if (!video_factory) return InitVideo(); + + Print(" Reset Video...\n"); + Print(" Request %s mode\n", video_settings->GetModeDescription()); + + delete screen; + + if (video && !video->Reset(video_settings)) { + video_factory->DestroyVideo(video); + video = video_factory->CreateVideo(video_settings); + } + + if (!video || video->Status() != Video::VIDEO_OK) { + Panic::Panic("Could not re-create Video Interface."); + return false; + } + + Print(" Re-created video object.\n"); + + // save a copy of the device-specific video settings: + if (video->GetVideoSettings()) { + *video_settings = *video->GetVideoSettings(); + is_windowed = video_settings->IsWindowed(); + } + + Color::UseVideo(video); + + screen = new Screen(video); + if (!screen) { + Panic::Panic("Could not re-create Screen object."); + return false; + } + + Print(" Re-created screen object.\n"); + + if (!screen->SetBackgroundColor(Color::Black)) + Print(" WARNING: could not set video background color to Black\n"); + + screen->ClearAllFrames(true); + + Print(" Re-established requested video parameters.\n"); + + Bitmap::CacheUpdate(); + Print(" Refreshed texture bitmaps.\n\n"); + return true; +} + + +bool +GameWinDX9::ResizeVideo() +{ + if (!video || !video_settings) return false; + if (!is_windowed) return false; + if (ignore_size_change) return true; + + HRESULT hr = S_OK; + RECT client_old; + + client_old = client_rect; + + // Update window properties + GetWindowRect(hwnd, &bounds_rect); + GetClientRect(hwnd, &client_rect); + + if (client_old.right - client_old.left != + client_rect.right - client_rect.left || + client_old.bottom - client_old.top != + client_rect.bottom - client_rect.top) { + + // A new window size will require a new backbuffer + // size, so the 3D structures must be changed accordingly. + Pause(true); + + video_settings->is_windowed = true; + video_settings->window_width = client_rect.right - client_rect.left; + video_settings->window_height = client_rect.bottom - client_rect.top; + + ::Print("ResizeVideo() %d x %d\n", video_settings->window_width, video_settings->window_height); + + if (video) { + video->Reset(video_settings); + } + + Pause(false); + } + + // save a copy of the device-specific video settings: + if (video->GetVideoSettings()) { + *video_settings = *video->GetVideoSettings(); + is_windowed = video_settings->IsWindowed(); + } + + screen->Resize(video_settings->window_width, video_settings->window_height); + + return hr == S_OK; +} + + +bool +GameWinDX9::ToggleFullscreen() +{ + bool result = false; + + if (video && video_settings) { + Pause(true); + ignore_size_change = true; + + // Toggle the windowed state + is_windowed = !is_windowed; + video_settings->is_windowed = is_windowed; + + // Prepare window for windowed/fullscreen change + AdjustWindowForChange(); + + // Reset the 3D device + if (!video->Reset(video_settings)) { + // reset failed, try to restore... + ignore_size_change = false; + + if (!is_windowed) { + // Restore window type to windowed mode + is_windowed = !is_windowed; + video_settings->is_windowed = is_windowed; + + AdjustWindowForChange(); + + SetWindowPos(hwnd, + HWND_NOTOPMOST, + bounds_rect.left, + bounds_rect.top, + bounds_rect.right - bounds_rect.left, + bounds_rect.bottom - bounds_rect.top, + SWP_SHOWWINDOW); + } + + ::Print("Unable to toggle %s fullscreen mode.\n", is_windowed ? "into" : "out of"); + } + + else { + ignore_size_change = false; + + // When moving from fullscreen to windowed mode, it is important to + // adjust the window size after resetting the device rather than + // beforehand to ensure that you get the window size you want. For + // example, when switching from 640x480 fullscreen to windowed with + // a 1000x600 window on a 1024x768 desktop, it is impossible to set + // the window size to 1000x600 until after the display mode has + // changed to 1024x768, because windows cannot be larger than the + // desktop. + + if (is_windowed) { + SetWindowPos(hwnd, + HWND_NOTOPMOST, + bounds_rect.left, + bounds_rect.top, + bounds_rect.right - bounds_rect.left, + bounds_rect.bottom - bounds_rect.top, + SWP_SHOWWINDOW); + } + + GetClientRect(hwnd, &client_rect); // Update our copy + Pause(false); + + if (is_windowed) + screen->Resize(video_settings->window_width, + video_settings->window_height); + + else + screen->Resize(video_settings->fullscreen_mode.width, + video_settings->fullscreen_mode.height); + + result = true; + } + } + + return result; +} + + +bool +GameWinDX9::AdjustWindowForChange() +{ + if (is_windowed) { + // Set windowed-mode style + SetWindowLong(hwnd, GWL_STYLE, window_style); + if (hmenu != NULL) { + SetMenu(hwnd, hmenu); + hmenu = NULL; + } + } + else { + // Set fullscreen-mode style + SetWindowLong(hwnd, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE); + if (hmenu == NULL) { + hmenu = GetMenu(hwnd); + SetMenu(hwnd, NULL); + } + } + + return true; +} + + +bool +GameWinDX9::SetupPalette() +{ + if (LoadPalette(standard_palette, inverse_palette)) { + Color::SetPalette(standard_palette, 256, inverse_palette); + return true; + } + + return false; +} + + +bool +GameWinDX9::LoadPalette(PALETTEENTRY* pal, BYTE* inv) +{ + char palheader[32]; + struct { + WORD Version; + WORD NumberOfEntries; + PALETTEENTRY Entries[256]; + } Palette = { 0x300, 256 }; + + DataLoader* loader = DataLoader::GetLoader(); + BYTE* block; + char fname[256]; + sprintf_s(fname, "%s.pal", palette_name); + + if (!loader->LoadBuffer(fname, block)) { + Print(" Could not open file '%s'\n", fname); + return false; + } + + memcpy(&palheader, block, 24); + memcpy((char*) Palette.Entries, (block+24), 256*4); + + for (int i = 0; i < 256; i++) { + *pal++ = Palette.Entries[i]; + } + + loader->ReleaseBuffer(block); + + sprintf_s(fname, "%s.ipl", palette_name); + int size = loader->LoadBuffer(fname, block); + if (size < 32768) { + Print(" Could not open file '%s'\n", fname); + return false; + } + + memcpy(inv, block, 32768); + loader->ReleaseBuffer(block); + + return true; +} + + +int +GameWinDX9::Run() +{ + MSG msg; + status = RUN; + Clock::GetInstance()->Set(); + while (status < EXIT && !Panic::Panicked()) { + if (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) + break; + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else { + if (GameLoop()) + WaitMessage(); + } + } + return exit_code ? exit_code : msg.wParam; +} + + +int +GameWinDX9::MaxTexSize() const +{ + if (video) { + int max_from_video = video->MaxTexSize(); + if (max_from_video < max_tex_size) + return max_from_video; + return max_tex_size; + } + else if (Video* video = Video::GetInstance()) { + return video->MaxTexSize(); + } + return 256; +} + + +int +GameWinDX9::MaxTexAspect() const +{ + if (video) + return video->MaxTexAspect(); + else if (Video* video = Video::GetInstance()) + return video->MaxTexAspect(); + return 1; +} + + +Color +GameWinDX9::GetScreenColor() const +{ + return screen_color; +} + + +int +GameWinDX9::GetScreenWidth() const +{ + if (video) + return video->Width(); + return 0; +} + + +int +GameWinDX9::GetScreenHeight() const +{ + if (video) + return video->Height(); + return 0; +} + + +HINSTANCE +GameWinDX9::GetHINST() +{ + return hInst; +} + + +HWND +GameWinDX9::GetHWND() +{ + return hwnd; +} + + +void +GameWinDX9::SetMaxTexSize(int n) +{ + if (n >= 64 && n <= 4096) + max_tex_size = n; +} + + +void +GameWinDX9::SetScreenColor(Color c) +{ + screen_color = c; + if (screen) + screen->SetBackgroundColor(c); +} |