summaryrefslogtreecommitdiffhomepage
path: root/StarsEx/GameWinDX9.cpp
diff options
context:
space:
mode:
authorAki <please@ignore.pl>2022-04-01 21:23:39 +0200
committerAki <please@ignore.pl>2022-04-01 21:23:39 +0200
commit3c487c5cd69c53d6fea948643c0a76df03516605 (patch)
tree72730c7b8b26a5ef8fc9a987ec4c16129efd5aac /StarsEx/GameWinDX9.cpp
parent8f353abd0bfe18baddd8a8250ab7c4f2d1c83a6e (diff)
downloadstarshatter-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.cpp662
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);
+}