t7x/src/client/component/splash.cpp

211 lines
4.8 KiB
C++
Raw Normal View History

2022-05-21 06:04:08 -04:00
#include <std_include.hpp>
#include "loader/component_loader.hpp"
2022-06-16 06:12:36 -04:00
#include "splash.hpp"
2022-05-21 06:04:08 -04:00
#include "resource.hpp"
#include <utils/nt.hpp>
namespace splash
{
2022-05-23 11:57:45 -04:00
namespace
{
HANDLE load_splash_image()
{
const auto self = utils::nt::library::get_by_address(load_splash_image);
return LoadImageA(self, MAKEINTRESOURCE(IMAGE_SPLASH), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
}
2022-05-29 10:46:49 -04:00
void enable_dpi_awareness()
{
2022-05-30 12:14:12 -04:00
const utils::nt::library user32{"user32.dll"};
2022-05-29 10:46:49 -04:00
const auto set_dpi = user32
2022-05-30 12:14:12 -04:00
? user32.get_proc<BOOL(WINAPI*)(DPI_AWARENESS_CONTEXT)>(
"SetProcessDpiAwarenessContext")
: nullptr;
2022-05-29 10:46:49 -04:00
if (set_dpi)
{
set_dpi(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}
}
2022-05-23 11:57:45 -04:00
}
2022-05-21 06:04:08 -04:00
class component final : public component_interface
{
public:
2022-05-29 10:46:49 -04:00
component()
2022-05-29 12:23:52 -04:00
: image_(load_splash_image())
2022-05-21 06:04:08 -04:00
{
2022-05-29 10:46:49 -04:00
enable_dpi_awareness();
2022-06-16 06:12:36 -04:00
this->window_thread_ = std::thread([this]
{
this->draw();
});
2022-05-21 06:04:08 -04:00
}
2022-06-16 06:12:36 -04:00
~component()
2022-05-29 12:51:24 -04:00
{
2022-06-16 06:12:36 -04:00
if (this->window_thread_.joinable())
{
this->window_thread_.detach();
}
2022-05-29 12:51:24 -04:00
}
2022-05-21 06:04:08 -04:00
void pre_destroy() override
{
this->destroy();
}
2022-05-23 11:57:45 -04:00
void post_unpack() override
2022-05-21 06:04:08 -04:00
{
2022-05-23 11:57:45 -04:00
this->destroy();
2022-05-21 06:04:08 -04:00
}
2022-06-16 06:12:36 -04:00
void hide() const
{
if (this->window_ && IsWindow(this->window_))
{
ShowWindow(this->window_, SW_HIDE);
UpdateWindow(this->window_);
}
}
2022-05-21 06:04:08 -04:00
private:
2022-06-16 06:12:36 -04:00
std::atomic_bool join_safe_{false};
2022-05-21 06:04:08 -04:00
HWND window_{};
HANDLE image_{};
2022-06-16 06:12:36 -04:00
std::thread window_thread_{};
2022-05-21 06:04:08 -04:00
2022-06-16 06:12:36 -04:00
void destroy()
2022-05-30 12:14:12 -04:00
{
2022-06-16 06:12:36 -04:00
if (this->window_ && IsWindow(this->window_))
2022-05-30 12:14:12 -04:00
{
2022-06-16 06:12:36 -04:00
ShowWindow(this->window_, SW_HIDE);
DestroyWindow(this->window_);
this->window_ = nullptr;
if (this->window_thread_.joinable())
{
this->window_thread_.join();
}
this->window_ = nullptr;
2022-05-30 12:14:12 -04:00
}
}
2022-06-16 06:12:36 -04:00
void draw()
2022-05-21 06:04:08 -04:00
{
2022-06-16 06:12:36 -04:00
this->show();
while (this->draw_frame())
2022-05-21 06:04:08 -04:00
{
2022-06-16 06:12:36 -04:00
std::this_thread::sleep_for(1ms);
2022-05-21 06:04:08 -04:00
}
2022-06-16 06:12:36 -04:00
this->window_ = nullptr;
UnregisterClassA("Black Ops III Splash Screen", utils::nt::library{});
}
bool draw_frame() const
{
if (!this->window_)
{
return false;
}
MSG msg{};
bool success = true;
while (PeekMessageW(&msg, nullptr, NULL, NULL, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
if (msg.message == WM_DESTROY && msg.hwnd == this->window_)
{
PostQuitMessage(0);
}
if (msg.message == WM_QUIT)
{
success = false;
}
}
return success;
2022-05-21 06:04:08 -04:00
}
void show()
{
WNDCLASSA wnd_class;
2022-05-23 11:57:45 -04:00
const utils::nt::library host{};
2022-05-21 06:04:08 -04:00
wnd_class.style = CS_DROPSHADOW;
wnd_class.cbClsExtra = 0;
wnd_class.cbWndExtra = 0;
wnd_class.lpszMenuName = nullptr;
wnd_class.lpfnWndProc = DefWindowProcA;
wnd_class.hInstance = host;
2022-05-29 12:51:24 -04:00
wnd_class.hIcon = LoadIconA(host, MAKEINTRESOURCEA(1));
2022-05-21 06:04:08 -04:00
wnd_class.hCursor = LoadCursorA(nullptr, IDC_APPSTARTING);
wnd_class.hbrBackground = reinterpret_cast<HBRUSH>(6);
wnd_class.lpszClassName = "Black Ops III Splash Screen";
if (RegisterClassA(&wnd_class))
{
const auto x_pixels = GetSystemMetrics(SM_CXFULLSCREEN);
const auto y_pixels = GetSystemMetrics(SM_CYFULLSCREEN);
if (image_)
{
this->window_ = CreateWindowExA(WS_EX_APPWINDOW, "Black Ops III Splash Screen", "BOIII",
WS_POPUP | WS_SYSMENU,
(x_pixels - 320) / 2, (y_pixels - 100) / 2, 320, 100, nullptr,
nullptr,
host, nullptr);
if (this->window_)
{
auto* const image_window = CreateWindowExA(0, "Static", nullptr, WS_CHILD | WS_VISIBLE | 0xEu,
0, 0,
320, 100, this->window_, nullptr, host, nullptr);
if (image_window)
{
RECT rect;
SendMessageA(image_window, 0x172u, 0, reinterpret_cast<LPARAM>(image_));
GetWindowRect(image_window, &rect);
const int width = rect.right - rect.left;
rect.left = (x_pixels - width) / 2;
const int height = rect.bottom - rect.top;
rect.top = (y_pixels - height) / 2;
rect.right = rect.left + width;
rect.bottom = rect.top + height;
AdjustWindowRect(&rect, WS_CHILD | WS_VISIBLE | 0xEu, 0);
SetWindowPos(this->window_, nullptr, rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top, SWP_NOZORDER);
2022-05-30 12:14:12 -04:00
SetWindowRgn(this->window_,
CreateRoundRectRgn(0, 0, rect.right - rect.left, rect.bottom - rect.top, 15,
15), TRUE);
2022-05-29 12:51:24 -04:00
2022-05-21 06:04:08 -04:00
ShowWindow(this->window_, SW_SHOW);
UpdateWindow(this->window_);
}
}
}
}
}
};
2022-06-16 06:12:36 -04:00
void hide()
{
auto* splash_component = component_loader::get<component>();
if (splash_component)
{
splash_component->hide();
}
}
2022-05-21 06:04:08 -04:00
}
REGISTER_COMPONENT(splash::component)