diff --git a/.gitmodules b/.gitmodules index 76e12692..9e7892ca 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,3 +25,6 @@ [submodule "deps/discord-rpc"] path = deps/discord-rpc url = https://github.com/momo5502/discord-rpc.git +[submodule "deps/stb"] + path = deps/stb + url = https://github.com/nothings/stb.git diff --git a/deps/premake/stb.lua b/deps/premake/stb.lua new file mode 100644 index 00000000..6f20a983 --- /dev/null +++ b/deps/premake/stb.lua @@ -0,0 +1,19 @@ +stb = { + source = path.join(dependencies.basePath, "stb"), +} + +function stb.import() + stb.includes() +end + +function stb.includes() + includedirs { + stb.source + } +end + +function stb.project() + +end + +table.insert(dependencies, stb) diff --git a/deps/stb b/deps/stb new file mode 160000 index 00000000..8b5f1f37 --- /dev/null +++ b/deps/stb @@ -0,0 +1 @@ +Subproject commit 8b5f1f37b5b75829fc72d38e7b5d4bcbf8a26d55 diff --git a/premake5.lua b/premake5.lua index 74a232d0..1bfca583 100644 --- a/premake5.lua +++ b/premake5.lua @@ -312,11 +312,15 @@ project "tlsdll" symbols 'Off' exceptionhandling "Off" + flags {"NoRuntimeChecks", "NoBufferSecurityCheck", "OmitDefaultLibrary"} + buildoptions {"/Zc:threadSafeInit-"} - removebuildoptions {"/GL"} linkoptions {"/NODEFAULTLIB", "/IGNORE:4210"} + removebuildoptions {"/GL"} + removelinkoptions {"/LTCG"} + files {"./src/tlsdll/**.rc", "./src/tlsdll/**.hpp", "./src/tlsdll/**.cpp", "./src/tlsdll/resources/**.*"} includedirs {"./src/tlsdll", "%{prj.location}/src"} diff --git a/src/client/component/console.cpp b/src/client/component/console.cpp index 6493ccc2..43d3e096 100644 --- a/src/client/component/console.cpp +++ b/src/client/component/console.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #define CONSOLE_BUFFER_SIZE 16384 #define WINDOW_WIDTH 608 @@ -15,7 +16,7 @@ namespace console { namespace { - HANDLE logo; + utils::image::object logo; std::atomic_bool started{false}; std::atomic_bool terminate_runner{false}; utils::concurrency::container> message_queue{}; @@ -79,25 +80,8 @@ namespace console INT_PTR get_gray_brush() { - static struct brush - { - HBRUSH hbrush; - - brush() - : hbrush(CreateSolidBrush(RGB(50, 50, 50))) - { - } - - ~brush() - { - if (hbrush) - { - DeleteObject(hbrush); - } - } - } b; - - return reinterpret_cast(b.hbrush); + static utils::image::object b(CreateSolidBrush(RGB(50, 50, 50))); + return reinterpret_cast(b.get()); } LRESULT con_wnd_proc(const HWND hwnd, const UINT msg, const WPARAM wparam, const LPARAM lparam) @@ -185,7 +169,7 @@ namespace console utils::hook::set(game::s_wcd::codLogo, CreateWindowExA( 0, "Static", nullptr, 0x5000000Eu, 5, 5, 0, 0, *game::s_wcd::hWnd, reinterpret_cast(1), h_instance, nullptr)); - SendMessageA(*game::s_wcd::codLogo, 0x172u, 0, reinterpret_cast(logo)); + SendMessageA(*game::s_wcd::codLogo, STM_SETIMAGE, IMAGE_BITMAP, logo); } // create the input line @@ -219,8 +203,12 @@ namespace console utils::hook::jump(0x1423337F0_g, queue_message); utils::hook::nop(0x14233380A_g, 2); // Print from every thread - const auto self = utils::nt::library::get_by_address(sys_create_console_stub); - logo = LoadImageA(self.get_handle(), MAKEINTRESOURCEA(IMAGE_LOGO), 0, 0, 0, LR_COPYFROMRESOURCE); + //const auto self = utils::nt::library::get_by_address(sys_create_console_stub); + //logo = LoadImageA(self.get_handle(), MAKEINTRESOURCEA(IMAGE_LOGO), 0, 0, 0, LR_COPYFROMRESOURCE); + + const auto res = utils::nt::load_resource(IMAGE_LOGO); + const auto img = utils::image::load_image(res); + logo = utils::image::create_bitmap(img); utils::hook::jump(printf, print_stub); diff --git a/src/client/component/splash.cpp b/src/client/component/splash.cpp index 70ac2855..354a8ddd 100644 --- a/src/client/component/splash.cpp +++ b/src/client/component/splash.cpp @@ -5,20 +5,24 @@ #include "resource.hpp" #include +#include namespace splash { namespace { HWND window{}; - HANDLE image{}; + utils::image::object image{}; std::thread window_thread{}; - std::atomic_bool join_safe{false}; - HANDLE load_splash_image() + utils::image::object 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); + //const auto self = utils::nt::library::get_by_address(load_splash_image); + //return LoadImageA(self, MAKEINTRESOURCE(IMAGE_SPLASH), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + + const auto res = utils::nt::load_resource(IMAGE_SPLASH); + const auto img = utils::image::load_image(res); + return utils::image::create_bitmap(img); } void enable_dpi_awareness() @@ -93,7 +97,7 @@ namespace splash if (image_window) { RECT rect; - SendMessageA(image_window, 0x172u, 0, reinterpret_cast(image)); + SendMessageA(image_window, STM_SETIMAGE, IMAGE_BITMAP, image); GetWindowRect(image_window, &rect); const int width = rect.right - rect.left; diff --git a/src/client/resource.rc b/src/client/resource.rc index 92e99f4b..1f74314b 100644 --- a/src/client/resource.rc +++ b/src/client/resource.rc @@ -92,8 +92,8 @@ END // ID_ICON ICON "resources/icon.ico" -IMAGE_SPLASH BITMAP "resources/splash.bmp" -IMAGE_LOGO BITMAP "resources/logo.bmp" +IMAGE_SPLASH RCDATA "resources/splash.jpg" +IMAGE_LOGO RCDATA "resources/logo.jpg" DW_MOTD RCDATA "resources/dw/experiments_tu32.gz" DW_CARDS RCDATA "resources/dw/featured_cards-english_tu32.gz" diff --git a/src/client/resources/icon.ico b/src/client/resources/icon.ico index 8747d929..fa177cfc 100644 Binary files a/src/client/resources/icon.ico and b/src/client/resources/icon.ico differ diff --git a/src/client/resources/logo.bmp b/src/client/resources/logo.bmp deleted file mode 100644 index d62dc9cb..00000000 Binary files a/src/client/resources/logo.bmp and /dev/null differ diff --git a/src/client/resources/logo.jpg b/src/client/resources/logo.jpg new file mode 100644 index 00000000..07a43341 Binary files /dev/null and b/src/client/resources/logo.jpg differ diff --git a/src/client/resources/splash.bmp b/src/client/resources/splash.bmp deleted file mode 100644 index f580ad70..00000000 Binary files a/src/client/resources/splash.bmp and /dev/null differ diff --git a/src/client/resources/splash.jpg b/src/client/resources/splash.jpg new file mode 100644 index 00000000..6a606a18 Binary files /dev/null and b/src/client/resources/splash.jpg differ diff --git a/src/common/utils/image.cpp b/src/common/utils/image.cpp new file mode 100644 index 00000000..3f54018a --- /dev/null +++ b/src/common/utils/image.cpp @@ -0,0 +1,56 @@ +#include "image.hpp" +#include + +#pragma warning(push) +#pragma warning(disable: 4100) +#define STBI_ONLY_JPEG +#define STB_IMAGE_IMPLEMENTATION +#include +#pragma warning(pop) + +#include "finally.hpp" + +namespace utils::image +{ + image load_image(const std::string& data) + { + stbi_uc* buffer{}; + const auto _ = finally([&] + { + if (buffer) + { + stbi_image_free(buffer); + } + }); + + constexpr int channels = 4; + int x, y, channels_in_file; + buffer = stbi_load_from_memory(reinterpret_cast(data.data()), + static_cast(data.size()), &x, &y, &channels_in_file, channels); + if (!buffer) + { + throw std::runtime_error("Failed to load image"); + } + + image res{}; + res.width = static_cast(x); + res.height = static_cast(y); + res.data.assign(reinterpret_cast(buffer), res.width * res.height * channels); + + return res; + } + + object create_bitmap(const image& img) + { + auto copy = img.data; + + for (size_t i = 0; i < (img.width * img.height); ++i) + { + auto& r = copy[i * 4 + 0]; + auto& b = copy[i * 4 + 2]; + std::swap(r, b); + } + + return CreateBitmap(static_cast(img.width), static_cast(img.height), 4, 8, copy.data()); + } +} diff --git a/src/common/utils/image.hpp b/src/common/utils/image.hpp new file mode 100644 index 00000000..2dea7b8b --- /dev/null +++ b/src/common/utils/image.hpp @@ -0,0 +1,89 @@ +#pragma once + +#include +#include "nt.hpp" + +namespace utils::image +{ + struct image + { + size_t width; + size_t height; + std::string data; + }; + + class object + { + public: + object() = default; + + object(const HGDIOBJ h) + : handle_(h) + { + } + + ~object() + { + if (*this) + { + DeleteObject(this->handle_); + this->handle_ = nullptr; + } + } + + object(const object&) = delete; + object& operator=(const object&) = delete; + + object(object&& obj) noexcept + : object() + { + this->operator=(std::move(obj)); + } + + object& operator=(object&& obj) noexcept + { + if (this != &obj) + { + this->~object(); + this->handle_ = obj.handle_; + obj.handle_ = nullptr; + } + + return *this; + } + + object& operator=(HANDLE h) noexcept + { + this->~object(); + this->handle_ = h; + + return *this; + } + + HGDIOBJ get() const + { + return this->handle_; + } + + operator bool() const + { + return this->handle_ != nullptr; + } + + operator HGDIOBJ() const + { + return this->handle_; + } + + operator LPARAM() const + { + return reinterpret_cast(this->handle_); + } + + private: + HGDIOBJ handle_{nullptr}; + }; + + image load_image(const std::string& data); + object create_bitmap(const image& img); +}