/* 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 #include #include "Color.h" #include "DataLoader.h" #include "Game.h" #include "MachineInfo.h" #include "Panic.h" #include "Types.h" #include "Utils.h" GameWinDX9* GameWinDX9::instance = nullptr; GameWinDX9* GameWinDX9::GetInstance() { return instance; } GameWinDX9::GameWinDX9() : max_tex_size {2048}, screen_color {Color::Black} { 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"); return Game::InitGame(); } 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::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; } 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); }