.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # SCSP-localify
4 |
5 | 简体中文 | [English](readme_EN.md)
6 |
7 | 偶像大师 闪耀色彩 棱镜之歌 **DMM 版** 本地化插件。
8 |
9 | **注意:使用外部插件属于违反游戏条款的行为。若使用插件后账号被封禁,造成的后果由用户自行承担。**
10 |
11 |
12 |
13 |
14 |
15 | # 使用说明:
16 |
17 | - 将插件本体解压到游戏安装目录内即可 (`version.dll` 和 `imasscprism.exe` 在同一级目录)
18 | - 启动游戏后看见控制台(需打开`enableConsole` )即安装成功
19 |
20 |
21 |
22 | # 功能列表
23 |
24 | - dump 文本
25 |
26 | - 汉化、替换字体
27 | - 解锁帧数
28 | - 切换窗口不暂停
29 | - Free Camera 自由视角
30 | - Live MV 相关 **(在 GUI 中修改)**
31 | - 解锁服装
32 | - 自由选择服装,可以穿别人的衣服
33 | - 允许相同偶像登场
34 |
35 | - 角色身体参数实时修改,可修改 身高、头部、胸部、手臂、手掌 大小 **(在 GUI 中修改)**
36 |
37 |
38 |
39 | # 配置说明
40 |
41 | - 配置项位于 `scsp-config.json` 文件中
42 |
43 | | 配置项 | 类型 | 默认值 | 说明 |
44 | | -------------------------- | ---------------------------------------- | -------------------------------------- | ---------------------------------------------------- |
45 | | enableConsole | Bool | `true` | 是否开启控制台 |
46 | | enableVSync | Bool | `false` | 是否启用垂直同步 |
47 | | maxFps | Int | `60` | 最大帧数
当启用 `enableVSync` 时,此项配置失效 |
48 | | 3DResolutionScale | Float | `1.0` | 3D 渲染分辨率倍率 |
49 | | localifyBasePath | String | `scsp_localify` | 本地化文件目录 |
50 | | hotKey | String (Char) | `u` | 按下 `Ctrl` + 此项配置的热键,**打开插件 GUI** |
51 | | dumpUntransLyrics | Bool | `false` | dump 未翻译的歌词 |
52 | | dumpUntransLocal2 | Bool | `false` | dump 未翻译的文本 |
53 | | autoDumpAllJson | Bool | `false` | dump 所有游戏加载的 JSON |
54 | | extraAssetBundlePaths | String[] | `["scsp_localify/scsp-bundle"]` | 自定义数据包路径 |
55 | | customFontPath | String | `assets/font/sbtphumminge-regular.ttf` | 自定义数据包中字体路径
用于替换游戏内置字体 |
56 | | blockOutOfFocus | Bool | `true` | 拦截窗口失焦事件
切换到其它窗口后不会触发游戏暂停 |
57 | | baseFreeCamera | [BaseFreeCamera](#BaseFreeCamera) Object | [BaseFreeCamera](#BaseFreeCamera) | 自由视角配置 |
58 | | unlockPIdolAndSCharaEvents | Bool | `false` | 解锁 `角色` - `一览` 中的P卡和S卡事件 |
59 | | startResolution | [Resolution](#Resolution) Object | [Resolution](#Resolution) | 启动游戏初始分辨率 |
60 |
61 |
62 |
63 | ### BaseFreeCamera
64 |
65 | | 配置项 | 类型 | 默认值 | 说明 |
66 | | ---------- | ----- | ------- | ------------------ |
67 | | enable | Bool | `false` | 启用自由视角 |
68 | | moveStep | Float | `50` | 摄像机移动速度 |
69 | | mouseSpeed | Float | `35` | 鼠标移动视角灵敏度 |
70 |
71 |
72 |
73 | ### Resolution
74 |
75 | | 配置项 | 类型 | 默认值 | 说明 |
76 | | ------ | ---- | ------- | -------- |
77 | | w | Int | `1280` | 窗口宽度 |
78 | | h | Int | `720` | 窗口高度 |
79 | | isFull | Bool | `false` | 是否全屏 |
80 |
81 |
82 |
83 | # 自由视角说明 (Free Camera)
84 |
85 | - 将 `scsp-config.json` 中 `baseFreeCamera` - `enable` 设置为 `true` 即可。
86 | - 生效范围:所有 3D 场景。包括但不限于主页、故事、Live
87 |
88 |
89 |
90 | ## 自由视角操作方法
91 |
92 | - 移动: `W`, `S`, `A`, `D`
93 | - 上移: `Space`,下移: `Ctrl`
94 | - 摄像头复位: `R`
95 |
96 | - 视角转动:
97 | - 键盘: `↑`, `↓`, `←`, `→`
98 | - 鼠标:
99 | - 按 ` 键(数字键最左边,TAB 键上方)切换
100 | - 或者**按住**鼠标右键
101 | - 调整视场角 (FOV)
102 | - 键盘: `Q`, `E`
103 | - 或者鼠标滚轮
104 |
105 |
106 |
107 | # 如何汉化
108 |
109 | - 将 dumps 目录内的 Json 文件汉化后,放进 `scsp_localify` 目录即可。
110 | - 汉化仓库:[SCSPTranslationData](https://github.com/ShinyGroup/SCSPTranslationData) 欢迎各位贡献自己的翻译~
111 |
112 |
113 |
114 | ## 自行 dump 原文
115 | - 游戏内的 UI 文本大致可以分为三类。
116 |
117 | - 1、通过游戏内的 `Localify` 接口加载
118 |
119 | - 2、不通过 `Localify`接口加载
120 |
121 | - 3、直接通过 Json 加载(这部分不止文本,还有其它诸如镜头数据、人物动作等,插件也支持替换。)
122 |
123 |
124 |
125 | - 第一类对应 `localify.json`
126 |
127 | - 第二类对应 `local2.json` 和 ` lyrics.json`
128 |
129 | - 除此之外的文件都对应第三类
130 |
131 | - (UI 文本一部分走 `Localify`,一部分不走,很奇怪。)
132 |
133 |
134 |
135 | ### 故事和部分 UI 文本 dump
136 | 登录游戏后,进入故事阅读界面,按下 `ctrl` + `u`,会弹出控制窗口,勾选 `Waiting Extract Text`,然后点击任意故事标题,之后会自动 dump 故事文本和 `localify.json`
137 |
138 |
139 |
140 | ### 歌词和另一部分 UI 文本 dump
141 | 将 `scsp-config.json` 内 `dumpUntransLyrics` 和 `dumpUntransLocal2` 设置为 `true`,然后打开游戏。插件会实时将未翻译的部分 dump 到 Json 中。
--------------------------------------------------------------------------------
/conanfile.txt:
--------------------------------------------------------------------------------
1 | [requires]
2 | cpprestsdk/2.10.18
3 | minizip/1.2.11
4 | zlib/1.2.12
5 | msgpack/3.3.0
6 | sqlite3/3.39.2
7 | nlohmann_json/3.11.2
8 |
9 | [generators]
10 | premake
11 |
--------------------------------------------------------------------------------
/deps/minhook.lua:
--------------------------------------------------------------------------------
1 | minhook = {
2 | source = path.join(dependencies.basePath, "minhook"),
3 | }
4 |
5 | function minhook.import()
6 | links { "minhook" }
7 | minhook.includes()
8 | end
9 |
10 | function minhook.includes()
11 | includedirs {
12 | path.join(minhook.source, "include")
13 | }
14 | end
15 |
16 | function minhook.project()
17 | project "minhook"
18 | language "C"
19 |
20 | minhook.includes()
21 |
22 | files {
23 | path.join(minhook.source, "src/**.h"),
24 | path.join(minhook.source, "src/**.c"),
25 | }
26 |
27 | warnings "Off"
28 | kind "StaticLib"
29 | end
30 |
31 | table.insert(dependencies, minhook)
32 |
--------------------------------------------------------------------------------
/deps/rapidjson.lua:
--------------------------------------------------------------------------------
1 | rapidjson = {
2 | source = path.join(dependencies.basePath, "rapidjson"),
3 | }
4 |
5 | function rapidjson.import()
6 | rapidjson.includes()
7 | end
8 |
9 | function rapidjson.includes()
10 | includedirs {
11 | path.join(rapidjson.source, "include")
12 | }
13 | end
14 |
15 | function rapidjson.project()
16 | end
17 |
18 | table.insert(dependencies, rapidjson)
19 |
--------------------------------------------------------------------------------
/generate.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | conan install . -if build -s build_type=Release --build missing
3 | utils\bin\premake5 %* vs2019
4 |
--------------------------------------------------------------------------------
/premake5.lua:
--------------------------------------------------------------------------------
1 | dependencies = {
2 | basePath = "./deps"
3 | }
4 |
5 | function dependencies.load()
6 | dir = path.join(dependencies.basePath, "premake/*.lua")
7 | deps = os.matchfiles(dir)
8 |
9 | for i, dep in pairs(deps) do
10 | dep = dep:gsub(".lua", "")
11 | require(dep)
12 | end
13 | end
14 |
15 | function dependencies.imports()
16 | for i, proj in pairs(dependencies) do
17 | if type(i) == 'number' then
18 | proj.import()
19 | end
20 | end
21 | end
22 |
23 | function dependencies.projects()
24 | for i, proj in pairs(dependencies) do
25 | if type(i) == 'number' then
26 | proj.project()
27 | end
28 | end
29 | end
30 |
31 | include "deps/minhook.lua"
32 | include "deps/rapidjson.lua"
33 | include "build/conanbuildinfo.premake.lua"
34 |
35 | workspace "ImasSCSP-localify"
36 | conan_basic_setup()
37 |
38 | location "./build"
39 | objdir "%{wks.location}/obj"
40 | targetdir "%{wks.location}/bin/%{cfg.platform}/%{cfg.buildcfg}"
41 |
42 | architecture "x64"
43 | platforms "x64"
44 |
45 | configurations {
46 | "Debug",
47 | "Release",
48 | }
49 |
50 | buildoptions {
51 | "/std:c++latest",
52 | "/utf-8",
53 | }
54 | systemversion "latest"
55 | symbols "On"
56 | staticruntime "On"
57 | editandcontinue "Off"
58 | warnings "Off"
59 | characterset "ASCII"
60 |
61 | flags {
62 | "NoIncrementalLink",
63 | "NoMinimalRebuild",
64 | "MultiProcessorCompile",
65 | }
66 |
67 | staticruntime "Off"
68 |
69 | configuration "Release"
70 | optimize "Full"
71 | buildoptions "/Os"
72 |
73 | configuration "Debug"
74 | optimize "Debug"
75 |
76 | dependencies.projects()
77 |
78 | project "ImasSCSP-localify"
79 | targetname "version"
80 |
81 | language "C++"
82 | kind "SharedLib"
83 |
84 | files {
85 | "./src/**.hpp",
86 | "./src/**.cpp",
87 | "./src/**.asm",
88 | "./src/**.def",
89 | }
90 |
91 | includedirs {
92 | "./src",
93 | "%{prj.location}/src",
94 | }
95 |
96 | dependencies.imports()
97 |
98 | linkoptions { conan_sharedlinkflags }
99 |
100 | configuration "Release"
101 | linkoptions "/SAFESEH:NO"
102 | syslibdirs {
103 | "./libs/Release",
104 | }
105 |
106 | configuration "Debug"
107 | linkoptions "/SAFESEH:NO"
108 | syslibdirs {
109 | "./libs/Debug",
110 | }
111 |
--------------------------------------------------------------------------------
/readme_EN.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # SCSP-localify
4 |
5 | [简体中文](README.md) | English
6 |
7 | iM@S SCSP localify plugin.
8 |
9 | **Note: Using external plugins violates the game's terms of service. If your account is banned due to plugin usage, the consequences are solely your responsibility.**
10 |
11 |
12 |
13 |
14 |
15 | # Instructions for Use
16 |
17 | - Simply unzip the plugin into the game installation directory (`version.dll` and `imasscprism.exe` should be in the same directory).
18 | - Upon launching the game, if you see the console (make sure to open `enableConsole`), the installation is successful.
19 |
20 |
21 |
22 | # Function List
23 |
24 | - Dump Text
25 | - Localization, Font Replacement
26 | - Unlock Frame Rate
27 | - Switching Windows Without Pausing
28 | - Free Camera
29 | - Live MV Related **(Modify in GUI)**
30 | - Unlock Costumes
31 | - Freedom to Choose Costumes, Wear Other Characters' Clothes
32 | - Allow Same Idol Appearance
33 | - Real-time Modification of Character Body Parameters, Adjust Height, Head, Chest, Arm, and Palm Size **(Modify in GUI)**
34 |
35 |
36 |
37 |
38 | # Configuration Instructions
39 |
40 | - Configuration items are located in the `scsp-config.json` file.
41 |
42 | | Configuration Item | Type | Default Value | Description |
43 | | --------------------- | --------- | ------------------------------------- | ------------------------------------------------------ |
44 | | enableConsole | Bool | `true` | Enable console |
45 | | enableVSync | Bool | `false` | Enable vertical sync |
46 | | maxFps | Int | `60` | Maximum frame rate
When `enableVSync` is enabled, this configuration is ineffective |
47 | | 3DResolutionScale | Float | `1.0` | 3D resolution render scale |
48 | | localifyBasePath | String | `scsp_localify` | Localization file directory |
49 | | hotKey | String (Char) | `u` | Press `Ctrl` + this configured hotkey to **open the plugin GUI** |
50 | | dumpUntransLyrics | Bool | `false` | Dump untranslated lyrics |
51 | | dumpUntransLocal2 | Bool | `false` | Dump untranslated text |
52 | | autoDumpAllJson | Bool | `false` | Dump all loaded JSON files |
53 | | extraAssetBundlePaths | String[] | `["scsp_localify/scsp-bundle"]` | Custom asset bundle paths |
54 | | customFontPath | String | `assets/font/sbtphumminge-regular.ttf` | Custom font path in asset bundles
Used for replacing built-in fonts in the game |
55 | | blockOutOfFocus | Bool | `true` | Intercept window out-of-focus events
Game won't pause when switching to other windows |
56 | | baseFreeCamera | [BaseFreeCamera](#BaseFreeCamera) Object | [BaseFreeCamera](#BaseFreeCamera) | Free camera configuration |
57 | | unlockPIdolAndSCharaEvents | Bool | `false` | Unlock Idol Event (アイドルイベント) and Support Event (サポートイベント) in `Characters` - `Overview` |
58 | | startResolution | [Resolution](#Resolution) Object | [Resolution](#Resolution) | Game window resolution |
59 |
60 |
61 |
62 | ### BaseFreeCamera
63 |
64 | | Configuration Item | Type | Default Value | Description |
65 | | ------------------ | ------ | ------------- | --------------------|
66 | | enable | Bool | `false` | Enable free camera |
67 | | moveStep | Float | `50` | Camera movement speed |
68 | | mouseSpeed | Float | `35` | Mouse sensitivity for camera movement |
69 |
70 |
71 |
72 | ### Resolution
73 |
74 | | Configuration Item | Type | Default Value | Description |
75 | | ------------------ | ---- | ------------- | -------------- |
76 | | w | Int | `1280` | Window width |
77 | | h | Int | `720` | Window height |
78 | | isFull | Bool | `false` | Is full screen |
79 |
80 |
81 |
82 | # Free Camera Instructions
83 |
84 | - Set `enable` under `baseFreeCamera` in `scsp-config.json` to `true`.
85 | - Scope of application: All 3D scenes. Including but not limited to homepage, story, Live.
86 |
87 |
88 |
89 | ## Free Camera Operation Method
90 |
91 | - Movement: `W`, `S`, `A`, `D`
92 | - Ascend: `Space`, Descend: `Ctrl`
93 | - Reset camera: `R`
94 |
95 | - Camera Rotation:
96 | - Keyboard: `↑`, `↓`, `←`, `→`
97 | - Mouse:
98 | - Press the ` key (located to the left of the number keys, above the TAB key)
99 | - Or **hold down** the right mouse button
100 | - Adjust Field of View (FOV)
101 | - Keyboard: `Q`, `E`
102 | - Or mouse scroll wheel
103 |
104 |
105 |
106 | # How to Localize
107 |
108 | - After localizing the Json files in the dumps directory, place them in the `scsp_localify` directory.
109 | - Localization Repository (Chinese): [SCSPTranslationData](https://github.com/ShinyGroup/SCSPTranslationData) Contributors are welcome to contribute their translations~
110 |
111 |
112 |
113 | ## Dump Original Text Yourself
114 | - The UI text in the game can be roughly divided into three categories.
115 |
116 | - 1. Loaded through the game's `Localify` interface
117 | - 2. Loaded without using the `Localify` interface
118 | - 3. Loaded directly through Json (this part includes not only text but also other things like camera data, character actions, etc., which can be replaced by the plugin.)
119 |
120 |
121 |
122 | - The first category corresponds to `localify.json`
123 |
124 | - The second category corresponds to `local2.json` and `lyrics.json`
125 |
126 | - Files other than these correspond to the third category
127 |
128 | - (Some UI text goes through `Localify`, some don't, it's strange.)
129 |
130 |
131 |
132 | ### Story and Some UI Text Dump
133 | After logging into the game, go to the story reading interface, press `ctrl` + `u`, a control window will pop up, check `Waiting Extract Text`, then click on any story title, and the story text and `localify.json` will be automatically dumped.
134 |
135 |
136 |
137 | ### Lyrics and Another Part of UI Text Dump
138 | Set `dumpUntransLyrics` and `dumpUntransLocal2` in `scsp-config.json` to `true`, then open the game. The plugin will continuously dump untranslated parts into Json in real time.
--------------------------------------------------------------------------------
/resources/scsp-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "enableConsole": true,
3 | "enableVSync": false,
4 | "maxFps": 60,
5 | "3DResolutionScale": 1.0,
6 | "localifyBasePath": "scsp_localify",
7 | "hotKey": "u",
8 | "dumpUntransLyrics": false,
9 | "dumpUntransLocal2": false,
10 | "autoDumpAllJson": false,
11 | "extraAssetBundlePaths": [
12 | "scsp_localify/scsp-bundle"
13 | ],
14 | "customFontPath": "assets/font/sbtphumminge-regular.ttf",
15 | "fontSizeOffset": -3,
16 | "blockOutOfFocus": true,
17 | "baseFreeCamera": {
18 | "enable": false,
19 | "moveStep": 50,
20 | "mouseSpeed": 35
21 | },
22 | "unlockPIdolAndSCharaEvents": false,
23 | "startResolution": {
24 | "w": 1280,
25 | "h": 720,
26 | "isFull": false
27 | }
28 | }
--------------------------------------------------------------------------------
/src/camera/baseCamera.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinosk6/scsp-localify/fc36b8a03d26dcff6aeaba0b2c77cf62f11a75c3/src/camera/baseCamera.cpp
--------------------------------------------------------------------------------
/src/camera/baseCamera.hpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinosk6/scsp-localify/fc36b8a03d26dcff6aeaba0b2c77cf62f11a75c3/src/camera/baseCamera.hpp
--------------------------------------------------------------------------------
/src/camera/camera.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinosk6/scsp-localify/fc36b8a03d26dcff6aeaba0b2c77cf62f11a75c3/src/camera/camera.cpp
--------------------------------------------------------------------------------
/src/camera/camera.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "camera/baseCamera.hpp"
3 |
4 | namespace SCCamera {
5 | extern BaseCamera::Camera baseCamera;
6 | extern Vector2Int_t currRenderResolution;
7 |
8 | void onKillFocus();
9 | void initCameraSettings();
10 | void mouseMove(LONG moveX, LONG moveY, int mouseEventType);
11 | }
12 |
--------------------------------------------------------------------------------
/src/console.cpp:
--------------------------------------------------------------------------------
1 | #include "stdinclude.hpp"
2 |
3 | namespace
4 | {
5 | void console_thread()
6 | {
7 | std::string line;
8 |
9 | while (true)
10 | {
11 | std::cin >> line;
12 |
13 | std::cout << "\n] " << line << "\n";
14 |
15 | if (line == "reload")
16 | {
17 | std::ifstream config_stream {"config.json"};
18 | std::vector dicts {};
19 |
20 | rapidjson::IStreamWrapper wrapper {config_stream};
21 | rapidjson::Document document;
22 |
23 | document.ParseStream(wrapper);
24 |
25 | if (!document.HasParseError())
26 | {
27 | auto& dicts_arr = document["dicts"];
28 | auto len = dicts_arr.Size();
29 |
30 | for (size_t i = 0; i < len; ++i)
31 | {
32 | auto dict = dicts_arr[i].GetString();
33 |
34 | dicts.push_back(dict);
35 | }
36 | }
37 |
38 | config_stream.close();
39 |
40 | }
41 | }
42 | }
43 | }
44 |
45 | void start_console()
46 | {
47 | #ifdef _DEBUG
48 | std::thread(console_thread).detach();
49 | #endif
50 | }
--------------------------------------------------------------------------------
/src/dllproxy/proxy.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | extern "C"
4 | {
5 | void* GetFileVersionInfoA_Original = NULL;
6 | void* GetFileVersionInfoByHandle_Original = NULL;
7 | void* GetFileVersionInfoExA_Original = NULL;
8 | void* GetFileVersionInfoExW_Original = NULL;
9 | void* GetFileVersionInfoSizeA_Original = NULL;
10 | void* GetFileVersionInfoSizeExA_Original = NULL;
11 | void* GetFileVersionInfoSizeExW_Original = NULL;
12 | void* GetFileVersionInfoSizeW_Original = NULL;
13 | void* GetFileVersionInfoW_Original = NULL;
14 | void* VerFindFileA_Original = NULL;
15 | void* VerFindFileW_Original = NULL;
16 | void* VerInstallFileA_Original = NULL;
17 | void* VerInstallFileW_Original = NULL;
18 | void* VerLanguageNameA_Original = NULL;
19 | void* VerLanguageNameW_Original = NULL;
20 | void* VerQueryValueA_Original = NULL;
21 | void* VerQueryValueW_Original = NULL;
22 | }
23 |
24 | using namespace std;
25 |
26 | namespace
27 | {
28 | class version_init
29 | {
30 | public:
31 | version_init()
32 | {
33 | std::string dll_path;
34 | dll_path.resize(MAX_PATH);
35 | dll_path.resize(GetSystemDirectoryA(dll_path.data(), MAX_PATH));
36 |
37 | dll_path += "\\" + "version.dll"s;
38 |
39 | auto original_dll = LoadLibraryA(dll_path.data());
40 |
41 | GetFileVersionInfoA_Original = GetProcAddress(original_dll, "GetFileVersionInfoA");
42 | GetFileVersionInfoByHandle_Original = GetProcAddress(original_dll, "GetFileVersionInfoByHandle");
43 | GetFileVersionInfoExA_Original = GetProcAddress(original_dll, "GetFileVersionInfoExA");
44 | GetFileVersionInfoExW_Original = GetProcAddress(original_dll, "GetFileVersionInfoExW");
45 | GetFileVersionInfoSizeA_Original = GetProcAddress(original_dll, "GetFileVersionInfoSizeA");
46 | GetFileVersionInfoSizeExA_Original = GetProcAddress(original_dll, "GetFileVersionInfoSizeExA");
47 | GetFileVersionInfoSizeExW_Original = GetProcAddress(original_dll, "GetFileVersionInfoSizeExW");
48 | GetFileVersionInfoSizeW_Original = GetProcAddress(original_dll, "GetFileVersionInfoSizeW");
49 | GetFileVersionInfoW_Original = GetProcAddress(original_dll, "GetFileVersionInfoW");
50 | VerFindFileA_Original = GetProcAddress(original_dll, "VerFindFileA");
51 | VerFindFileW_Original = GetProcAddress(original_dll, "VerFindFileW");
52 | VerInstallFileA_Original = GetProcAddress(original_dll, "VerInstallFileA");
53 | VerInstallFileW_Original = GetProcAddress(original_dll, "VerInstallFileW");
54 | VerLanguageNameA_Original = GetProcAddress(original_dll, "VerLanguageNameA");
55 | VerLanguageNameW_Original = GetProcAddress(original_dll, "VerLanguageNameW");
56 | VerQueryValueA_Original = GetProcAddress(original_dll, "VerQueryValueA");
57 | VerQueryValueW_Original = GetProcAddress(original_dll, "VerQueryValueW");
58 | };
59 | };
60 |
61 | version_init init {};
62 | }
63 |
--------------------------------------------------------------------------------
/src/dllproxy/version.asm:
--------------------------------------------------------------------------------
1 | .code
2 |
3 | extern GetFileVersionInfoA_Original:QWORD
4 | extern GetFileVersionInfoByHandle_Original:QWORD
5 | extern GetFileVersionInfoExA_Original:QWORD
6 | extern GetFileVersionInfoExW_Original:QWORD
7 | extern GetFileVersionInfoSizeA_Original:QWORD
8 | extern GetFileVersionInfoSizeExA_Original:QWORD
9 | extern GetFileVersionInfoSizeExW_Original:QWORD
10 | extern GetFileVersionInfoSizeW_Original:QWORD
11 | extern GetFileVersionInfoW_Original:QWORD
12 | extern VerFindFileA_Original:QWORD
13 | extern VerFindFileW_Original:QWORD
14 | extern VerInstallFileA_Original:QWORD
15 | extern VerInstallFileW_Original:QWORD
16 | extern VerLanguageNameA_Original:QWORD
17 | extern VerLanguageNameW_Original:QWORD
18 | extern VerQueryValueA_Original:QWORD
19 | extern VerQueryValueW_Original:QWORD
20 |
21 | GetFileVersionInfoA_EXPORT proc
22 | jmp QWORD ptr GetFileVersionInfoA_Original
23 | GetFileVersionInfoA_EXPORT endp
24 |
25 | GetFileVersionInfoByHandle_EXPORT proc
26 | jmp QWORD ptr GetFileVersionInfoByHandle_Original
27 | GetFileVersionInfoByHandle_EXPORT endp
28 |
29 | GetFileVersionInfoExA_EXPORT proc
30 | jmp QWORD ptr GetFileVersionInfoExA_Original
31 | GetFileVersionInfoExA_EXPORT endp
32 |
33 | GetFileVersionInfoExW_EXPORT proc
34 | jmp QWORD ptr GetFileVersionInfoExW_Original
35 | GetFileVersionInfoExW_EXPORT endp
36 |
37 | GetFileVersionInfoSizeA_EXPORT proc
38 | jmp QWORD ptr GetFileVersionInfoSizeA_Original
39 | GetFileVersionInfoSizeA_EXPORT endp
40 |
41 | GetFileVersionInfoSizeExA_EXPORT proc
42 | jmp QWORD ptr GetFileVersionInfoSizeExA_Original
43 | GetFileVersionInfoSizeExA_EXPORT endp
44 |
45 | GetFileVersionInfoSizeExW_EXPORT proc
46 | jmp QWORD ptr GetFileVersionInfoSizeExW_Original
47 | GetFileVersionInfoSizeExW_EXPORT endp
48 |
49 | GetFileVersionInfoSizeW_EXPORT proc
50 | jmp QWORD ptr GetFileVersionInfoSizeW_Original
51 | GetFileVersionInfoSizeW_EXPORT endp
52 |
53 | GetFileVersionInfoW_EXPORT proc
54 | jmp QWORD ptr GetFileVersionInfoW_Original
55 | GetFileVersionInfoW_EXPORT endp
56 |
57 | VerFindFileA_EXPORT proc
58 | jmp QWORD ptr VerFindFileA_Original
59 | VerFindFileA_EXPORT endp
60 |
61 | VerFindFileW_EXPORT proc
62 | jmp QWORD ptr VerFindFileW_Original
63 | VerFindFileW_EXPORT endp
64 |
65 | VerInstallFileA_EXPORT proc
66 | jmp QWORD ptr VerInstallFileA_Original
67 | VerInstallFileA_EXPORT endp
68 |
69 | VerInstallFileW_EXPORT proc
70 | jmp QWORD ptr VerInstallFileW_Original
71 | VerInstallFileW_EXPORT endp
72 |
73 | VerLanguageNameA_EXPORT proc
74 | jmp QWORD ptr VerLanguageNameA_Original
75 | VerLanguageNameA_EXPORT endp
76 |
77 | VerLanguageNameW_EXPORT proc
78 | jmp QWORD ptr VerLanguageNameW_Original
79 | VerLanguageNameW_EXPORT endp
80 |
81 | VerQueryValueA_EXPORT proc
82 | jmp QWORD ptr VerQueryValueA_Original
83 | VerQueryValueA_EXPORT endp
84 |
85 | VerQueryValueW_EXPORT proc
86 | jmp QWORD ptr VerQueryValueW_Original
87 | VerQueryValueW_EXPORT endp
88 |
89 | end
90 |
--------------------------------------------------------------------------------
/src/dllproxy/version.def:
--------------------------------------------------------------------------------
1 | LIBRARY version.dll
2 | EXPORTS
3 | GetFileVersionInfoA=GetFileVersionInfoA_EXPORT
4 | GetFileVersionInfoByHandle=GetFileVersionInfoByHandle_EXPORT
5 | GetFileVersionInfoExA=GetFileVersionInfoExA_EXPORT
6 | GetFileVersionInfoExW=GetFileVersionInfoExW_EXPORT
7 | GetFileVersionInfoSizeA=GetFileVersionInfoSizeA_EXPORT
8 | GetFileVersionInfoSizeExA=GetFileVersionInfoSizeExA_EXPORT
9 | GetFileVersionInfoSizeExW=GetFileVersionInfoSizeExW_EXPORT
10 | GetFileVersionInfoSizeW=GetFileVersionInfoSizeW_EXPORT
11 | GetFileVersionInfoW=GetFileVersionInfoW_EXPORT
12 | VerFindFileA=VerFindFileA_EXPORT
13 | VerFindFileW=VerFindFileW_EXPORT
14 | VerInstallFileA=VerInstallFileA_EXPORT
15 | VerInstallFileW=VerInstallFileW_EXPORT
16 | VerLanguageNameA=VerLanguageNameA_EXPORT
17 | VerLanguageNameW=VerLanguageNameW_EXPORT
18 | VerQueryValueA=VerQueryValueA_EXPORT
19 | VerQueryValueW=VerQueryValueW_EXPORT
20 |
--------------------------------------------------------------------------------
/src/il2cpp/il2cpp_symbols.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | il2cpp_string_new_utf16_t il2cpp_string_new_utf16;
4 | il2cpp_string_new_t il2cpp_string_new;
5 | il2cpp_domain_get_t il2cpp_domain_get;
6 | il2cpp_domain_assembly_open_t il2cpp_domain_assembly_open;
7 | il2cpp_assembly_get_image_t il2cpp_assembly_get_image;
8 | il2cpp_class_from_name_t il2cpp_class_from_name;
9 | il2cpp_class_get_methods_t il2cpp_class_get_methods;
10 | il2cpp_class_get_method_from_name_t il2cpp_class_get_method_from_name;
11 | il2cpp_method_get_param_t il2cpp_method_get_param;
12 | il2cpp_object_new_t il2cpp_object_new;
13 | il2cpp_resolve_icall_t il2cpp_resolve_icall;
14 | il2cpp_array_new_t il2cpp_array_new;
15 | il2cpp_thread_attach_t il2cpp_thread_attach;
16 | il2cpp_thread_detach_t il2cpp_thread_detach;
17 | il2cpp_class_get_field_from_name_t il2cpp_class_get_field_from_name;
18 | il2cpp_class_is_assignable_from_t il2cpp_class_is_assignable_from;
19 | il2cpp_class_for_each_t il2cpp_class_for_each;
20 | il2cpp_class_get_nested_types_t il2cpp_class_get_nested_types;
21 | il2cpp_class_get_type_t il2cpp_class_get_type;
22 | il2cpp_type_get_object_t il2cpp_type_get_object;
23 | il2cpp_gchandle_new_t il2cpp_gchandle_new;
24 | il2cpp_gchandle_free_t il2cpp_gchandle_free;
25 | il2cpp_gchandle_get_target_t il2cpp_gchandle_get_target;
26 | il2cpp_class_from_type_t il2cpp_class_from_type;
27 | il2cpp_runtime_class_init_t il2cpp_runtime_class_init;
28 | il2cpp_runtime_invoke_t il2cpp_runtime_invoke;
29 | il2cpp_class_get_static_field_data_t il2cpp_class_get_static_field_data;
30 | il2cpp_field_get_value_t il2cpp_field_get_value;
31 | il2cpp_field_get_value_object_t il2cpp_field_get_value_object;
32 | il2cpp_class_from_system_type_t il2cpp_class_from_system_type;
33 | il2cpp_get_corlib_t il2cpp_get_corlib;
34 |
35 | char* il2cpp_array_addr_with_size(void* array, int32_t size, uintptr_t idx)
36 | {
37 | return ((char*)array) + kIl2CppSizeOfArray + size * idx;
38 | }
39 |
40 | namespace il2cpp_symbols
41 | {
42 | #define RESOLVE_IMPORT(name) name = reinterpret_cast(GetProcAddress(game_module, #name))
43 |
44 | void* il2cpp_domain = nullptr;
45 |
46 | void init(HMODULE game_module)
47 | {
48 | RESOLVE_IMPORT(il2cpp_string_new_utf16);
49 | RESOLVE_IMPORT(il2cpp_string_new);
50 | RESOLVE_IMPORT(il2cpp_domain_get);
51 | RESOLVE_IMPORT(il2cpp_domain_assembly_open);
52 | RESOLVE_IMPORT(il2cpp_assembly_get_image);
53 | RESOLVE_IMPORT(il2cpp_class_from_name);
54 | RESOLVE_IMPORT(il2cpp_class_get_methods);
55 | RESOLVE_IMPORT(il2cpp_class_get_method_from_name);
56 | RESOLVE_IMPORT(il2cpp_method_get_param);
57 | RESOLVE_IMPORT(il2cpp_object_new);
58 | RESOLVE_IMPORT(il2cpp_resolve_icall);
59 | RESOLVE_IMPORT(il2cpp_array_new);
60 | RESOLVE_IMPORT(il2cpp_thread_attach);
61 | RESOLVE_IMPORT(il2cpp_thread_detach);
62 | RESOLVE_IMPORT(il2cpp_class_get_field_from_name);
63 | RESOLVE_IMPORT(il2cpp_class_is_assignable_from);
64 | RESOLVE_IMPORT(il2cpp_class_for_each);
65 | RESOLVE_IMPORT(il2cpp_class_get_nested_types);
66 | RESOLVE_IMPORT(il2cpp_class_get_type);
67 | RESOLVE_IMPORT(il2cpp_type_get_object);
68 | RESOLVE_IMPORT(il2cpp_gchandle_new);
69 | RESOLVE_IMPORT(il2cpp_gchandle_free);
70 | RESOLVE_IMPORT(il2cpp_gchandle_get_target);
71 | RESOLVE_IMPORT(il2cpp_class_from_type);
72 | RESOLVE_IMPORT(il2cpp_runtime_class_init);
73 | RESOLVE_IMPORT(il2cpp_runtime_invoke);
74 | RESOLVE_IMPORT(il2cpp_class_get_static_field_data);
75 | RESOLVE_IMPORT(il2cpp_field_get_value);
76 | RESOLVE_IMPORT(il2cpp_field_get_value_object);
77 | RESOLVE_IMPORT(il2cpp_class_from_system_type);
78 | RESOLVE_IMPORT(il2cpp_get_corlib);
79 |
80 | il2cpp_domain = il2cpp_domain_get();
81 | }
82 |
83 | void* get_class(const char* assemblyName, const char* namespaze, const char* klassName)
84 | {
85 | auto assembly = il2cpp_domain_assembly_open(il2cpp_domain, assemblyName);
86 | auto image = il2cpp_assembly_get_image(assembly);
87 | return il2cpp_class_from_name(image, namespaze, klassName);
88 | }
89 |
90 | uintptr_t get_method_pointer(const char* assemblyName, const char* namespaze,
91 | const char* klassName, const char* name, int argsCount)
92 | {
93 | auto assembly = il2cpp_domain_assembly_open(il2cpp_domain, assemblyName);
94 | if (!assembly) {
95 | printf("\nError: invalid assembly: %s\n", assemblyName);
96 | return NULL;
97 | }
98 | auto image = il2cpp_assembly_get_image(assembly);
99 | auto klass = il2cpp_class_from_name(image, namespaze, klassName);
100 | if (!klass) {
101 | printf("\nError: invalid klass: %s::%s\n", namespaze, klassName);
102 | return NULL;
103 | }
104 | auto ret = il2cpp_class_get_method_from_name(klass, name, argsCount);
105 | if (ret) {
106 | return ret->methodPointer;
107 | }
108 | else {
109 | printf("\nError: method not found: %s - %s::%s.%s (%d)\n\n", assemblyName, namespaze, klassName, name, argsCount);
110 | return NULL;
111 | }
112 |
113 | }
114 |
115 | void* find_nested_class_from_name(void* klass, const char* name)
116 | {
117 | return find_nested_class(klass, [name = std::string_view(name)](void* nestedClass) {
118 | return static_cast(nestedClass)->name == name;
119 | });
120 | }
121 |
122 | MethodInfo* get_method(const char* assemblyName, const char* namespaze,
123 | const char* klassName, const char* name, int argsCount)
124 | {
125 | auto assembly = il2cpp_domain_assembly_open(il2cpp_domain, assemblyName);
126 | auto image = il2cpp_assembly_get_image(assembly);
127 | auto klass = il2cpp_class_from_name(image, namespaze, klassName);
128 |
129 | return il2cpp_class_get_method_from_name(klass, name, argsCount);
130 | }
131 |
132 | uintptr_t find_method(const char* assemblyName, const char* namespaze,
133 | const char* klassName, std::function predict)
134 | {
135 | auto assembly = il2cpp_domain_assembly_open(il2cpp_domain, assemblyName);
136 | auto image = il2cpp_assembly_get_image(assembly);
137 | auto klass = il2cpp_class_from_name(image, namespaze, klassName);
138 |
139 | void* iter = nullptr;
140 | while (const MethodInfo* method = il2cpp_class_get_methods(klass, &iter))
141 | {
142 | if (predict(method))
143 | return method->methodPointer;
144 | }
145 |
146 | return 0;
147 | }
148 |
149 | FieldInfo* get_field(const char* assemblyName, const char* namespaze,
150 | const char* klassName, const char* name)
151 | {
152 | const auto assembly = il2cpp_domain_assembly_open(il2cpp_domain, assemblyName);
153 | const auto image = il2cpp_assembly_get_image(assembly);
154 | const auto klass = il2cpp_class_from_name(image, namespaze, klassName);
155 |
156 | return il2cpp_class_get_field_from_name(klass, name);
157 | }
158 |
159 | void* get_class_from_instance(const void* instance)
160 | {
161 | return *static_cast(std::assume_aligned(instance));
162 | }
163 |
164 | Il2CppString* NewWStr(std::wstring_view str)
165 | {
166 | return il2cpp_string_new_utf16(str.data(), str.size());
167 | }
168 |
169 | void* get_system_class_from_reflection_type_str(const char* typeStr, const char* assemblyName) {
170 | static auto assemblyLoad = reinterpret_cast(
171 | il2cpp_symbols::get_method_pointer("mscorlib.dll", "System.Reflection",
172 | "Assembly", "Load", 1)
173 | );
174 | static auto assemblyGetType = reinterpret_cast(
175 | il2cpp_symbols::get_method_pointer("mscorlib.dll", "System.Reflection",
176 | "Assembly", "GetType", 1)
177 | );
178 |
179 | static auto reflectionAssembly = assemblyLoad(il2cpp_string_new(assemblyName));
180 | auto reflectionType = assemblyGetType(reflectionAssembly, il2cpp_string_new(typeStr));
181 | return il2cpp_class_from_system_type(reflectionType);
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/src/il2cpp/il2cpp_symbols.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | // UnityEngine.Color
6 | struct Color_t
7 | {
8 | public:
9 | // System.Single UnityEngine.Color::r
10 | float r;
11 | // System.Single UnityEngine.Color::g
12 | float g;
13 | // System.Single UnityEngine.Color::b
14 | float b;
15 | // System.Single UnityEngine.Color::a
16 | float a;
17 | };
18 |
19 | // UnityEngine.Vector2
20 | struct Vector2_t
21 | {
22 | public:
23 | // System.Single UnityEngine.Vector2::x
24 | float x;
25 | // System.Single UnityEngine.Vector2::y
26 | float y;
27 | };
28 |
29 | // UnityEngine.Vector2
30 | struct Vector2Int_t
31 | {
32 | public:
33 | int x;
34 | int y;
35 | };
36 |
37 | // UnityEngine.Vector3
38 | struct Vector3_t
39 | {
40 | public:
41 | // System.Single UnityEngine.Vector3::x
42 | float x;
43 | // System.Single UnityEngine.Vector3::y
44 | float y;
45 | // System.Single UnityEngine.Vector3::z
46 | float z;
47 | };
48 |
49 | // UnityEngine.Quaternion
50 | struct Quaternion_t
51 | {
52 | public:
53 | float w;
54 | float x;
55 | float y;
56 | float z;
57 | };
58 |
59 | struct Resolution_t
60 | {
61 | public:
62 | int width;
63 | int height;
64 | int herz;
65 | };
66 |
67 | struct Matrix4x4_t
68 | {
69 | public:
70 | float m00;
71 | float m10;
72 | float m20;
73 | float m30;
74 | float m01;
75 | float m11;
76 | float m21;
77 | float m31;
78 | float m02;
79 | float m12;
80 | float m22;
81 | float m32;
82 | float m03;
83 | float m13;
84 | float m23;
85 | float m33;
86 | };
87 |
88 | // UnityEngine.TextGenerationSettings
89 | struct TextGenerationSettings_t
90 | {
91 | public:
92 | // UnityEngine.Font UnityEngine.TextGenerationSettings::font
93 | void* font;
94 | // UnityEngine.Color UnityEngine.TextGenerationSettings::color
95 | Color_t color;
96 | // System.Int32 UnityEngine.TextGenerationSettings::fontSize
97 | int32_t fontSize;
98 | // System.Single UnityEngine.TextGenerationSettings::lineSpacing
99 | float lineSpacing;
100 | // System.Boolean UnityEngine.TextGenerationSettings::richText
101 | bool richText;
102 | // System.Single UnityEngine.TextGenerationSettings::scaleFactor
103 | float scaleFactor;
104 | // UnityEngine.FontStyle UnityEngine.TextGenerationSettings::fontStyle
105 | int32_t fontStyle;
106 | // UnityEngine.TextAnchor UnityEngine.TextGenerationSettings::textAnchor
107 | int32_t textAnchor;
108 | // System.Boolean UnityEngine.TextGenerationSettings::alignByGeometry
109 | bool alignByGeometry;
110 | // System.Boolean UnityEngine.TextGenerationSettings::resizeTextForBestFit
111 | bool resizeTextForBestFit;
112 | // System.Int32 UnityEngine.TextGenerationSettings::resizeTextMinSize
113 | int32_t resizeTextMinSize;
114 | // System.Int32 UnityEngine.TextGenerationSettings::resizeTextMaxSize
115 | int32_t resizeTextMaxSize;
116 | // System.Boolean UnityEngine.TextGenerationSettings::updateBounds
117 | bool updateBounds;
118 | // UnityEngine.VerticalWrapMode UnityEngine.TextGenerationSettings::verticalOverflow
119 | int32_t verticalOverflow;
120 | // UnityEngine.HorizontalWrapMode UnityEngine.TextGenerationSettings::horizontalOverflow
121 | int32_t horizontalOverflow;
122 | // UnityEngine.Vector2 UnityEngine.TextGenerationSettings::generationExtents
123 | Vector2_t generationExtents;
124 | // UnityEngine.Vector2 UnityEngine.TextGenerationSettings::pivot
125 | Vector2_t pivot;
126 | // System.Boolean UnityEngine.TextGenerationSettings::generateOutOfBounds
127 | bool generateOutOfBounds;
128 | };
129 |
130 | // not real Il2CppString class
131 | struct Il2CppString
132 | {
133 | void* Empty;
134 | void* WhiteChars;
135 | int32_t length;
136 | wchar_t start_char[1];
137 | };
138 |
139 | enum Il2CppTypeEnum
140 | {
141 | IL2CPP_TYPE_END = 0x00, /* End of List */
142 | IL2CPP_TYPE_VOID = 0x01,
143 | IL2CPP_TYPE_BOOLEAN = 0x02,
144 | IL2CPP_TYPE_CHAR = 0x03,
145 | IL2CPP_TYPE_I1 = 0x04,
146 | IL2CPP_TYPE_U1 = 0x05,
147 | IL2CPP_TYPE_I2 = 0x06,
148 | IL2CPP_TYPE_U2 = 0x07,
149 | IL2CPP_TYPE_I4 = 0x08,
150 | IL2CPP_TYPE_U4 = 0x09,
151 | IL2CPP_TYPE_I8 = 0x0a,
152 | IL2CPP_TYPE_U8 = 0x0b,
153 | IL2CPP_TYPE_R4 = 0x0c,
154 | IL2CPP_TYPE_R8 = 0x0d,
155 | IL2CPP_TYPE_STRING = 0x0e,
156 | IL2CPP_TYPE_PTR = 0x0f,
157 | IL2CPP_TYPE_BYREF = 0x10,
158 | IL2CPP_TYPE_VALUETYPE = 0x11,
159 | IL2CPP_TYPE_CLASS = 0x12,
160 | IL2CPP_TYPE_VAR = 0x13,
161 | IL2CPP_TYPE_ARRAY = 0x14,
162 | IL2CPP_TYPE_GENERICINST = 0x15,
163 | IL2CPP_TYPE_TYPEDBYREF = 0x16,
164 | IL2CPP_TYPE_I = 0x18,
165 | IL2CPP_TYPE_U = 0x19,
166 | IL2CPP_TYPE_FNPTR = 0x1b,
167 | IL2CPP_TYPE_OBJECT = 0x1c,
168 | IL2CPP_TYPE_SZARRAY = 0x1d,
169 | IL2CPP_TYPE_MVAR = 0x1e,
170 | IL2CPP_TYPE_CMOD_REQD = 0x1f,
171 | IL2CPP_TYPE_CMOD_OPT = 0x20,
172 | IL2CPP_TYPE_INTERNAL = 0x21,
173 |
174 | IL2CPP_TYPE_MODIFIER = 0x40,
175 | IL2CPP_TYPE_SENTINEL = 0x41,
176 | IL2CPP_TYPE_PINNED = 0x45,
177 |
178 | IL2CPP_TYPE_ENUM = 0x55
179 | };
180 |
181 | typedef struct Il2CppType
182 | {
183 | void* dummy;
184 | unsigned int attrs : 16;
185 | Il2CppTypeEnum type : 8;
186 | unsigned int num_mods : 6;
187 | unsigned int byref : 1;
188 | unsigned int pinned : 1;
189 | } Il2CppType;
190 |
191 | struct ParameterInfo
192 | {
193 | const char* name;
194 | int32_t position;
195 | uint32_t token;
196 | const Il2CppType* parameter_type;
197 | };
198 |
199 | struct MethodInfo
200 | {
201 | uintptr_t methodPointer;
202 | uintptr_t virtualMethodPointer;
203 | uintptr_t invoker_method;
204 | const char* name;
205 | uintptr_t klass;
206 | const Il2CppType* return_type;
207 | const ParameterInfo* parameters;
208 | uintptr_t methodDefinition;
209 | uintptr_t genericContainer;
210 | uint32_t token;
211 | uint16_t flags;
212 | uint16_t iflags;
213 | uint16_t slot;
214 | uint8_t parameters_count;
215 | uint8_t is_generic : 1;
216 | uint8_t is_inflated : 1;
217 | uint8_t wrapper_type : 1;
218 | uint8_t is_marshaled_from_native : 1;
219 | };
220 |
221 | struct FieldInfo
222 | {
223 | const char* name;
224 | const Il2CppType* type;
225 | uintptr_t parent;
226 | int32_t offset;
227 | uint32_t token;
228 | };
229 |
230 | template
231 | struct TypedField
232 | {
233 | FieldInfo* Field;
234 |
235 | constexpr FieldInfo* operator->() const noexcept
236 | {
237 | return Field;
238 | }
239 | };
240 |
241 | struct Il2CppObject
242 | {
243 | union
244 | {
245 | void* klass;
246 | void* vtable;
247 | };
248 | void* monitor;
249 | };
250 |
251 | typedef struct Il2CppArraySize
252 | {
253 | Il2CppObject obj;
254 | void* bounds;
255 | uintptr_t max_length;
256 | alignas(8)
257 | void* vector[0];
258 | } Il2CppArraySize;
259 |
260 | struct Il2CppClassHead
261 | {
262 | const void* image;
263 | void* gc_desc;
264 | const char* name;
265 | const char* namespaze;
266 | };
267 |
268 | struct Il2CppReflectionType
269 | {
270 | Il2CppObject object;
271 | const Il2CppType* type;
272 | };
273 |
274 | static const size_t kIl2CppSizeOfArray = (offsetof(Il2CppArraySize, vector));
275 |
276 | // function types
277 | typedef Il2CppString* (*il2cpp_string_new_utf16_t)(const wchar_t* str, unsigned int len);
278 | typedef Il2CppString* (*il2cpp_string_new_t)(const char* str);
279 | typedef void* (*il2cpp_domain_get_t)();
280 | typedef void* (*il2cpp_domain_assembly_open_t)(void* domain, const char* name);
281 | typedef void* (*il2cpp_assembly_get_image_t)(void* assembly);
282 | typedef void* (*il2cpp_class_from_name_t)(void* image, const char* namespaze, const char* name);
283 | typedef MethodInfo* (*il2cpp_class_get_methods_t)(void* klass, void** iter);
284 | typedef MethodInfo* (*il2cpp_class_get_method_from_name_t)(void* klass, const char* name, int argsCount);
285 | typedef void* (*il2cpp_method_get_param_t)(const MethodInfo* method, uint32_t index);
286 | typedef void* (*il2cpp_object_new_t)(void* klass);
287 | typedef void* (*il2cpp_resolve_icall_t)(const char* name);
288 | typedef void* (*il2cpp_array_new_t)(void* klass, uintptr_t count);
289 | typedef void* (*il2cpp_thread_attach_t)(void* domain);
290 | typedef void (*il2cpp_thread_detach_t)(void* thread);
291 | typedef FieldInfo* (*il2cpp_class_get_field_from_name_t)(void* klass, const char* name);
292 | typedef bool (*il2cpp_class_is_assignable_from_t)(void* klass, void* oklass);
293 | typedef void (*il2cpp_class_for_each_t)(void(*klassReportFunc)(void* klass, void* userData), void* userData);
294 | typedef void* (*il2cpp_class_get_nested_types_t)(void* klass, void** iter);
295 | typedef void* (*il2cpp_class_get_type_t)(void* klass);
296 | typedef Il2CppReflectionType* (*il2cpp_type_get_object_t)(const void* type);
297 | typedef uint32_t (*il2cpp_gchandle_new_t)(void* obj, bool pinned);
298 | typedef void (*il2cpp_gchandle_free_t)(uint32_t gchandle);
299 | typedef void* (*il2cpp_gchandle_get_target_t)(uint32_t gchandle);
300 | typedef void* (*il2cpp_class_from_type_t)(const Il2CppType* type);
301 | typedef void (*il2cpp_runtime_class_init_t)(void* klass);
302 | typedef void* (*il2cpp_runtime_invoke_t)(MethodInfo* method, void* obj, void** params, Il2CppObject** exc);
303 | typedef void* (*il2cpp_class_get_static_field_data_t)(void* klass);
304 | typedef void (*il2cpp_field_get_value_t)(void* obj, void* field, void* value);
305 | typedef void* (*il2cpp_field_get_value_object_t)(void* field, void* obj);
306 | typedef void* (*il2cpp_class_from_system_type_t)(Il2CppReflectionType* type);
307 | typedef void* (*il2cpp_get_corlib_t)();
308 |
309 | // function defines
310 | extern il2cpp_string_new_utf16_t il2cpp_string_new_utf16;
311 | extern il2cpp_string_new_t il2cpp_string_new;
312 | extern il2cpp_domain_get_t il2cpp_domain_get;
313 | extern il2cpp_domain_assembly_open_t il2cpp_domain_assembly_open;
314 | extern il2cpp_assembly_get_image_t il2cpp_assembly_get_image;
315 | extern il2cpp_class_from_name_t il2cpp_class_from_name;
316 | extern il2cpp_class_get_methods_t il2cpp_class_get_methods;
317 | extern il2cpp_class_get_method_from_name_t il2cpp_class_get_method_from_name;
318 | extern il2cpp_method_get_param_t il2cpp_method_get_param;
319 | extern il2cpp_object_new_t il2cpp_object_new;
320 | extern il2cpp_resolve_icall_t il2cpp_resolve_icall;
321 | extern il2cpp_array_new_t il2cpp_array_new;
322 | extern il2cpp_thread_attach_t il2cpp_thread_attach;
323 | extern il2cpp_thread_detach_t il2cpp_thread_detach;
324 | extern il2cpp_class_get_field_from_name_t il2cpp_class_get_field_from_name;
325 | extern il2cpp_class_is_assignable_from_t il2cpp_class_is_assignable_from;
326 | extern il2cpp_class_for_each_t il2cpp_class_for_each;
327 | extern il2cpp_class_get_nested_types_t il2cpp_class_get_nested_types;
328 | extern il2cpp_class_get_type_t il2cpp_class_get_type;
329 | extern il2cpp_type_get_object_t il2cpp_type_get_object;
330 | extern il2cpp_gchandle_new_t il2cpp_gchandle_new;
331 | extern il2cpp_gchandle_free_t il2cpp_gchandle_free;
332 | extern il2cpp_gchandle_get_target_t il2cpp_gchandle_get_target;
333 | extern il2cpp_class_from_type_t il2cpp_class_from_type;
334 | extern il2cpp_runtime_class_init_t il2cpp_runtime_class_init;
335 | extern il2cpp_runtime_invoke_t il2cpp_runtime_invoke;
336 | extern il2cpp_class_get_static_field_data_t il2cpp_class_get_static_field_data;
337 | extern il2cpp_field_get_value_t il2cpp_field_get_value;
338 | extern il2cpp_field_get_value_object_t il2cpp_field_get_value_object;
339 | extern il2cpp_class_from_system_type_t il2cpp_class_from_system_type;
340 | extern il2cpp_get_corlib_t il2cpp_get_corlib;
341 |
342 | char* il2cpp_array_addr_with_size(void* arr, int32_t size, uintptr_t idx);
343 |
344 | // array macro
345 | #define il2cpp_array_addr(array, type, index) ((type*)(void*) il2cpp_array_addr_with_size (array, sizeof (type), index))
346 |
347 | #define il2cpp_array_setref(array, index, value) \
348 | do { \
349 | void* *__p = (void* *) il2cpp_array_addr ((array), void*, (index)); \
350 | *__p = (value); \
351 | } while (0)
352 |
353 | namespace il2cpp_symbols
354 | {
355 | void init(HMODULE game_module);
356 | uintptr_t get_method_pointer(const char* assemblyName, const char* namespaze,
357 | const char* klassName, const char* name, int argsCount);
358 |
359 | void* get_class(const char* assemblyName, const char* namespaze, const char* klassName);
360 |
361 | void* find_nested_class(void* klass, std::predicate auto&& predicate)
362 | {
363 | void* iter{};
364 | while (const auto curNestedClass = il2cpp_class_get_nested_types(klass, &iter))
365 | {
366 | if (static_cast(predicate)(curNestedClass))
367 | {
368 | return curNestedClass;
369 | }
370 | }
371 |
372 | return nullptr;
373 | }
374 |
375 | void* find_nested_class_from_name(void* klass, const char* name);
376 |
377 | MethodInfo* get_method(const char* assemblyName, const char* namespaze,
378 | const char* klassName, const char* name, int argsCount);
379 |
380 | uintptr_t find_method(const char* assemblyName, const char* namespaze,
381 | const char* klassName, std::function predict);
382 |
383 | FieldInfo* get_field(const char* assemblyName, const char* namespaze,
384 | const char* klassName, const char* name);
385 |
386 | template
387 | TypedField get_field(const char* assemblyName, const char* namespaze,
388 | const char* klassName, const char* name)
389 | {
390 | return { get_field(assemblyName, namespaze, klassName, name) };
391 | }
392 |
393 | void* get_class_from_instance(const void* instance);
394 |
395 | template requires std::is_trivial_v
396 | T read_field(const void* ptr, const FieldInfo* field)
397 | {
398 | T result;
399 | const auto fieldPtr = static_cast(ptr) + field->offset;
400 | std::memcpy(std::addressof(result), fieldPtr, sizeof(T));
401 | return result;
402 | }
403 |
404 | template
405 | T read_field(const void* ptr, TypedField field)
406 | {
407 | return read_field(ptr, field.Field);
408 | }
409 |
410 | template requires std::is_trivial_v
411 | void write_field(void* ptr, const FieldInfo* field, const T& value)
412 | {
413 | const auto fieldPtr = static_cast(ptr) + field->offset;
414 | std::memcpy(fieldPtr, std::addressof(value), sizeof(T));
415 | }
416 |
417 | template
418 | void write_field(void* ptr, TypedField field, U&& value)
419 | {
420 | write_field(ptr, field.Field, static_cast(std::forward(value)));
421 | }
422 |
423 | template
424 | void iterate_list(const void* list, std::invocable auto&& receiver)
425 | {
426 | const auto listClass = get_class_from_instance(list);
427 | const auto getItemMethod = reinterpret_cast(il2cpp_class_get_method_from_name(listClass, "get_Item", 1)->methodPointer);
428 | const auto getCountMethod = reinterpret_cast(il2cpp_class_get_method_from_name(listClass, "get_Count", 0)->methodPointer);
429 |
430 | const auto count = getCountMethod(list);
431 | for (int32_t i = 0; i < count; ++i)
432 | {
433 | static_cast(receiver)(i, getItemMethod(list, i));
434 | }
435 | }
436 |
437 | template
438 | void iterate_IEnumerable(const void* obj, std::invocable auto&& receiver)
439 | {
440 | const auto klass = get_class_from_instance(obj);
441 | const auto getEnumeratorMethod = reinterpret_cast(il2cpp_class_get_method_from_name(klass, "GetEnumerator", 0)->methodPointer);
442 | const auto enumerator = getEnumeratorMethod(obj);
443 | const auto enumeratorClass = get_class_from_instance(enumerator);
444 | const auto getCurrentMethod = reinterpret_cast(il2cpp_class_get_method_from_name(enumeratorClass, "get_Current", 0)->methodPointer);
445 | const auto moveNextMethod = reinterpret_cast(il2cpp_class_get_method_from_name(enumeratorClass, "MoveNext", 0)->methodPointer);
446 |
447 | while (moveNextMethod(enumerator))
448 | {
449 | static_cast(receiver)(getCurrentMethod(enumerator));
450 | }
451 | }
452 |
453 | Il2CppString* NewWStr(std::wstring_view str);
454 | void* get_system_class_from_reflection_type_str(const char* typeStr, const char* assemblyName = "mscorlib");
455 | }
456 |
--------------------------------------------------------------------------------
/src/imgui/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014-2023 Omar Cornut
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/imgui/imconfig.h:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | // COMPILE-TIME OPTIONS FOR DEAR IMGUI
3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
5 | //-----------------------------------------------------------------------------
6 | // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
7 | // B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
8 | //-----------------------------------------------------------------------------
9 | // You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
10 | // files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
11 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
12 | // Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
13 | //-----------------------------------------------------------------------------
14 |
15 | #pragma once
16 |
17 | //---- Define assertion handler. Defaults to calling assert().
18 | // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
19 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
20 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
21 |
22 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
23 | // Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
24 | // DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
25 | // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
26 | //#define IMGUI_API __declspec( dllexport )
27 | //#define IMGUI_API __declspec( dllimport )
28 |
29 | //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
30 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
31 | //#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
32 |
33 | //---- Disable all of Dear ImGui or don't implement standard windows/tools.
34 | // It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
35 | //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
36 | //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
37 | //#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88).
38 |
39 | //---- Don't implement some functions to reduce linkage requirements.
40 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
41 | //#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
42 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
43 | //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
44 | //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
45 | //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
46 | //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
47 | //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
48 | //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
49 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
50 | //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
51 |
52 | //---- Include imgui_user.h at the end of imgui.h as a convenience
53 | //#define IMGUI_INCLUDE_IMGUI_USER_H
54 |
55 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
56 | //#define IMGUI_USE_BGRA_PACKED_COLOR
57 |
58 | //---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
59 | //#define IMGUI_USE_WCHAR32
60 |
61 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
62 | // By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
63 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
64 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
65 | //#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if enabled
66 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
67 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
68 |
69 | //---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
70 | // Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
71 | //#define IMGUI_USE_STB_SPRINTF
72 |
73 | //---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
74 | // Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
75 | // On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
76 | //#define IMGUI_ENABLE_FREETYPE
77 |
78 | //---- Use stb_truetype to build and rasterize the font atlas (default)
79 | // The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
80 | //#define IMGUI_ENABLE_STB_TRUETYPE
81 |
82 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
83 | // This will be inlined as part of ImVec2 and ImVec4 class declarations.
84 | /*
85 | #define IM_VEC2_CLASS_EXTRA \
86 | constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
87 | operator MyVec2() const { return MyVec2(x,y); }
88 |
89 | #define IM_VEC4_CLASS_EXTRA \
90 | constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
91 | operator MyVec4() const { return MyVec4(x,y,z,w); }
92 | */
93 | //---- ...Or use Dear ImGui's own very basic math operators.
94 | //#define IMGUI_DEFINE_MATH_OPERATORS
95 |
96 | //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
97 | // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
98 | // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
99 | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
100 | //#define ImDrawIdx unsigned int
101 |
102 | //---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
103 | //struct ImDrawList;
104 | //struct ImDrawCmd;
105 | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
106 | //#define ImDrawCallback MyImDrawCallback
107 |
108 | //---- Debug Tools: Macro to break in Debugger
109 | // (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
110 | //#define IM_DEBUG_BREAK IM_ASSERT(0)
111 | //#define IM_DEBUG_BREAK __debugbreak()
112 |
113 | //---- Debug Tools: Enable slower asserts
114 | //#define IMGUI_DEBUG_PARANOID
115 |
116 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
117 | /*
118 | namespace ImGui
119 | {
120 | void MyFunction(const char* name, const MyMatrix44& v);
121 | }
122 | */
123 |
--------------------------------------------------------------------------------
/src/imgui/imgui_impl_dx11.cpp:
--------------------------------------------------------------------------------
1 | // dear imgui: Renderer Backend for DirectX11
2 | // This needs to be used along with a Platform Backend (e.g. Win32)
3 |
4 | // Implemented features:
5 | // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
6 | // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
7 |
8 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
9 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
10 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
11 | // Read online: https://github.com/ocornut/imgui/tree/master/docs
12 |
13 | // CHANGELOG
14 | // (minor and older changes stripped away, please see git history for details)
15 | // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
16 | // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
17 | // 2021-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
18 | // 2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer.
19 | // 2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled).
20 | // 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore.
21 | // 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
22 | // 2019-04-30: DirectX11: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
23 | // 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
24 | // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
25 | // 2018-08-01: DirectX11: Querying for IDXGIFactory instead of IDXGIFactory1 to increase compatibility.
26 | // 2018-07-13: DirectX11: Fixed unreleased resources in Init and Shutdown functions.
27 | // 2018-06-08: Misc: Extracted imgui_impl_dx11.cpp/.h away from the old combined DX11+Win32 example.
28 | // 2018-06-08: DirectX11: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
29 | // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX11_RenderDrawData() in the .h file so you can call it yourself.
30 | // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
31 | // 2016-05-07: DirectX11: Disabling depth-write.
32 |
33 | #include "imgui.h"
34 | #include "imgui_impl_dx11.h"
35 |
36 | // DirectX
37 | #include
38 | #include
39 | #include
40 | #ifdef _MSC_VER
41 | #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
42 | #endif
43 |
44 | // DirectX11 data
45 | struct ImGui_ImplDX11_Data
46 | {
47 | ID3D11Device* pd3dDevice;
48 | ID3D11DeviceContext* pd3dDeviceContext;
49 | IDXGIFactory* pFactory;
50 | ID3D11Buffer* pVB;
51 | ID3D11Buffer* pIB;
52 | ID3D11VertexShader* pVertexShader;
53 | ID3D11InputLayout* pInputLayout;
54 | ID3D11Buffer* pVertexConstantBuffer;
55 | ID3D11PixelShader* pPixelShader;
56 | ID3D11SamplerState* pFontSampler;
57 | ID3D11ShaderResourceView* pFontTextureView;
58 | ID3D11RasterizerState* pRasterizerState;
59 | ID3D11BlendState* pBlendState;
60 | ID3D11DepthStencilState* pDepthStencilState;
61 | int VertexBufferSize;
62 | int IndexBufferSize;
63 |
64 | ImGui_ImplDX11_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
65 | };
66 |
67 | struct VERTEX_CONSTANT_BUFFER_DX11
68 | {
69 | float mvp[4][4];
70 | };
71 |
72 | // Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
73 | // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
74 | static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData()
75 | {
76 | return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
77 | }
78 |
79 | // Functions
80 | static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx)
81 | {
82 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
83 |
84 | // Setup viewport
85 | D3D11_VIEWPORT vp;
86 | memset(&vp, 0, sizeof(D3D11_VIEWPORT));
87 | vp.Width = draw_data->DisplaySize.x;
88 | vp.Height = draw_data->DisplaySize.y;
89 | vp.MinDepth = 0.0f;
90 | vp.MaxDepth = 1.0f;
91 | vp.TopLeftX = vp.TopLeftY = 0;
92 | ctx->RSSetViewports(1, &vp);
93 |
94 | // Setup shader and vertex buffers
95 | unsigned int stride = sizeof(ImDrawVert);
96 | unsigned int offset = 0;
97 | ctx->IASetInputLayout(bd->pInputLayout);
98 | ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset);
99 | ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
100 | ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
101 | ctx->VSSetShader(bd->pVertexShader, nullptr, 0);
102 | ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer);
103 | ctx->PSSetShader(bd->pPixelShader, nullptr, 0);
104 | ctx->PSSetSamplers(0, 1, &bd->pFontSampler);
105 | ctx->GSSetShader(nullptr, nullptr, 0);
106 | ctx->HSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used..
107 | ctx->DSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used..
108 | ctx->CSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used..
109 |
110 | // Setup blend state
111 | const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
112 | ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);
113 | ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0);
114 | ctx->RSSetState(bd->pRasterizerState);
115 | }
116 |
117 | // Render function
118 | void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
119 | {
120 | // Avoid rendering when minimized
121 | if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
122 | return;
123 |
124 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
125 | ID3D11DeviceContext* ctx = bd->pd3dDeviceContext;
126 |
127 | // Create and grow vertex/index buffers if needed
128 | if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
129 | {
130 | if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
131 | bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
132 | D3D11_BUFFER_DESC desc;
133 | memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
134 | desc.Usage = D3D11_USAGE_DYNAMIC;
135 | desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert);
136 | desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
137 | desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
138 | desc.MiscFlags = 0;
139 | if (bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pVB) < 0)
140 | return;
141 | }
142 | if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
143 | {
144 | if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
145 | bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
146 | D3D11_BUFFER_DESC desc;
147 | memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
148 | desc.Usage = D3D11_USAGE_DYNAMIC;
149 | desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);
150 | desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
151 | desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
152 | if (bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pIB) < 0)
153 | return;
154 | }
155 |
156 | // Upload vertex/index data into a single contiguous GPU buffer
157 | D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
158 | if (ctx->Map(bd->pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
159 | return;
160 | if (ctx->Map(bd->pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
161 | return;
162 | ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
163 | ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
164 | for (int n = 0; n < draw_data->CmdListsCount; n++)
165 | {
166 | const ImDrawList* cmd_list = draw_data->CmdLists[n];
167 | memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
168 | memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
169 | vtx_dst += cmd_list->VtxBuffer.Size;
170 | idx_dst += cmd_list->IdxBuffer.Size;
171 | }
172 | ctx->Unmap(bd->pVB, 0);
173 | ctx->Unmap(bd->pIB, 0);
174 |
175 | // Setup orthographic projection matrix into our constant buffer
176 | // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
177 | {
178 | D3D11_MAPPED_SUBRESOURCE mapped_resource;
179 | if (ctx->Map(bd->pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
180 | return;
181 | VERTEX_CONSTANT_BUFFER_DX11* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX11*)mapped_resource.pData;
182 | float L = draw_data->DisplayPos.x;
183 | float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
184 | float T = draw_data->DisplayPos.y;
185 | float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
186 | float mvp[4][4] =
187 | {
188 | { 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
189 | { 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
190 | { 0.0f, 0.0f, 0.5f, 0.0f },
191 | { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
192 | };
193 | memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
194 | ctx->Unmap(bd->pVertexConstantBuffer, 0);
195 | }
196 |
197 | // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
198 | struct BACKUP_DX11_STATE
199 | {
200 | UINT ScissorRectsCount, ViewportsCount;
201 | D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
202 | D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
203 | ID3D11RasterizerState* RS;
204 | ID3D11BlendState* BlendState;
205 | FLOAT BlendFactor[4];
206 | UINT SampleMask;
207 | UINT StencilRef;
208 | ID3D11DepthStencilState* DepthStencilState;
209 | ID3D11ShaderResourceView* PSShaderResource;
210 | ID3D11SamplerState* PSSampler;
211 | ID3D11PixelShader* PS;
212 | ID3D11VertexShader* VS;
213 | ID3D11GeometryShader* GS;
214 | UINT PSInstancesCount, VSInstancesCount, GSInstancesCount;
215 | ID3D11ClassInstance *PSInstances[256], *VSInstances[256], *GSInstances[256]; // 256 is max according to PSSetShader documentation
216 | D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
217 | ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
218 | UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
219 | DXGI_FORMAT IndexBufferFormat;
220 | ID3D11InputLayout* InputLayout;
221 | };
222 | BACKUP_DX11_STATE old = {};
223 | old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
224 | ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
225 | ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
226 | ctx->RSGetState(&old.RS);
227 | ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
228 | ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
229 | ctx->PSGetShaderResources(0, 1, &old.PSShaderResource);
230 | ctx->PSGetSamplers(0, 1, &old.PSSampler);
231 | old.PSInstancesCount = old.VSInstancesCount = old.GSInstancesCount = 256;
232 | ctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount);
233 | ctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount);
234 | ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
235 | ctx->GSGetShader(&old.GS, old.GSInstances, &old.GSInstancesCount);
236 |
237 | ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);
238 | ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
239 | ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
240 | ctx->IAGetInputLayout(&old.InputLayout);
241 |
242 | // Setup desired DX state
243 | ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
244 |
245 | // Render command lists
246 | // (Because we merged all buffers into a single one, we maintain our own offset into them)
247 | int global_idx_offset = 0;
248 | int global_vtx_offset = 0;
249 | ImVec2 clip_off = draw_data->DisplayPos;
250 | for (int n = 0; n < draw_data->CmdListsCount; n++)
251 | {
252 | const ImDrawList* cmd_list = draw_data->CmdLists[n];
253 | for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
254 | {
255 | const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
256 | if (pcmd->UserCallback != nullptr)
257 | {
258 | // User callback, registered via ImDrawList::AddCallback()
259 | // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
260 | if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
261 | ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
262 | else
263 | pcmd->UserCallback(cmd_list, pcmd);
264 | }
265 | else
266 | {
267 | // Project scissor/clipping rectangles into framebuffer space
268 | ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
269 | ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
270 | if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
271 | continue;
272 |
273 | // Apply scissor/clipping rectangle
274 | const D3D11_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
275 | ctx->RSSetScissorRects(1, &r);
276 |
277 | // Bind texture, Draw
278 | ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->GetTexID();
279 | ctx->PSSetShaderResources(0, 1, &texture_srv);
280 | ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
281 | }
282 | }
283 | global_idx_offset += cmd_list->IdxBuffer.Size;
284 | global_vtx_offset += cmd_list->VtxBuffer.Size;
285 | }
286 |
287 | // Restore modified DX state
288 | ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
289 | ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
290 | ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
291 | ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
292 | ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
293 | ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
294 | ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
295 | ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release();
296 | for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release();
297 | ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release();
298 | ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
299 | ctx->GSSetShader(old.GS, old.GSInstances, old.GSInstancesCount); if (old.GS) old.GS->Release();
300 | for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release();
301 | ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
302 | ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
303 | ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
304 | ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
305 | }
306 |
307 | static void ImGui_ImplDX11_CreateFontsTexture()
308 | {
309 | // Build texture atlas
310 | ImGuiIO& io = ImGui::GetIO();
311 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
312 | unsigned char* pixels;
313 | int width, height;
314 | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
315 |
316 | // Upload texture to graphics system
317 | {
318 | D3D11_TEXTURE2D_DESC desc;
319 | ZeroMemory(&desc, sizeof(desc));
320 | desc.Width = width;
321 | desc.Height = height;
322 | desc.MipLevels = 1;
323 | desc.ArraySize = 1;
324 | desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
325 | desc.SampleDesc.Count = 1;
326 | desc.Usage = D3D11_USAGE_DEFAULT;
327 | desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
328 | desc.CPUAccessFlags = 0;
329 |
330 | ID3D11Texture2D* pTexture = nullptr;
331 | D3D11_SUBRESOURCE_DATA subResource;
332 | subResource.pSysMem = pixels;
333 | subResource.SysMemPitch = desc.Width * 4;
334 | subResource.SysMemSlicePitch = 0;
335 | bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
336 | IM_ASSERT(pTexture != nullptr);
337 |
338 | // Create texture view
339 | D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
340 | ZeroMemory(&srvDesc, sizeof(srvDesc));
341 | srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
342 | srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
343 | srvDesc.Texture2D.MipLevels = desc.MipLevels;
344 | srvDesc.Texture2D.MostDetailedMip = 0;
345 | bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &bd->pFontTextureView);
346 | pTexture->Release();
347 | }
348 |
349 | // Store our identifier
350 | io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView);
351 |
352 | // Create texture sampler
353 | // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
354 | {
355 | D3D11_SAMPLER_DESC desc;
356 | ZeroMemory(&desc, sizeof(desc));
357 | desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
358 | desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
359 | desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
360 | desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
361 | desc.MipLODBias = 0.f;
362 | desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
363 | desc.MinLOD = 0.f;
364 | desc.MaxLOD = 0.f;
365 | bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler);
366 | }
367 | }
368 |
369 | bool ImGui_ImplDX11_CreateDeviceObjects()
370 | {
371 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
372 | if (!bd->pd3dDevice)
373 | return false;
374 | if (bd->pFontSampler)
375 | ImGui_ImplDX11_InvalidateDeviceObjects();
376 |
377 | // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
378 | // If you would like to use this DX11 sample code but remove this dependency you can:
379 | // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
380 | // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
381 | // See https://github.com/ocornut/imgui/pull/638 for sources and details.
382 |
383 | // Create the vertex shader
384 | {
385 | static const char* vertexShader =
386 | "cbuffer vertexBuffer : register(b0) \
387 | {\
388 | float4x4 ProjectionMatrix; \
389 | };\
390 | struct VS_INPUT\
391 | {\
392 | float2 pos : POSITION;\
393 | float4 col : COLOR0;\
394 | float2 uv : TEXCOORD0;\
395 | };\
396 | \
397 | struct PS_INPUT\
398 | {\
399 | float4 pos : SV_POSITION;\
400 | float4 col : COLOR0;\
401 | float2 uv : TEXCOORD0;\
402 | };\
403 | \
404 | PS_INPUT main(VS_INPUT input)\
405 | {\
406 | PS_INPUT output;\
407 | output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
408 | output.col = input.col;\
409 | output.uv = input.uv;\
410 | return output;\
411 | }";
412 |
413 | ID3DBlob* vertexShaderBlob;
414 | if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), nullptr, nullptr, nullptr, "main", "vs_4_0", 0, 0, &vertexShaderBlob, nullptr)))
415 | return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
416 | if (bd->pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), nullptr, &bd->pVertexShader) != S_OK)
417 | {
418 | vertexShaderBlob->Release();
419 | return false;
420 | }
421 |
422 | // Create the input layout
423 | D3D11_INPUT_ELEMENT_DESC local_layout[] =
424 | {
425 | { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
426 | { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
427 | { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
428 | };
429 | if (bd->pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pInputLayout) != S_OK)
430 | {
431 | vertexShaderBlob->Release();
432 | return false;
433 | }
434 | vertexShaderBlob->Release();
435 |
436 | // Create the constant buffer
437 | {
438 | D3D11_BUFFER_DESC desc;
439 | desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER_DX11);
440 | desc.Usage = D3D11_USAGE_DYNAMIC;
441 | desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
442 | desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
443 | desc.MiscFlags = 0;
444 | bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pVertexConstantBuffer);
445 | }
446 | }
447 |
448 | // Create the pixel shader
449 | {
450 | static const char* pixelShader =
451 | "struct PS_INPUT\
452 | {\
453 | float4 pos : SV_POSITION;\
454 | float4 col : COLOR0;\
455 | float2 uv : TEXCOORD0;\
456 | };\
457 | sampler sampler0;\
458 | Texture2D texture0;\
459 | \
460 | float4 main(PS_INPUT input) : SV_Target\
461 | {\
462 | float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
463 | return out_col; \
464 | }";
465 |
466 | ID3DBlob* pixelShaderBlob;
467 | if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), nullptr, nullptr, nullptr, "main", "ps_4_0", 0, 0, &pixelShaderBlob, nullptr)))
468 | return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
469 | if (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), nullptr, &bd->pPixelShader) != S_OK)
470 | {
471 | pixelShaderBlob->Release();
472 | return false;
473 | }
474 | pixelShaderBlob->Release();
475 | }
476 |
477 | // Create the blending setup
478 | {
479 | D3D11_BLEND_DESC desc;
480 | ZeroMemory(&desc, sizeof(desc));
481 | desc.AlphaToCoverageEnable = false;
482 | desc.RenderTarget[0].BlendEnable = true;
483 | desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
484 | desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
485 | desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
486 | desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
487 | desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
488 | desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
489 | desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
490 | bd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState);
491 | }
492 |
493 | // Create the rasterizer state
494 | {
495 | D3D11_RASTERIZER_DESC desc;
496 | ZeroMemory(&desc, sizeof(desc));
497 | desc.FillMode = D3D11_FILL_SOLID;
498 | desc.CullMode = D3D11_CULL_NONE;
499 | desc.ScissorEnable = true;
500 | desc.DepthClipEnable = true;
501 | bd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState);
502 | }
503 |
504 | // Create depth-stencil State
505 | {
506 | D3D11_DEPTH_STENCIL_DESC desc;
507 | ZeroMemory(&desc, sizeof(desc));
508 | desc.DepthEnable = false;
509 | desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
510 | desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
511 | desc.StencilEnable = false;
512 | desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
513 | desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
514 | desc.BackFace = desc.FrontFace;
515 | bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState);
516 | }
517 |
518 | ImGui_ImplDX11_CreateFontsTexture();
519 |
520 | return true;
521 | }
522 |
523 | void ImGui_ImplDX11_InvalidateDeviceObjects()
524 | {
525 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
526 | if (!bd->pd3dDevice)
527 | return;
528 |
529 | if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = nullptr; }
530 | if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well.
531 | if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
532 | if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
533 | if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = nullptr; }
534 | if (bd->pDepthStencilState) { bd->pDepthStencilState->Release(); bd->pDepthStencilState = nullptr; }
535 | if (bd->pRasterizerState) { bd->pRasterizerState->Release(); bd->pRasterizerState = nullptr; }
536 | if (bd->pPixelShader) { bd->pPixelShader->Release(); bd->pPixelShader = nullptr; }
537 | if (bd->pVertexConstantBuffer) { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = nullptr; }
538 | if (bd->pInputLayout) { bd->pInputLayout->Release(); bd->pInputLayout = nullptr; }
539 | if (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = nullptr; }
540 | }
541 |
542 | bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
543 | {
544 | ImGuiIO& io = ImGui::GetIO();
545 | IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
546 |
547 | // Setup backend capabilities flags
548 | ImGui_ImplDX11_Data* bd = IM_NEW(ImGui_ImplDX11_Data)();
549 | io.BackendRendererUserData = (void*)bd;
550 | io.BackendRendererName = "imgui_impl_dx11";
551 | io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
552 |
553 | // Get factory from device
554 | IDXGIDevice* pDXGIDevice = nullptr;
555 | IDXGIAdapter* pDXGIAdapter = nullptr;
556 | IDXGIFactory* pFactory = nullptr;
557 |
558 | if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
559 | if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
560 | if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
561 | {
562 | bd->pd3dDevice = device;
563 | bd->pd3dDeviceContext = device_context;
564 | bd->pFactory = pFactory;
565 | }
566 | if (pDXGIDevice) pDXGIDevice->Release();
567 | if (pDXGIAdapter) pDXGIAdapter->Release();
568 | bd->pd3dDevice->AddRef();
569 | bd->pd3dDeviceContext->AddRef();
570 |
571 | return true;
572 | }
573 |
574 | void ImGui_ImplDX11_Shutdown()
575 | {
576 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
577 | IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
578 | ImGuiIO& io = ImGui::GetIO();
579 |
580 | ImGui_ImplDX11_InvalidateDeviceObjects();
581 | if (bd->pFactory) { bd->pFactory->Release(); }
582 | if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
583 | if (bd->pd3dDeviceContext) { bd->pd3dDeviceContext->Release(); }
584 | io.BackendRendererName = nullptr;
585 | io.BackendRendererUserData = nullptr;
586 | IM_DELETE(bd);
587 | }
588 |
589 | void ImGui_ImplDX11_NewFrame()
590 | {
591 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
592 | IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplDX11_Init()?");
593 |
594 | if (!bd->pFontSampler)
595 | ImGui_ImplDX11_CreateDeviceObjects();
596 | }
597 |
--------------------------------------------------------------------------------
/src/imgui/imgui_impl_dx11.h:
--------------------------------------------------------------------------------
1 | // dear imgui: Renderer Backend for DirectX11
2 | // This needs to be used along with a Platform Backend (e.g. Win32)
3 |
4 | // Implemented features:
5 | // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
6 | // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
7 |
8 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
9 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
10 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
11 | // Read online: https://github.com/ocornut/imgui/tree/master/docs
12 |
13 | #pragma once
14 | #include "imgui.h" // IMGUI_IMPL_API
15 |
16 | struct ID3D11Device;
17 | struct ID3D11DeviceContext;
18 |
19 | IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context);
20 | IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown();
21 | IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame();
22 | IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
23 |
24 | // Use if you want to reset your rendering device without losing Dear ImGui state.
25 | IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
26 | IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();
27 |
--------------------------------------------------------------------------------
/src/imgui/imgui_impl_win32.h:
--------------------------------------------------------------------------------
1 | // dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications)
2 | // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
3 |
4 | // Implemented features:
5 | // [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
6 | // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
7 | // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
8 | // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
9 |
10 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
11 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
12 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
13 | // Read online: https://github.com/ocornut/imgui/tree/master/docs
14 |
15 | #pragma once
16 | #include "imgui.h" // IMGUI_IMPL_API
17 |
18 | IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd);
19 | IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown();
20 | IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame();
21 |
22 | // Win32 message handler your application need to call.
23 | // - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on from this helper.
24 | // - You should COPY the line below into your .cpp code to forward declare the function and then you can call it.
25 | // - Call from your application's message handler. Keep calling your message handler unless this function returns TRUE.
26 |
27 | #if 0
28 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
29 | #endif
30 |
31 | // DPI-related helpers (optional)
32 | // - Use to enable DPI awareness without having to create an application manifest.
33 | // - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.
34 | // - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.
35 | // but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,
36 | // neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.
37 | IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness();
38 | IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd
39 | IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor
40 |
41 | // Transparency related helpers (optional) [experimental]
42 | // - Use to enable alpha compositing transparency with the desktop.
43 | // - Use together with e.g. clearing your framebuffer with zero-alpha.
44 | IMGUI_IMPL_API void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd); // HWND hwnd
45 |
--------------------------------------------------------------------------------
/src/imgui/imstb_rectpack.h:
--------------------------------------------------------------------------------
1 | // [DEAR IMGUI]
2 | // This is a slightly modified version of stb_rect_pack.h 1.01.
3 | // Grep for [DEAR IMGUI] to find the changes.
4 | //
5 | // stb_rect_pack.h - v1.01 - public domain - rectangle packing
6 | // Sean Barrett 2014
7 | //
8 | // Useful for e.g. packing rectangular textures into an atlas.
9 | // Does not do rotation.
10 | //
11 | // Before #including,
12 | //
13 | // #define STB_RECT_PACK_IMPLEMENTATION
14 | //
15 | // in the file that you want to have the implementation.
16 | //
17 | // Not necessarily the awesomest packing method, but better than
18 | // the totally naive one in stb_truetype (which is primarily what
19 | // this is meant to replace).
20 | //
21 | // Has only had a few tests run, may have issues.
22 | //
23 | // More docs to come.
24 | //
25 | // No memory allocations; uses qsort() and assert() from stdlib.
26 | // Can override those by defining STBRP_SORT and STBRP_ASSERT.
27 | //
28 | // This library currently uses the Skyline Bottom-Left algorithm.
29 | //
30 | // Please note: better rectangle packers are welcome! Please
31 | // implement them to the same API, but with a different init
32 | // function.
33 | //
34 | // Credits
35 | //
36 | // Library
37 | // Sean Barrett
38 | // Minor features
39 | // Martins Mozeiko
40 | // github:IntellectualKitty
41 | //
42 | // Bugfixes / warning fixes
43 | // Jeremy Jaussaud
44 | // Fabian Giesen
45 | //
46 | // Version history:
47 | //
48 | // 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
49 | // 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
50 | // 0.99 (2019-02-07) warning fixes
51 | // 0.11 (2017-03-03) return packing success/fail result
52 | // 0.10 (2016-10-25) remove cast-away-const to avoid warnings
53 | // 0.09 (2016-08-27) fix compiler warnings
54 | // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
55 | // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
56 | // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
57 | // 0.05: added STBRP_ASSERT to allow replacing assert
58 | // 0.04: fixed minor bug in STBRP_LARGE_RECTS support
59 | // 0.01: initial release
60 | //
61 | // LICENSE
62 | //
63 | // See end of file for license information.
64 |
65 | //////////////////////////////////////////////////////////////////////////////
66 | //
67 | // INCLUDE SECTION
68 | //
69 |
70 | #ifndef STB_INCLUDE_STB_RECT_PACK_H
71 | #define STB_INCLUDE_STB_RECT_PACK_H
72 |
73 | #define STB_RECT_PACK_VERSION 1
74 |
75 | #ifdef STBRP_STATIC
76 | #define STBRP_DEF static
77 | #else
78 | #define STBRP_DEF extern
79 | #endif
80 |
81 | #ifdef __cplusplus
82 | extern "C" {
83 | #endif
84 |
85 | typedef struct stbrp_context stbrp_context;
86 | typedef struct stbrp_node stbrp_node;
87 | typedef struct stbrp_rect stbrp_rect;
88 |
89 | typedef int stbrp_coord;
90 |
91 | #define STBRP__MAXVAL 0x7fffffff
92 | // Mostly for internal use, but this is the maximum supported coordinate value.
93 |
94 | STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
95 | // Assign packed locations to rectangles. The rectangles are of type
96 | // 'stbrp_rect' defined below, stored in the array 'rects', and there
97 | // are 'num_rects' many of them.
98 | //
99 | // Rectangles which are successfully packed have the 'was_packed' flag
100 | // set to a non-zero value and 'x' and 'y' store the minimum location
101 | // on each axis (i.e. bottom-left in cartesian coordinates, top-left
102 | // if you imagine y increasing downwards). Rectangles which do not fit
103 | // have the 'was_packed' flag set to 0.
104 | //
105 | // You should not try to access the 'rects' array from another thread
106 | // while this function is running, as the function temporarily reorders
107 | // the array while it executes.
108 | //
109 | // To pack into another rectangle, you need to call stbrp_init_target
110 | // again. To continue packing into the same rectangle, you can call
111 | // this function again. Calling this multiple times with multiple rect
112 | // arrays will probably produce worse packing results than calling it
113 | // a single time with the full rectangle array, but the option is
114 | // available.
115 | //
116 | // The function returns 1 if all of the rectangles were successfully
117 | // packed and 0 otherwise.
118 |
119 | struct stbrp_rect
120 | {
121 | // reserved for your use:
122 | int id;
123 |
124 | // input:
125 | stbrp_coord w, h;
126 |
127 | // output:
128 | stbrp_coord x, y;
129 | int was_packed; // non-zero if valid packing
130 |
131 | }; // 16 bytes, nominally
132 |
133 |
134 | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
135 | // Initialize a rectangle packer to:
136 | // pack a rectangle that is 'width' by 'height' in dimensions
137 | // using temporary storage provided by the array 'nodes', which is 'num_nodes' long
138 | //
139 | // You must call this function every time you start packing into a new target.
140 | //
141 | // There is no "shutdown" function. The 'nodes' memory must stay valid for
142 | // the following stbrp_pack_rects() call (or calls), but can be freed after
143 | // the call (or calls) finish.
144 | //
145 | // Note: to guarantee best results, either:
146 | // 1. make sure 'num_nodes' >= 'width'
147 | // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
148 | //
149 | // If you don't do either of the above things, widths will be quantized to multiples
150 | // of small integers to guarantee the algorithm doesn't run out of temporary storage.
151 | //
152 | // If you do #2, then the non-quantized algorithm will be used, but the algorithm
153 | // may run out of temporary storage and be unable to pack some rectangles.
154 |
155 | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
156 | // Optionally call this function after init but before doing any packing to
157 | // change the handling of the out-of-temp-memory scenario, described above.
158 | // If you call init again, this will be reset to the default (false).
159 |
160 |
161 | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
162 | // Optionally select which packing heuristic the library should use. Different
163 | // heuristics will produce better/worse results for different data sets.
164 | // If you call init again, this will be reset to the default.
165 |
166 | enum
167 | {
168 | STBRP_HEURISTIC_Skyline_default=0,
169 | STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
170 | STBRP_HEURISTIC_Skyline_BF_sortHeight
171 | };
172 |
173 |
174 | //////////////////////////////////////////////////////////////////////////////
175 | //
176 | // the details of the following structures don't matter to you, but they must
177 | // be visible so you can handle the memory allocations for them
178 |
179 | struct stbrp_node
180 | {
181 | stbrp_coord x,y;
182 | stbrp_node *next;
183 | };
184 |
185 | struct stbrp_context
186 | {
187 | int width;
188 | int height;
189 | int align;
190 | int init_mode;
191 | int heuristic;
192 | int num_nodes;
193 | stbrp_node *active_head;
194 | stbrp_node *free_head;
195 | stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
196 | };
197 |
198 | #ifdef __cplusplus
199 | }
200 | #endif
201 |
202 | #endif
203 |
204 | //////////////////////////////////////////////////////////////////////////////
205 | //
206 | // IMPLEMENTATION SECTION
207 | //
208 |
209 | #ifdef STB_RECT_PACK_IMPLEMENTATION
210 | #ifndef STBRP_SORT
211 | #include
212 | #define STBRP_SORT qsort
213 | #endif
214 |
215 | #ifndef STBRP_ASSERT
216 | #include
217 | #define STBRP_ASSERT assert
218 | #endif
219 |
220 | #ifdef _MSC_VER
221 | #define STBRP__NOTUSED(v) (void)(v)
222 | #define STBRP__CDECL __cdecl
223 | #else
224 | #define STBRP__NOTUSED(v) (void)sizeof(v)
225 | #define STBRP__CDECL
226 | #endif
227 |
228 | enum
229 | {
230 | STBRP__INIT_skyline = 1
231 | };
232 |
233 | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
234 | {
235 | switch (context->init_mode) {
236 | case STBRP__INIT_skyline:
237 | STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
238 | context->heuristic = heuristic;
239 | break;
240 | default:
241 | STBRP_ASSERT(0);
242 | }
243 | }
244 |
245 | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
246 | {
247 | if (allow_out_of_mem)
248 | // if it's ok to run out of memory, then don't bother aligning them;
249 | // this gives better packing, but may fail due to OOM (even though
250 | // the rectangles easily fit). @TODO a smarter approach would be to only
251 | // quantize once we've hit OOM, then we could get rid of this parameter.
252 | context->align = 1;
253 | else {
254 | // if it's not ok to run out of memory, then quantize the widths
255 | // so that num_nodes is always enough nodes.
256 | //
257 | // I.e. num_nodes * align >= width
258 | // align >= width / num_nodes
259 | // align = ceil(width/num_nodes)
260 |
261 | context->align = (context->width + context->num_nodes-1) / context->num_nodes;
262 | }
263 | }
264 |
265 | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
266 | {
267 | int i;
268 |
269 | for (i=0; i < num_nodes-1; ++i)
270 | nodes[i].next = &nodes[i+1];
271 | nodes[i].next = NULL;
272 | context->init_mode = STBRP__INIT_skyline;
273 | context->heuristic = STBRP_HEURISTIC_Skyline_default;
274 | context->free_head = &nodes[0];
275 | context->active_head = &context->extra[0];
276 | context->width = width;
277 | context->height = height;
278 | context->num_nodes = num_nodes;
279 | stbrp_setup_allow_out_of_mem(context, 0);
280 |
281 | // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
282 | context->extra[0].x = 0;
283 | context->extra[0].y = 0;
284 | context->extra[0].next = &context->extra[1];
285 | context->extra[1].x = (stbrp_coord) width;
286 | context->extra[1].y = (1<<30);
287 | context->extra[1].next = NULL;
288 | }
289 |
290 | // find minimum y position if it starts at x1
291 | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
292 | {
293 | stbrp_node *node = first;
294 | int x1 = x0 + width;
295 | int min_y, visited_width, waste_area;
296 |
297 | STBRP__NOTUSED(c);
298 |
299 | STBRP_ASSERT(first->x <= x0);
300 |
301 | #if 0
302 | // skip in case we're past the node
303 | while (node->next->x <= x0)
304 | ++node;
305 | #else
306 | STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
307 | #endif
308 |
309 | STBRP_ASSERT(node->x <= x0);
310 |
311 | min_y = 0;
312 | waste_area = 0;
313 | visited_width = 0;
314 | while (node->x < x1) {
315 | if (node->y > min_y) {
316 | // raise min_y higher.
317 | // we've accounted for all waste up to min_y,
318 | // but we'll now add more waste for everything we've visted
319 | waste_area += visited_width * (node->y - min_y);
320 | min_y = node->y;
321 | // the first time through, visited_width might be reduced
322 | if (node->x < x0)
323 | visited_width += node->next->x - x0;
324 | else
325 | visited_width += node->next->x - node->x;
326 | } else {
327 | // add waste area
328 | int under_width = node->next->x - node->x;
329 | if (under_width + visited_width > width)
330 | under_width = width - visited_width;
331 | waste_area += under_width * (min_y - node->y);
332 | visited_width += under_width;
333 | }
334 | node = node->next;
335 | }
336 |
337 | *pwaste = waste_area;
338 | return min_y;
339 | }
340 |
341 | typedef struct
342 | {
343 | int x,y;
344 | stbrp_node **prev_link;
345 | } stbrp__findresult;
346 |
347 | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
348 | {
349 | int best_waste = (1<<30), best_x, best_y = (1 << 30);
350 | stbrp__findresult fr;
351 | stbrp_node **prev, *node, *tail, **best = NULL;
352 |
353 | // align to multiple of c->align
354 | width = (width + c->align - 1);
355 | width -= width % c->align;
356 | STBRP_ASSERT(width % c->align == 0);
357 |
358 | // if it can't possibly fit, bail immediately
359 | if (width > c->width || height > c->height) {
360 | fr.prev_link = NULL;
361 | fr.x = fr.y = 0;
362 | return fr;
363 | }
364 |
365 | node = c->active_head;
366 | prev = &c->active_head;
367 | while (node->x + width <= c->width) {
368 | int y,waste;
369 | y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
370 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
371 | // bottom left
372 | if (y < best_y) {
373 | best_y = y;
374 | best = prev;
375 | }
376 | } else {
377 | // best-fit
378 | if (y + height <= c->height) {
379 | // can only use it if it first vertically
380 | if (y < best_y || (y == best_y && waste < best_waste)) {
381 | best_y = y;
382 | best_waste = waste;
383 | best = prev;
384 | }
385 | }
386 | }
387 | prev = &node->next;
388 | node = node->next;
389 | }
390 |
391 | best_x = (best == NULL) ? 0 : (*best)->x;
392 |
393 | // if doing best-fit (BF), we also have to try aligning right edge to each node position
394 | //
395 | // e.g, if fitting
396 | //
397 | // ____________________
398 | // |____________________|
399 | //
400 | // into
401 | //
402 | // | |
403 | // | ____________|
404 | // |____________|
405 | //
406 | // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
407 | //
408 | // This makes BF take about 2x the time
409 |
410 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
411 | tail = c->active_head;
412 | node = c->active_head;
413 | prev = &c->active_head;
414 | // find first node that's admissible
415 | while (tail->x < width)
416 | tail = tail->next;
417 | while (tail) {
418 | int xpos = tail->x - width;
419 | int y,waste;
420 | STBRP_ASSERT(xpos >= 0);
421 | // find the left position that matches this
422 | while (node->next->x <= xpos) {
423 | prev = &node->next;
424 | node = node->next;
425 | }
426 | STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
427 | y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
428 | if (y + height <= c->height) {
429 | if (y <= best_y) {
430 | if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
431 | best_x = xpos;
432 | //STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
433 | best_y = y;
434 | best_waste = waste;
435 | best = prev;
436 | }
437 | }
438 | }
439 | tail = tail->next;
440 | }
441 | }
442 |
443 | fr.prev_link = best;
444 | fr.x = best_x;
445 | fr.y = best_y;
446 | return fr;
447 | }
448 |
449 | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
450 | {
451 | // find best position according to heuristic
452 | stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
453 | stbrp_node *node, *cur;
454 |
455 | // bail if:
456 | // 1. it failed
457 | // 2. the best node doesn't fit (we don't always check this)
458 | // 3. we're out of memory
459 | if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
460 | res.prev_link = NULL;
461 | return res;
462 | }
463 |
464 | // on success, create new node
465 | node = context->free_head;
466 | node->x = (stbrp_coord) res.x;
467 | node->y = (stbrp_coord) (res.y + height);
468 |
469 | context->free_head = node->next;
470 |
471 | // insert the new node into the right starting point, and
472 | // let 'cur' point to the remaining nodes needing to be
473 | // stiched back in
474 |
475 | cur = *res.prev_link;
476 | if (cur->x < res.x) {
477 | // preserve the existing one, so start testing with the next one
478 | stbrp_node *next = cur->next;
479 | cur->next = node;
480 | cur = next;
481 | } else {
482 | *res.prev_link = node;
483 | }
484 |
485 | // from here, traverse cur and free the nodes, until we get to one
486 | // that shouldn't be freed
487 | while (cur->next && cur->next->x <= res.x + width) {
488 | stbrp_node *next = cur->next;
489 | // move the current node to the free list
490 | cur->next = context->free_head;
491 | context->free_head = cur;
492 | cur = next;
493 | }
494 |
495 | // stitch the list back in
496 | node->next = cur;
497 |
498 | if (cur->x < res.x + width)
499 | cur->x = (stbrp_coord) (res.x + width);
500 |
501 | #ifdef _DEBUG
502 | cur = context->active_head;
503 | while (cur->x < context->width) {
504 | STBRP_ASSERT(cur->x < cur->next->x);
505 | cur = cur->next;
506 | }
507 | STBRP_ASSERT(cur->next == NULL);
508 |
509 | {
510 | int count=0;
511 | cur = context->active_head;
512 | while (cur) {
513 | cur = cur->next;
514 | ++count;
515 | }
516 | cur = context->free_head;
517 | while (cur) {
518 | cur = cur->next;
519 | ++count;
520 | }
521 | STBRP_ASSERT(count == context->num_nodes+2);
522 | }
523 | #endif
524 |
525 | return res;
526 | }
527 |
528 | static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
529 | {
530 | const stbrp_rect *p = (const stbrp_rect *) a;
531 | const stbrp_rect *q = (const stbrp_rect *) b;
532 | if (p->h > q->h)
533 | return -1;
534 | if (p->h < q->h)
535 | return 1;
536 | return (p->w > q->w) ? -1 : (p->w < q->w);
537 | }
538 |
539 | static int STBRP__CDECL rect_original_order(const void *a, const void *b)
540 | {
541 | const stbrp_rect *p = (const stbrp_rect *) a;
542 | const stbrp_rect *q = (const stbrp_rect *) b;
543 | return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
544 | }
545 |
546 | STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
547 | {
548 | int i, all_rects_packed = 1;
549 |
550 | // we use the 'was_packed' field internally to allow sorting/unsorting
551 | for (i=0; i < num_rects; ++i) {
552 | rects[i].was_packed = i;
553 | }
554 |
555 | // sort according to heuristic
556 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
557 |
558 | for (i=0; i < num_rects; ++i) {
559 | if (rects[i].w == 0 || rects[i].h == 0) {
560 | rects[i].x = rects[i].y = 0; // empty rect needs no space
561 | } else {
562 | stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
563 | if (fr.prev_link) {
564 | rects[i].x = (stbrp_coord) fr.x;
565 | rects[i].y = (stbrp_coord) fr.y;
566 | } else {
567 | rects[i].x = rects[i].y = STBRP__MAXVAL;
568 | }
569 | }
570 | }
571 |
572 | // unsort
573 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
574 |
575 | // set was_packed flags and all_rects_packed status
576 | for (i=0; i < num_rects; ++i) {
577 | rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
578 | if (!rects[i].was_packed)
579 | all_rects_packed = 0;
580 | }
581 |
582 | // return the all_rects_packed status
583 | return all_rects_packed;
584 | }
585 | #endif
586 |
587 | /*
588 | ------------------------------------------------------------------------------
589 | This software is available under 2 licenses -- choose whichever you prefer.
590 | ------------------------------------------------------------------------------
591 | ALTERNATIVE A - MIT License
592 | Copyright (c) 2017 Sean Barrett
593 | Permission is hereby granted, free of charge, to any person obtaining a copy of
594 | this software and associated documentation files (the "Software"), to deal in
595 | the Software without restriction, including without limitation the rights to
596 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
597 | of the Software, and to permit persons to whom the Software is furnished to do
598 | so, subject to the following conditions:
599 | The above copyright notice and this permission notice shall be included in all
600 | copies or substantial portions of the Software.
601 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
602 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
603 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
604 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
605 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
606 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
607 | SOFTWARE.
608 | ------------------------------------------------------------------------------
609 | ALTERNATIVE B - Public Domain (www.unlicense.org)
610 | This is free and unencumbered software released into the public domain.
611 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
612 | software, either in source code form or as a compiled binary, for any purpose,
613 | commercial or non-commercial, and by any means.
614 | In jurisdictions that recognize copyright laws, the author or authors of this
615 | software dedicate any and all copyright interest in the software to the public
616 | domain. We make this dedication for the benefit of the public at large and to
617 | the detriment of our heirs and successors. We intend this dedication to be an
618 | overt act of relinquishment in perpetuity of all present and future rights to
619 | this software under copyright law.
620 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
621 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
622 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
623 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
624 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
625 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
626 | ------------------------------------------------------------------------------
627 | */
628 |
--------------------------------------------------------------------------------
/src/local/local.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chinosk6/scsp-localify/fc36b8a03d26dcff6aeaba0b2c77cf62f11a75c3/src/local/local.cpp
--------------------------------------------------------------------------------
/src/local/local.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | namespace SCLocal {
5 | void loadLocalTrans();
6 | bool getLocalifyText(const std::string& category, int id, std::string* getStr);
7 | bool getLocalifyText(const std::wstring& category, int id, std::wstring* getStr);
8 | std::filesystem::path getFilePathByName(const std::wstring& gamePath, bool createFatherPath, const std::filesystem::path& fatherBase);
9 | bool getLocalFileName(const std::wstring& gamePath, std::filesystem::path* localPath, bool checkExists = true);
10 | std::string getLyricsTrans(const std::wstring& orig);
11 | bool getGameUnlocalTrans(const std::wstring& orig, std::string* newStr);
12 | }
13 |
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | extern bool init_hook();
16 | extern void uninit_hook();
17 | extern void start_console();
18 |
19 | using namespace web;
20 | using namespace http;
21 | using namespace utility;
22 | using namespace http::experimental::listener;
23 |
24 |
25 | bool g_enable_plugin = true;
26 | bool g_enable_console = true;
27 | bool g_auto_dump_all_json = false;
28 | bool g_dump_untrans_lyrics = false;
29 | bool g_dump_untrans_unlocal = false;
30 | int g_max_fps = 60;
31 | int g_vsync_count = 0;
32 | float g_3d_resolution_scale = 1.0f;
33 | std::string g_custom_font_path = "";
34 | std::list g_extra_assetbundle_paths{};
35 | char hotKey = 'u';
36 | float g_font_size_offset = -3.0f;
37 |
38 | bool g_enable_free_camera = false;
39 | bool g_block_out_of_focus = false;
40 | float g_free_camera_mouse_speed = 35;
41 | bool g_allow_use_tryon_costume = false;
42 | bool g_allow_same_idol = false;
43 | bool g_unlock_all_dress = false;
44 | bool g_unlock_all_headwear = false;
45 | bool g_enable_chara_param_edit = false;
46 | bool g_unlock_PIdol_and_SChara_events = false;
47 | int g_start_resolution_w = -1;
48 | int g_start_resolution_h = -1;
49 | bool g_start_resolution_fullScreen = false;
50 |
51 | std::filesystem::path g_localify_base("scsp_localify");
52 | constexpr const char ConfigJson[] = "scsp-config.json";
53 |
54 | const auto CONSOLE_TITLE = L"iM@S SCSP Tools By chinosk";
55 |
56 | namespace
57 | {
58 | void create_debug_console()
59 | {
60 | AllocConsole();
61 |
62 | // open stdout stream
63 | auto _ = freopen("CONOUT$", "w+t", stdout);
64 | _ = freopen("CONOUT$", "w", stderr);
65 | _ = freopen("CONIN$", "r", stdin);
66 |
67 | SetConsoleTitleW(CONSOLE_TITLE);
68 |
69 | // set this to avoid turn japanese texts into question mark
70 | SetConsoleOutputCP(65001);
71 | std::locale::global(std::locale(""));
72 |
73 | wprintf(L"THEiDOLM@STER ShinyColors Song for Prism tools loaded! - By chinosk\n");
74 | }
75 | }
76 |
77 |
78 |
79 | namespace
80 | {
81 | std::vector read_config()
82 | {
83 | std::ifstream config_stream{ ConfigJson };
84 | std::vector dicts{};
85 |
86 | if (!config_stream.is_open())
87 | return dicts;
88 |
89 | rapidjson::IStreamWrapper wrapper{ config_stream };
90 | rapidjson::Document document;
91 |
92 | document.ParseStream(wrapper);
93 |
94 | if (!document.HasParseError())
95 | {
96 | if (document.HasMember("enableVSync")) {
97 | if (document["enableVSync"].GetBool()) {
98 | g_vsync_count = 1;
99 | }
100 | else {
101 | g_vsync_count = 0;
102 | }
103 | }
104 | if (document.HasMember("vSyncCount")) {
105 | g_vsync_count = document["vSyncCount"].GetInt();
106 | }
107 | if (document.HasMember("maxFps")) {
108 | g_max_fps = document["maxFps"].GetInt();
109 | }
110 | if (document.HasMember("3DResolutionScale")) {
111 | g_3d_resolution_scale = document["3DResolutionScale"].GetFloat();
112 | }
113 |
114 | if (document.HasMember("enableConsole")) {
115 | g_enable_console = document["enableConsole"].GetBool();
116 | }
117 | if (document.HasMember("localifyBasePath")) {
118 | g_localify_base = document["localifyBasePath"].GetString();
119 | }
120 | if (document.HasMember("hotKey")) {
121 | hotKey = document["hotKey"].GetString()[0];
122 | }
123 | if (document.HasMember("autoDumpAllJson")) {
124 | g_auto_dump_all_json = document["autoDumpAllJson"].GetBool();
125 | }
126 | if (document.HasMember("dumpUntransLyrics")) {
127 | g_dump_untrans_lyrics = document["dumpUntransLyrics"].GetBool();
128 | }
129 | if (document.HasMember("dumpUntransLocal2")) {
130 | g_dump_untrans_unlocal = document["dumpUntransLocal2"].GetBool();
131 | }
132 | g_extra_assetbundle_paths.clear();
133 | if (document.HasMember("extraAssetBundlePath")) {
134 | const auto& extraAssetBundlePath = document["extraAssetBundlePath"];
135 | if (extraAssetBundlePath.IsString())
136 | {
137 | g_extra_assetbundle_paths.push_back(extraAssetBundlePath.GetString());
138 | }
139 | }
140 | if (document.HasMember("extraAssetBundlePaths")) {
141 | const auto& extraAssetBundlePaths = document["extraAssetBundlePaths"];
142 | if (extraAssetBundlePaths.IsArray())
143 | {
144 | for (const auto& i : document["extraAssetBundlePaths"].GetArray()) {
145 | g_extra_assetbundle_paths.push_back(i.GetString());
146 | }
147 | }
148 | }
149 | if (document.HasMember("customFontPath")) {
150 | g_custom_font_path = document["customFontPath"].GetString();
151 | }
152 | if (document.HasMember("fontSizeOffset")) {
153 | g_font_size_offset = document["fontSizeOffset"].GetFloat();
154 | }
155 |
156 | if (document.HasMember("blockOutOfFocus")) {
157 | g_block_out_of_focus = document["blockOutOfFocus"].GetBool();
158 | }
159 |
160 | if (document.HasMember("baseFreeCamera")) {
161 | const auto& freeCamConfig = document["baseFreeCamera"];
162 | if (freeCamConfig.IsObject()) {
163 | if (freeCamConfig.HasMember("enable")) {
164 | g_enable_free_camera = freeCamConfig["enable"].GetBool();
165 | }
166 | if (freeCamConfig.HasMember("moveStep")) {
167 | BaseCamera::moveStep = freeCamConfig["moveStep"].GetFloat() / 1000;
168 | }
169 | if (freeCamConfig.HasMember("mouseSpeed")) {
170 | g_free_camera_mouse_speed = freeCamConfig["mouseSpeed"].GetFloat();
171 | }
172 | }
173 | }
174 |
175 | if (document.HasMember("allowUseTryOnCostume")) {
176 | g_allow_use_tryon_costume = document["allowUseTryOnCostume"].GetBool();
177 | }
178 | if (document.HasMember("allowSameIdol")) {
179 | g_allow_same_idol = document["allowSameIdol"].GetBool();
180 | }
181 | if (document.HasMember("unlockAllDress")) {
182 | g_unlock_all_dress = document["unlockAllDress"].GetBool();
183 | }
184 | if (document.HasMember("unlockAllHeadwear")) {
185 | g_unlock_all_headwear = document["unlockAllHeadwear"].GetBool() && g_unlock_all_dress;
186 | }
187 | if (document.HasMember("unlockPIdolAndSCharaEvents")) {
188 | g_unlock_PIdol_and_SChara_events = document["unlockPIdolAndSCharaEvents"].GetBool();
189 | }
190 |
191 | if (document.HasMember("startResolution")) {
192 | auto& startResolution = document["startResolution"];
193 | g_start_resolution_w = startResolution["w"].GetInt();
194 | g_start_resolution_h = startResolution["h"].GetInt();
195 | g_start_resolution_fullScreen = startResolution["isFull"].GetBool();
196 | }
197 |
198 | }
199 |
200 | config_stream.close();
201 | return dicts;
202 | }
203 | }
204 |
205 | void reloadTransData() {
206 | SCLocal::loadLocalTrans();
207 | }
208 |
209 | void reload_all_data() {
210 | read_config();
211 | reloadTransData();
212 | }
213 |
214 | extern std::function g_on_hook_ready;
215 | std::function g_reload_all_data = reload_all_data;
216 |
217 | int __stdcall DllMain(HINSTANCE dllModule, DWORD reason, LPVOID)
218 | {
219 | if (reason == DLL_PROCESS_ATTACH)
220 | {
221 | // the DMM Launcher set start path to system32 wtf????
222 | std::string module_name;
223 | module_name.resize(MAX_PATH);
224 | module_name.resize(GetModuleFileName(nullptr, module_name.data(), MAX_PATH));
225 |
226 | std::filesystem::path module_path(module_name);
227 |
228 | // check name
229 | if (module_path.filename() != "imasscprism.exe")
230 | return 1;
231 |
232 | std::filesystem::current_path(
233 | module_path.parent_path()
234 | );
235 |
236 |
237 | auto dicts = read_config();
238 |
239 | if (g_enable_console) {
240 | create_debug_console();
241 | printf("Command: %s\n", GetCommandLineA());
242 | }
243 |
244 | std::thread init_thread([dicts = std::move(dicts)] {
245 |
246 | if (g_enable_console)
247 | {
248 | start_console();
249 | }
250 |
251 | init_hook();
252 |
253 | std::mutex mutex;
254 | std::condition_variable cond;
255 | std::atomic hookIsReady(false);
256 | g_on_hook_ready = [&]
257 | {
258 | hookIsReady.store(true, std::memory_order_release);
259 | cond.notify_one();
260 | };
261 |
262 | // 依赖检查游戏版本的指针加载,因此在 hook 完成后再加载翻译数据
263 | std::unique_lock lock(mutex);
264 | cond.wait(lock, [&] {
265 | return hookIsReady.load(std::memory_order_acquire);
266 | });
267 | if (g_enable_console)
268 | {
269 | auto _ = freopen("CONOUT$", "w+t", stdout);
270 | _ = freopen("CONOUT$", "w", stderr);
271 | _ = freopen("CONIN$", "r", stdin);
272 | }
273 |
274 | reloadTransData();
275 | SetConsoleTitleW(CONSOLE_TITLE); // 保持控制台标题
276 | });
277 | init_thread.detach();
278 | }
279 | else if (reason == DLL_PROCESS_DETACH)
280 | {
281 | uninit_hook();
282 | }
283 | return 1;
284 | }
285 |
--------------------------------------------------------------------------------
/src/mhotkey.cpp:
--------------------------------------------------------------------------------
1 | // #define _WIN32_WINNT 0x0400
2 | #pragma comment( lib, "user32.lib" )
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include "camera/camera.hpp"
12 |
13 | extern std::function on_hotKey_0;
14 | extern std::function g_on_close;
15 |
16 | namespace MHotkey{
17 | namespace {
18 | HHOOK hKeyboardHook;
19 | bool is_uma = false;
20 | char hotk = 'u';
21 | std::string extPluginPath = "";
22 | std::string umaArgs = "";
23 | bool openPluginSuccess = false;
24 | DWORD pluginPID = -1;
25 | int tlgport = 43215;
26 | bool ext_server_start = false;
27 |
28 | std::function mKeyBoardCallBack = nullptr;
29 | std::function mKeyBoardRawCallBack = nullptr;
30 | bool hotKeyThreadStarted = false;
31 | }
32 |
33 | bool get_is_plugin_open() {
34 | return openPluginSuccess && ext_server_start;
35 | }
36 |
37 | void set_ext_server_start(const bool status)
38 | {
39 | ext_server_start = status;
40 | }
41 |
42 | void SetKeyCallBack(std::function callbackfun) {
43 | mKeyBoardCallBack = callbackfun;
44 | }
45 |
46 | bool check_file_exist(const std::string& name) {
47 | struct stat buffer;
48 | return (stat(name.c_str(), &buffer) == 0);
49 | }
50 |
51 | bool setWindowPosOffset(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags) {
52 | RECT* windowR = new RECT;
53 | RECT* clientR = new RECT;
54 | GetWindowRect(hWnd, windowR);
55 | GetClientRect(hWnd, clientR);
56 |
57 | return SetWindowPos(hWnd, hWndInsertAfter, X, Y, cx + windowR->right - windowR->left - clientR->right,
58 | cy + windowR->bottom - windowR->top - clientR->bottom, uFlags);
59 | }
60 |
61 | void setMKeyBoardRawCallBack(std::function cbfunc) {
62 | mKeyBoardRawCallBack = cbfunc;
63 | }
64 |
65 |
66 | WNDPROC g_pfnOldWndProc = NULL;
67 | LRESULT CALLBACK WndProcCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
68 | DWORD SHIFT_key = 0;
69 | DWORD CTRL_key = 0;
70 | DWORD ALT_key = 0;
71 | DWORD SPACE_key = 0;
72 | DWORD UP_key = 0;
73 | DWORD DOWN_key = 0;
74 | DWORD LEFT_key = 0;
75 | DWORD RIGHT_key = 0;
76 |
77 | switch (uMsg) {
78 | case WM_INPUT: {
79 | RAWINPUT rawInput;
80 | UINT size = sizeof(RAWINPUT);
81 | if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &rawInput, &size, sizeof(RAWINPUTHEADER)) == size) {
82 |
83 | if (rawInput.header.dwType == RIM_TYPEMOUSE)
84 | {
85 | switch (rawInput.data.mouse.ulButtons) {
86 | case 0: { // move
87 | SCCamera::mouseMove(rawInput.data.mouse.lLastX, rawInput.data.mouse.lLastY, 3);
88 | }; break;
89 | case 4: { // press
90 | SCCamera::mouseMove(0, 0, 1);
91 | }; break;
92 | case 8: { // release
93 | SCCamera::mouseMove(0, 0, 2);
94 | }; break;
95 | default: break;
96 | }
97 |
98 | if (rawInput.data.mouse.usButtonFlags == RI_MOUSE_WHEEL) {
99 | if (rawInput.data.mouse.usButtonData == 120) {
100 | SCCamera::mouseMove(0, 1, 4);
101 | }
102 | else {
103 | SCCamera::mouseMove(0, -1, 4);
104 | }
105 | }
106 |
107 | }
108 | }
109 | }; break;
110 |
111 | case WM_SYSKEYUP:
112 | case WM_KEYUP: {
113 | int key = wParam;
114 | if (mKeyBoardRawCallBack != nullptr) mKeyBoardRawCallBack(uMsg, key);
115 | }; break;
116 |
117 | case WM_SYSKEYDOWN:
118 | case WM_KEYDOWN: {
119 | int key = wParam;
120 |
121 | if (mKeyBoardRawCallBack != nullptr) mKeyBoardRawCallBack(uMsg, key);
122 | SHIFT_key = GetAsyncKeyState(VK_SHIFT);
123 | CTRL_key = GetAsyncKeyState(VK_CONTROL);
124 | ALT_key = GetAsyncKeyState(VK_MENU);
125 | SPACE_key = GetAsyncKeyState(VK_SPACE);
126 |
127 | UP_key = GetAsyncKeyState(VK_UP);
128 | DOWN_key = GetAsyncKeyState(VK_DOWN);
129 | LEFT_key = GetAsyncKeyState(VK_LEFT);
130 | RIGHT_key = GetAsyncKeyState(VK_RIGHT);
131 |
132 | if (mKeyBoardCallBack != nullptr) {
133 | mKeyBoardCallBack(key, SHIFT_key, CTRL_key, ALT_key, SPACE_key, UP_key, DOWN_key, LEFT_key, RIGHT_key);
134 | }
135 |
136 | if (key >= 'A' && key <= 'Z')
137 | {
138 |
139 | if (GetAsyncKeyState(VK_SHIFT) >= 0) key += 32;
140 |
141 | if (CTRL_key != 0 && key == hotk)
142 | {
143 | // fopenExternalPlugin(tlgport);
144 | printf("hotKey pressed.\n");
145 | if (on_hotKey_0) on_hotKey_0();
146 | }
147 |
148 | SHIFT_key = 0;
149 | CTRL_key = 0;
150 | ALT_key = 0;
151 | SPACE_key = 0;
152 | DWORD UP_key = 0;
153 | DWORD DOWN_key = 0;
154 | DWORD LEFT_key = 0;
155 | DWORD RIGHT_key = 0;
156 | }
157 | }; break;
158 | case WM_NCACTIVATE: {
159 | if (!wParam) {
160 | SCCamera::onKillFocus();
161 | return FALSE;
162 | }
163 | }; break;
164 | case WM_KILLFOCUS: {
165 | SCCamera::onKillFocus();
166 | return FALSE;
167 | }; break;
168 | case WM_CLOSE: {
169 | if (g_on_close) g_on_close();
170 | }; break;
171 | default: break;
172 | }
173 |
174 | return CallWindowProc(g_pfnOldWndProc, hWnd, uMsg, wParam, lParam);
175 | }
176 |
177 | void InstallWndProcHook()
178 | {
179 | g_pfnOldWndProc = (WNDPROC)GetWindowLongPtr(FindWindowW(L"UnityWndClass", L"imasscprism"), GWLP_WNDPROC);
180 | SetWindowLongPtr(FindWindowW(L"UnityWndClass", L"imasscprism"), GWLP_WNDPROC, (LONG_PTR)WndProcCallback);
181 | }
182 |
183 | void UninstallWndProcHook(HWND hWnd)
184 | {
185 | SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)g_pfnOldWndProc);
186 | }
187 |
188 | bool get_uma_stat() {
189 | return MHotkey::is_uma;
190 | }
191 | void set_uma_stat(bool s) {
192 | MHotkey::is_uma = s;
193 | }
194 |
195 | void setExtPluginPath(std::string ppath) {
196 | MHotkey::extPluginPath = ppath;
197 | }
198 | void setUmaCommandLine(std::string args) {
199 | MHotkey::umaArgs = args;
200 | }
201 | void setTlgPort(int port) {
202 | tlgport = port;
203 | }
204 |
205 | int start_hotkey(char sethotk='u')
206 | {
207 | MHotkey::hotk = sethotk;
208 | if (hotKeyThreadStarted) return 1;
209 |
210 | HANDLE hThread;
211 | DWORD dwThread;
212 |
213 | hotKeyThreadStarted = true;
214 | InstallWndProcHook();
215 |
216 | return 1;
217 |
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/src/mhotkey.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace MHotkey {
4 | void SetKeyCallBack(std::function callbackfun);
5 | bool get_is_plugin_open();
6 | void set_ext_server_start(bool status);
7 | bool get_uma_stat();
8 | void set_uma_stat(bool s);
9 | int start_hotkey(char sethotk = 'u');
10 | void setExtPluginPath(std::string ppath);
11 | void setUmaCommandLine(std::string args);
12 | void setTlgPort(int port);
13 | void setMKeyBoardRawCallBack(std::function cbfunc);
14 | }
15 |
--------------------------------------------------------------------------------
/src/scgui/scGUIData.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | namespace SCGUIData {
4 | bool needExtractText = false;
5 |
6 | int screenW = 1280;
7 | int screenH = 720;
8 | bool screenFull = false;
9 |
10 | float sysCamFov = 60;
11 | Vector3_t sysCamPos{};
12 | Vector3_t sysCamLookAt{};
13 | Quaternion_t sysCamRot{};
14 |
15 | void updateSysCamLookAt() {
16 | BaseCamera::CameraPosRotToLookAt(sysCamPos, sysCamRot, &sysCamLookAt);
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/scgui/scGUIData.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace SCGUIData {
4 | extern bool needExtractText;
5 | extern int screenW;
6 | extern int screenH;
7 | extern bool screenFull;
8 |
9 | extern float sysCamFov;
10 | extern Vector3_t sysCamPos;
11 | extern Vector3_t sysCamLookAt;
12 | extern Quaternion_t sysCamRot;
13 |
14 | void updateSysCamLookAt();
15 | }
16 |
--------------------------------------------------------------------------------
/src/scgui/scGUILoop.cpp:
--------------------------------------------------------------------------------
1 | #include "imgui/imgui.h"
2 | #include "stdinclude.hpp"
3 | #include "scgui/scGUIData.hpp"
4 |
5 | extern void* SetResolution_orig;
6 | // extern std::vector, int>> replaceDressResIds;
7 | extern std::map charaParam;
8 | extern CharaParam_t baseParam;
9 | extern void saveGUIDataCache();
10 |
11 |
12 | #define INPUT_AND_SLIDER_FLOAT(label, data, min, max) \
13 | ImGui::SetNextItemWidth(inputFloatWidth);\
14 | ImGui::InputFloat("##"##label, data);\
15 | ImGui::SameLine();\
16 | ImGui::SetNextItemWidth(ImGui::CalcItemWidth() - inputFloatWidth - 1.0f);\
17 | ImGui::SliderFloat(label, data, min, max)
18 |
19 | #define FOR_INPUT_AND_SLIDER_FLOAT(label, data, min, max, hideIdName) \
20 | ImGui::SetNextItemWidth(inputFloatWidth);\
21 | ImGui::InputFloat(("##"##label + hideIdName).c_str(), data);\
22 | ImGui::SameLine();\
23 | ImGui::SetNextItemWidth(ImGui::CalcItemWidth() - inputFloatWidth - 1.0f);\
24 | ImGui::SliderFloat((label##"##" + hideIdName).c_str(), data, min, max)
25 |
26 | #define HELP_TOOLTIP(label, text) \
27 | ImGui::TextDisabled(label); \
28 | if (ImGui::IsItemHovered()) { \
29 | ImGui::BeginTooltip(); \
30 | ImGui::Text(text); \
31 | ImGui::EndTooltip(); \
32 | }
33 |
34 | namespace SCGUILoop {
35 | static float inputFloatWidth = 50.0f;
36 |
37 | void charaParamEditLoop() {
38 | if (ImGui::Begin("Character Parameter Edit")) {
39 | if (ImGui::CollapsingHeader("Sway offset (Non real-time, requires reloading)")) {
40 | static int currentEdit = 0x7; // BreastPointed
41 |
42 | if (ImGui::BeginCombo("Edit Type", swayTypes[currentEdit].c_str())) {
43 | for (const auto& pair : swayTypes) {
44 | bool isSelected = (currentEdit == pair.first);
45 | if (ImGui::Selectable(pair.second.c_str(), isSelected)) {
46 | currentEdit = pair.first;
47 | }
48 | if (isSelected) {
49 | ImGui::SetItemDefaultFocus();
50 | }
51 | }
52 | ImGui::EndCombo();
53 | }
54 |
55 | auto& currEditData = charaSwayStringOffset[currentEdit];
56 |
57 | INPUT_AND_SLIDER_FLOAT("Rate##sway", &currEditData.rate, -1.5, 1.5);
58 | INPUT_AND_SLIDER_FLOAT("BendStrength##sway", &currEditData.P_bendStrength, -5, 5.0);
59 | INPUT_AND_SLIDER_FLOAT("BaseGravity##sway", &currEditData.P_baseGravity, -50, 50.0);
60 | INPUT_AND_SLIDER_FLOAT("InertiaMoment##sway", &currEditData.P_inertiaMoment, -2, 2.0);
61 | INPUT_AND_SLIDER_FLOAT("AirResistance##sway", &currEditData.P_airResistance, -2, 2.0);
62 | INPUT_AND_SLIDER_FLOAT("DeformResistance##sway", &currEditData.P_deformResistance, -30, 30.0);
63 |
64 | if (ImGui::Button("Reset##sway")) {
65 | currEditData.rate = 0;
66 | currEditData.P_bendStrength = 0;
67 | currEditData.P_baseGravity = 0;
68 | currEditData.P_inertiaMoment = 0;
69 | currEditData.P_airResistance = 0;
70 | currEditData.P_deformResistance = 0;
71 | }
72 | ImGui::SameLine();
73 | if (ImGui::Button("Save##sway")) {
74 | saveGUIDataCache();
75 | }
76 | ImGui::NewLine();
77 | }
78 | if (ImGui::IsItemHovered()) {
79 | ImGui::BeginTooltip();
80 | ImGui::Text("SwayString 偏移调整。加载角色时生效,非实时生效。");
81 | ImGui::EndTooltip();
82 | }
83 |
84 | bool baseApply = false;
85 | bool resetAll = false;
86 | if (ImGui::CollapsingHeader("Base Offset", ImGuiTreeNodeFlags_DefaultOpen)) {
87 | INPUT_AND_SLIDER_FLOAT("Height##base", &baseParam.height, -1.5, 1.5);
88 | INPUT_AND_SLIDER_FLOAT("Bust##base", &baseParam.bust, -1.5, 1.5);
89 | INPUT_AND_SLIDER_FLOAT("Head##base", &baseParam.head, -1.5, 1.5);
90 | INPUT_AND_SLIDER_FLOAT("Arm##base", &baseParam.arm, -1.5, 1.5);
91 | INPUT_AND_SLIDER_FLOAT("Hand##base", &baseParam.hand, -1.5, 1.5);
92 | if (ImGui::Button("Apply##base")) {
93 | baseApply = true;
94 | }
95 | ImGui::SameLine();
96 | if (ImGui::Button("Reset Base##base")) {
97 | baseParam.Reset();
98 | baseApply = true;
99 | }
100 | ImGui::SameLine();
101 | if (ImGui::Button("Reset All##base")) {
102 | baseParam.Reset();
103 | resetAll = true;
104 | baseApply = true;
105 | }
106 | ImGui::SameLine();
107 | if (ImGui::Checkbox("Real-time Update##base", &baseParam.gui_real_time_apply)) {
108 | if (baseParam.gui_real_time_apply) {
109 | baseApply = true;
110 | }
111 | }
112 | }
113 |
114 | for (auto& i : charaParam) {
115 | if (i.second.checkObjAlive()) {
116 | if (ImGui::CollapsingHeader(i.first.c_str())) {
117 | FOR_INPUT_AND_SLIDER_FLOAT("Height", &i.second.height, 0.0, 2.0, i.first);
118 | FOR_INPUT_AND_SLIDER_FLOAT("Bust", &i.second.bust, 0.0, 2.0, i.first);
119 | FOR_INPUT_AND_SLIDER_FLOAT("Head", &i.second.head, 0.0, 2.0, i.first);
120 | FOR_INPUT_AND_SLIDER_FLOAT("Arm", &i.second.arm, 0.0, 2.0, i.first);
121 | FOR_INPUT_AND_SLIDER_FLOAT("Hand", &i.second.hand, 0.0, 2.0, i.first);
122 | if (ImGui::Button(("Apply##" + i.first).c_str()) || baseApply) {
123 | i.second.ApplyOnMainThread();
124 | }
125 | ImGui::SameLine();
126 | if (ImGui::Button(("Reset##" + i.first).c_str()) || resetAll) {
127 | i.second.Reset();
128 | i.second.ApplyOnMainThread();
129 | }
130 | ImGui::SameLine();
131 | if (ImGui::Checkbox(("Real-time Update##" + i.first).c_str(), &i.second.gui_real_time_apply)) {
132 | if (i.second.gui_real_time_apply) {
133 | i.second.ApplyOnMainThread();
134 | }
135 | }
136 | }
137 | else {
138 | if (baseApply) {
139 | if (resetAll) {
140 | i.second.Reset();
141 | }
142 | i.second.ApplyOnMainThread();
143 | }
144 | }
145 | }
146 | }
147 | }
148 | ImGui::End();
149 | }
150 |
151 | void mainLoop() {
152 | if (ImGui::Begin("SC Plugin Config")) {
153 | if (ImGui::Button("Reload Config And Translate Data")) {
154 | g_reload_all_data();
155 | }
156 | ImGui::Checkbox("Waiting Extract Text", &SCGUIData::needExtractText);
157 |
158 | ImGui::Checkbox("Live Unlock All Dress", &g_unlock_all_dress);
159 | ImGui::SameLine();
160 | HELP_TOOLTIP("(?)", "实现服(接)装(头)自(霸)由(王)!\n此模式下可以在 Live 中自由选择任何人的服装。\n此模式下,修改服装后可以不点击确定,直接返回也能生效\n若点击了确定,修改后的服装会被重置为默认服装。\n(此模式上传的编组数据为默认初始服装,无危险性)")
161 |
162 | if (g_unlock_all_dress) {
163 | ImGui::Checkbox("Live Unlock All Headwear (Warning)", &g_unlock_all_headwear);
164 | ImGui::SameLine();
165 | HELP_TOOLTIP("(?)", "解锁 Live 头饰\n警告:\n若未解锁 头发/眼镜/耳环/面妆 等项目的第一个,换装对应项目时,可能会上传异常数据。")
166 | }
167 |
168 | ImGui::Checkbox("Live Allow Same Idol (Dangerous)", &g_allow_same_idol);
169 | ImGui::SameLine();
170 | HELP_TOOLTIP("(?)", "影分身术!\n允许在 Live 中选择同一人。\n(此模式的编组数据会上传,请小心你的号)")
171 |
172 | ImGui::Checkbox("Live Allow Use Try On Costume (Dangerous)", &g_allow_use_tryon_costume);
173 | ImGui::SameLine();
174 | HELP_TOOLTIP("(?)", "偶像的事,怎么能叫抢呢(\n切换到试穿模式换装后,切回普通模式,仍旧锁定试穿模式的衣服\n(此模式的编组数据会上传,请小心你的号)")
175 |
176 | ImGui::Checkbox("Enable Character Parameter Editor", &g_enable_chara_param_edit);
177 | ImGui::SameLine();
178 | HELP_TOOLTIP("(?)", "启用角色身体参数编辑器")
179 |
180 | ImGui::Checkbox("Unlock PIdol And SChara Events", &g_unlock_PIdol_and_SChara_events);
181 | ImGui::SameLine();
182 | HELP_TOOLTIP("(?)", "解锁 角色 - 一览 中的P卡和S卡事件\nUnlock Idol Event (アイドルイベント) and Support Event (サポートイベント)")
183 |
184 | if (ImGui::CollapsingHeader("Resolution Settings", ImGuiTreeNodeFlags_DefaultOpen)) {
185 | ImGui::Text("Window Resolution Settings");
186 |
187 | if (ImGui::Button("720P")) {
188 | SCGUIData::screenW = 1280;
189 | SCGUIData::screenH = 720;
190 | }
191 | ImGui::SameLine();
192 | if (ImGui::Button("1080P")) {
193 | SCGUIData::screenW = 1920;
194 | SCGUIData::screenH = 1080;
195 | }
196 | ImGui::SameLine();
197 | if (ImGui::Button("1440P")) {
198 | SCGUIData::screenW = 2560;
199 | SCGUIData::screenH = 1440;
200 | }
201 | ImGui::SameLine();
202 | if (ImGui::Button("1620P")) {
203 | SCGUIData::screenW = 2880;
204 | SCGUIData::screenH = 1620;
205 | }
206 | ImGui::SameLine();
207 | if (ImGui::Button("2160P")) {
208 | SCGUIData::screenW = 3840;
209 | SCGUIData::screenH = 2160;
210 | }
211 |
212 | ImGui::InputInt("Width", &SCGUIData::screenW);
213 | ImGui::InputInt("Height", &SCGUIData::screenH);
214 | ImGui::Checkbox("Full Screen", &SCGUIData::screenFull);
215 | if (ImGui::Button("Update Resolution")) {
216 | if (SetResolution_orig) {
217 | reinterpret_cast(SetResolution_orig)(SCGUIData::screenW, SCGUIData::screenH, SCGUIData::screenFull);
218 | }
219 |
220 | }
221 |
222 | ImGui::Separator();
223 |
224 | INPUT_AND_SLIDER_FLOAT("3D Resolution Scale", &g_3d_resolution_scale, 0.1f, 5.0f);
225 | if (g_3d_resolution_scale == 1.0f) {
226 | SCCamera::currRenderResolution.x = SCGUIData::screenW;
227 | SCCamera::currRenderResolution.y = SCGUIData::screenH;
228 | }
229 | ImGui::Text("Current 3D Resolution: %d, %d", SCCamera::currRenderResolution.x, SCCamera::currRenderResolution.y);
230 | }
231 |
232 | if (ImGui::CollapsingHeader("Camera Info", ImGuiTreeNodeFlags_DefaultOpen)) {
233 | ImGui::InputFloat("Game Camera FOV", &SCGUIData::sysCamFov);
234 | ImGui::InputFloat3("Game Camera Pos (x, y, z)", &SCGUIData::sysCamPos.x);
235 | ImGui::InputFloat3("Game Camera LookAt (x, y, z)", &SCGUIData::sysCamLookAt.x);
236 | ImGui::InputFloat4("Game Camera Rotation (w, x, y, z)", &SCGUIData::sysCamRot.w);
237 |
238 | if(ImGui::CollapsingHeader("Free Camera", ImGuiTreeNodeFlags_DefaultOpen)) {
239 | ImGui::Checkbox("Enable Free Camera", &g_enable_free_camera);
240 | INPUT_AND_SLIDER_FLOAT("Move Speed", &BaseCamera::moveStep, 0.0f, 0.5f);
241 | INPUT_AND_SLIDER_FLOAT("Mouse Speed", &g_free_camera_mouse_speed, 0.0f, 100.0f);
242 | INPUT_AND_SLIDER_FLOAT("Camera FOV", &SCCamera::baseCamera.fov, 0.0f, 360.0f);
243 | ImGui::InputFloat3("Camera Pos (x, y, z)", &SCCamera::baseCamera.pos.x);
244 | ImGui::InputFloat3("Camera LookAt (x, y, z)", &SCCamera::baseCamera.lookAt.x);
245 | }
246 | }
247 |
248 | }
249 | ImGui::End();
250 | if (g_enable_chara_param_edit) charaParamEditLoop();
251 | }
252 | }
253 |
--------------------------------------------------------------------------------
/src/scgui/scGUILoop.hpp:
--------------------------------------------------------------------------------
1 |
2 |
3 | namespace SCGUILoop {
4 | void mainLoop();
5 | }
--------------------------------------------------------------------------------
/src/scgui/scGUIMain.cpp:
--------------------------------------------------------------------------------
1 | #include "imgui/imgui.h"
2 | #include "imgui/imgui_impl_win32.h"
3 | #include "imgui/imgui_impl_dx11.h"
4 | #include
5 | #include
6 | #include "stdinclude.hpp"
7 | #include "scgui/scGUILoop.hpp"
8 |
9 | #pragma comment(lib, "d3d11.lib")
10 | #pragma comment(lib, "d3dcompiler.lib")
11 |
12 | // Data
13 | static ID3D11Device* g_pd3dDevice = NULL;
14 | static ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
15 | static IDXGISwapChain* g_pSwapChain = NULL;
16 | static ID3D11RenderTargetView* g_mainRenderTargetView = NULL;
17 |
18 | // Forward declarations of helper functions
19 | bool CreateDeviceD3D(HWND hWnd);
20 | void CleanupDeviceD3D();
21 | void CreateRenderTarget();
22 | void CleanupRenderTarget();
23 | LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
24 | bool guiDone = true;
25 |
26 | bool attachToGame = false;
27 |
28 | HWND hwnd;
29 | RECT cacheRect{ 100, 100, 730, 910 };
30 |
31 | void SetGuiDone(bool isDone) {
32 | guiDone = isDone;
33 | }
34 |
35 | void SetWindowTop()
36 | {
37 | ::SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
38 | }
39 |
40 | void CancelWindowTop()
41 | {
42 | ::SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
43 | }
44 |
45 | bool lastTopStat = false;
46 | bool nowTopStat = false;
47 | void changeTopState() {
48 | if (lastTopStat == nowTopStat) return;
49 | lastTopStat = nowTopStat;
50 | if (nowTopStat) {
51 | SetWindowTop();
52 | }
53 | else {
54 | CancelWindowTop();
55 | }
56 |
57 | }
58 |
59 | bool getUmaGuiDone() {
60 | return guiDone;
61 | }
62 |
63 | // Main code
64 | void guimain()
65 | {
66 | guiDone = false;
67 | WNDCLASSW wc;
68 | RECT WindowRectangle;
69 | HWND GameHwnd;
70 | int WindowWide;
71 | int WindowHeight;
72 |
73 | // GameHwnd = GetConsoleWindow();
74 | // if (GameHwnd) attachToGame = true;
75 |
76 | // Create application window
77 | //ImGui_ImplWin32_EnableDpiAwareness();
78 | if (!attachToGame) {
79 | WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, L"iM@S SCSP Localify", NULL };
80 | ::RegisterClassExW(&wc);
81 | hwnd = ::CreateWindowW(wc.lpszClassName, L"iM@S SCSP GUI", WS_OVERLAPPEDWINDOW, cacheRect.left, cacheRect.top,
82 | cacheRect.right - cacheRect.left, cacheRect.bottom - cacheRect.top, NULL, NULL, wc.hInstance, NULL);
83 | if (nowTopStat) SetWindowTop();
84 | }
85 | else {
86 | // 注册窗体类
87 | // 附加到指定窗体上
88 | wc.cbClsExtra = NULL;
89 | wc.cbWndExtra = NULL;
90 | wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0, 0, 0));
91 | wc.hCursor = LoadCursor(0, IDC_ARROW);
92 | wc.hIcon = LoadIcon(0, IDI_APPLICATION);
93 | wc.hInstance = GetModuleHandle(NULL);
94 | wc.lpfnWndProc = (WNDPROC)WndProc;
95 | wc.lpszClassName = L" ";
96 | wc.lpszMenuName = L" ";
97 | wc.style = CS_VREDRAW | CS_HREDRAW;
98 |
99 | RegisterClassW(&wc);
100 |
101 | // 得到窗口句柄
102 | WindowRectangle;
103 | GameHwnd = FindWindowW(L"UnityWndClass", L"imasscprism");
104 | GetWindowRect(GameHwnd, &WindowRectangle);
105 | WindowWide = WindowRectangle.right - WindowRectangle.left;
106 | WindowHeight = WindowRectangle.bottom - WindowRectangle.top;
107 |
108 | // 创建窗体
109 | // HWND hwnd = ::CreateWindowW(WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TOOLWINDOW, L" ", L" ", WS_POPUP, 1, 1, WindowWide, WindowHeight, 0, 0, wc.hInstance, 0);
110 | hwnd = ::CreateWindowW(wc.lpszClassName, L"", WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_LAYERED | WS_POPUP, 1, 1, WindowWide, WindowHeight, NULL, NULL, wc.hInstance, NULL);
111 | LONG lWinStyleEx = GetWindowLong(hwnd, GWL_EXSTYLE);
112 | lWinStyleEx = lWinStyleEx | WS_EX_LAYERED;
113 |
114 | SetWindowLong(hwnd, GWL_EXSTYLE, lWinStyleEx);
115 | SetLayeredWindowAttributes(hwnd, 0, 0, LWA_ALPHA);
116 | // 去掉标题栏及边框
117 | LONG_PTR Style = GetWindowLongPtr(hwnd, GWL_STYLE);
118 | Style = Style & ~WS_CAPTION & ~WS_SYSMENU & ~WS_SIZEBOX;
119 | SetWindowLongPtr(hwnd, GWL_STYLE, Style);
120 | // 至顶层窗口 最大化
121 | SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, WindowWide, WindowHeight, SWP_SHOWWINDOW);
122 | SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
123 | // 设置窗体可穿透鼠标
124 | // SetWindowLong(hwnd, GWL_EXSTYLE, WS_EX_TRANSPARENT | WS_EX_LAYERED);
125 |
126 | }
127 |
128 | // Initialize Direct3D
129 | if (!CreateDeviceD3D(hwnd))
130 | {
131 | printf("init D3D failed\n");
132 | CleanupDeviceD3D();
133 | if (attachToGame) ::UnregisterClassW(wc.lpszClassName, wc.hInstance);
134 | return;
135 | }
136 |
137 | if (attachToGame) {
138 | // Show the window
139 | SetLayeredWindowAttributes(hwnd, 0, 0, LWA_ALPHA);
140 | SetLayeredWindowAttributes(hwnd, 0, 0, LWA_COLORKEY);
141 | }
142 |
143 | ::ShowWindow(hwnd, SW_SHOW);
144 | ::UpdateWindow(hwnd);
145 |
146 | // Setup Dear ImGui context
147 | IMGUI_CHECKVERSION();
148 | ImGui::CreateContext();
149 | ImGuiIO& io = ImGui::GetIO(); (void)io;
150 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
151 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
152 |
153 | // Setup Dear ImGui style
154 | ImGui::StyleColorsDark();
155 | //ImGui::StyleColorsLight();
156 |
157 | // Setup Platform/Renderer backends
158 | ImGui_ImplWin32_Init(hwnd);
159 | ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
160 |
161 | ImFontGlyphRangesBuilder builder;
162 |
163 | ImFontConfig config;
164 | builder.AddRanges(io.Fonts->GetGlyphRangesJapanese());
165 | builder.AddRanges(io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
166 | builder.AddRanges(io.Fonts->GetGlyphRangesChineseFull());
167 | builder.AddRanges(io.Fonts->GetGlyphRangesKorean());
168 | builder.AddRanges(io.Fonts->GetGlyphRangesDefault());
169 | builder.AddText("○◎△×☆");
170 | ImVector glyphRanges;
171 | builder.BuildRanges(&glyphRanges);
172 | config.GlyphRanges = glyphRanges.Data;
173 |
174 | if (std::filesystem::exists("c:\\Windows\\Fonts\\msyh.ttc")) {
175 | io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\msyh.ttc", 18.0f, &config);
176 | }
177 | else {
178 | io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f, &config);
179 | }
180 |
181 | ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 0.00f);
182 |
183 | // Main loop
184 | while (!guiDone)
185 | {
186 | // Poll and handle messages (inputs, window resize, etc.)
187 | // See the WndProc() function below for our to dispatch events to the Win32 backend.
188 | MSG msg;
189 | while (::PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
190 | {
191 | ::TranslateMessage(&msg);
192 | ::DispatchMessage(&msg);
193 | if (msg.message == WM_QUIT)
194 | guiDone = true;
195 | }
196 | if (guiDone)
197 | break;
198 |
199 |
200 | if (attachToGame) {
201 | // 每次都将窗体置顶并跟随游戏窗体移动
202 | GetWindowRect(GameHwnd, &WindowRectangle);
203 | WindowWide = (WindowRectangle.right) - (WindowRectangle.left);
204 | WindowHeight = (WindowRectangle.bottom) - (WindowRectangle.top);
205 | DWORD dwStyle = GetWindowLong(GameHwnd, GWL_STYLE);
206 | if (dwStyle & WS_BORDER)
207 | {
208 | WindowRectangle.top += 23;
209 | WindowHeight -= 23;
210 | }
211 |
212 | // 跟随窗口移动
213 | MoveWindow(hwnd, WindowRectangle.left + 9, WindowRectangle.top + 9, WindowWide - 18, WindowHeight - 18, true);
214 |
215 | }
216 |
217 | // Start the Dear ImGui frame
218 | ImGui_ImplDX11_NewFrame();
219 | ImGui_ImplWin32_NewFrame();
220 |
221 | ImGui::NewFrame();
222 | SCGUILoop::mainLoop();
223 |
224 | ImGui::Render();
225 | const float clear_color_with_alpha[4] = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w };
226 | g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, NULL);
227 | g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha);
228 | ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
229 |
230 | g_pSwapChain->Present(1, 0); // Present with vsync
231 | // g_pSwapChain->Present(0, 0); // Present without vsync
232 | }
233 |
234 | // Cleanup
235 | ImGui_ImplDX11_Shutdown();
236 | ImGui_ImplWin32_Shutdown();
237 | ImGui::DestroyContext();
238 |
239 | CleanupDeviceD3D();
240 | ::DestroyWindow(hwnd);
241 | ::UnregisterClassW(wc.lpszClassName, wc.hInstance);
242 |
243 | }
244 |
245 | // Helper functions
246 |
247 | bool CreateDeviceD3D(HWND hWnd)
248 | {
249 | // Setup swap chain
250 | DXGI_SWAP_CHAIN_DESC sd;
251 | ZeroMemory(&sd, sizeof(sd));
252 | sd.BufferCount = 2;
253 | sd.BufferDesc.Width = 0;
254 | sd.BufferDesc.Height = 0;
255 | sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
256 | sd.BufferDesc.RefreshRate.Numerator = 60;
257 | sd.BufferDesc.RefreshRate.Denominator = 1;
258 | sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
259 | sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
260 | sd.OutputWindow = hWnd;
261 | sd.SampleDesc.Count = 1;
262 | sd.SampleDesc.Quality = 0;
263 | sd.Windowed = TRUE;
264 | sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
265 |
266 | UINT createDeviceFlags = 0;
267 | //createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
268 | D3D_FEATURE_LEVEL featureLevel;
269 | const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, };
270 | HRESULT res = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext);
271 | if (res == DXGI_ERROR_UNSUPPORTED) // Try high-performance WARP software driver if hardware is not available.
272 | res = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_WARP, NULL, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext);
273 | if (res != S_OK)
274 | return false;
275 |
276 | CreateRenderTarget();
277 | return true;
278 | }
279 |
280 | void CleanupDeviceD3D()
281 | {
282 | CleanupRenderTarget();
283 | if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = NULL; }
284 | if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = NULL; }
285 | if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
286 | }
287 |
288 | void CreateRenderTarget()
289 | {
290 | ID3D11Texture2D* pBackBuffer;
291 | g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
292 | g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_mainRenderTargetView);
293 | pBackBuffer->Release();
294 | }
295 |
296 | void CleanupRenderTarget()
297 | {
298 | if (g_mainRenderTargetView) { g_mainRenderTargetView->Release(); g_mainRenderTargetView = NULL; }
299 | }
300 |
301 | // Forward declare message handler from imgui_impl_win32.cpp
302 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
303 |
304 | // Win32 message handler
305 | // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
306 | // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
307 | // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
308 | // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
309 | LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
310 | {
311 | if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
312 | return true;
313 |
314 | switch (msg)
315 | {
316 | case WM_SIZE:
317 | if (g_pd3dDevice != NULL && wParam != SIZE_MINIMIZED)
318 | {
319 | CleanupRenderTarget();
320 | g_pSwapChain->ResizeBuffers(0, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam), DXGI_FORMAT_UNKNOWN, 0);
321 | CreateRenderTarget();
322 | }
323 | return 0;
324 | case WM_SIZING: {
325 | RECT* rect = reinterpret_cast(lParam);
326 | cacheRect.left = rect->left;
327 | cacheRect.right = rect->right;
328 | cacheRect.top = rect->top;
329 | cacheRect.bottom = rect->bottom;
330 | }; break;
331 | case WM_SYSCOMMAND:
332 | if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu
333 | return 0;
334 | break;
335 | case WM_DESTROY:
336 | ::PostQuitMessage(0);
337 | return 0;
338 | }
339 | return ::DefWindowProcW(hWnd, msg, wParam, lParam);
340 | }
--------------------------------------------------------------------------------
/src/scgui/scGUIMain.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "stdinclude.hpp"
3 |
4 | void SetGuiDone(bool isDone);
5 | bool getUmaGuiDone();
6 | void guimain();
7 |
--------------------------------------------------------------------------------
/src/stdinclude.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define NOMINMAX
4 |
5 | #include
6 | #include
7 |
8 | #include
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include