├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── conanfile.txt ├── deps ├── minhook.lua └── rapidjson.lua ├── generate.bat ├── premake5.lua ├── readme_EN.md ├── resources └── scsp-config.json ├── src ├── camera │ ├── baseCamera.cpp │ ├── baseCamera.hpp │ ├── camera.cpp │ └── camera.hpp ├── console.cpp ├── dllproxy │ ├── proxy.cpp │ ├── version.asm │ └── version.def ├── hook.cpp ├── il2cpp │ ├── il2cpp_symbols.cpp │ └── il2cpp_symbols.hpp ├── imgui │ ├── LICENSE.txt │ ├── imconfig.h │ ├── imgui.cpp │ ├── imgui.h │ ├── imgui_demo.cpp │ ├── imgui_draw.cpp │ ├── imgui_impl_dx11.cpp │ ├── imgui_impl_dx11.h │ ├── imgui_impl_win32.cpp │ ├── imgui_impl_win32.h │ ├── imgui_internal.h │ ├── imgui_tables.cpp │ ├── imgui_widgets.cpp │ ├── imstb_rectpack.h │ ├── imstb_textedit.h │ └── imstb_truetype.h ├── local │ ├── local.cpp │ └── local.hpp ├── main.cpp ├── mhotkey.cpp ├── mhotkey.hpp ├── scgui │ ├── scGUIData.cpp │ ├── scGUIData.hpp │ ├── scGUILoop.cpp │ ├── scGUILoop.hpp │ ├── scGUIMain.cpp │ └── scGUIMain.hpp ├── stdinclude.hpp └── steam │ └── steam.cpp └── utils └── bin └── premake5.exe /.gitattributes: -------------------------------------------------------------------------------- 1 | resources/schinese/localized_data/umamusumelocalify filter=lfs diff=lfs merge=lfs -text 2 | *.dll filter=lfs diff=lfs merge=lfs -text 3 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | push: 4 | paths: 5 | - '**.lua' 6 | - '**.cpp' 7 | - '**.c' 8 | - '**.hpp' 9 | - '**.h' 10 | - '.gitmodules' 11 | - '.gitignore' 12 | - '.gitattributes' 13 | - 'conanfile.txt' 14 | - 'deps/**' 15 | - 'src/**' 16 | - 'utils/**' 17 | - 'ci.yml' 18 | pull_request: 19 | paths: 20 | - '**.lua' 21 | - '**.cpp' 22 | - '**.c' 23 | - '**.hpp' 24 | - '**.h' 25 | - '.gitmodules' 26 | - '.gitignore' 27 | - '.gitattributes' 28 | - 'conanfile.txt' 29 | - 'deps/**' 30 | - 'src/**' 31 | - 'utils/**' 32 | - 'ci.yml' 33 | jobs: 34 | build: 35 | runs-on: windows-2019 36 | 37 | steps: 38 | - name: checkout 39 | uses: actions/checkout@v2 40 | with: 41 | submodules: true 42 | - name: install-dependencies 43 | run: | 44 | pip3 install --upgrade conan==1.59.0 requests 45 | conan profile new default --detect 46 | conan config init 47 | - name: configure-msbuild-env 48 | uses: microsoft/setup-msbuild@v1.0.2 49 | - name: build 50 | run: | 51 | ./generate.bat 52 | cd build 53 | msbuild ImasSCSP-localify.sln -m -p:Configuration=Release 54 | - name: prepare-package 55 | run: | 56 | mkdir package 57 | cp build/bin/x64/Release/version.dll package/version.dll 58 | cp resources/scsp-config.json package/scsp-config.json 59 | cp -r resources/schinese/scsp_localify package/scsp_localify 60 | - uses: actions/upload-artifact@v4 61 | with: 62 | name: scsp-localify 63 | path: package 64 | - uses: actions/upload-artifact@v4 65 | with: 66 | name: scsp-localify-dll 67 | path: package/version.dll -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Windows 2 | 3 | # Windows image file caches 4 | Thumbs.db 5 | ehthumbs.db 6 | 7 | # Folder config file 8 | Desktop.ini 9 | 10 | # Recycle Bin used on file shares 11 | $RECYCLE.BIN/ 12 | 13 | # Windows Installer files 14 | *.cab 15 | *.msi 16 | *.msm 17 | *.msp 18 | 19 | # Shortcuts 20 | *.lnk 21 | 22 | ### OSX 23 | 24 | .DS_Store 25 | .AppleDouble 26 | .LSOverride 27 | 28 | # Icon must end with two \r 29 | Icon 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | 45 | ### Visual Studio 46 | 47 | # User-specific files 48 | *.suo 49 | *.user 50 | *.userosscache 51 | *.sln.docstates 52 | 53 | # User-specific files (MonoDevelop/Xamarin Studio) 54 | *.userprefs 55 | 56 | # Build results 57 | build 58 | 59 | # Visual Studio 2015 cache/options directory 60 | .vs/ 61 | 62 | # MSTest test Results 63 | [Tt]est[Rr]esult*/ 64 | [Bb]uild[Ll]og.* 65 | 66 | *_i.c 67 | *_p.c 68 | *_i.h 69 | *.ilk 70 | *.meta 71 | *.obj 72 | *.pch 73 | *.pdb 74 | *.pgc 75 | *.pgd 76 | *.rsp 77 | *.sbr 78 | *.tlb 79 | *.tli 80 | *.tlh 81 | *.tmp 82 | *.tmp_proj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | 100 | # Visual Studio profiler 101 | *.psess 102 | *.vsp 103 | *.vspx 104 | *.sap 105 | 106 | # TFS 2012 Local Workspace 107 | $tf/ 108 | 109 | # Guidance Automation Toolkit 110 | *.gpState 111 | 112 | # Visual Studio cache files 113 | # files ending in .cache can be ignored 114 | *.[Cc]ache 115 | # but keep track of directories ending in .cache 116 | !*.[Cc]ache/ 117 | 118 | # Others 119 | ~$* 120 | *~ 121 | *.dbmdl 122 | *.dbproj.schemaview 123 | *.pfx 124 | *.publishsettings 125 | 126 | # Backup & report files from converting an old project file 127 | # to a newer Visual Studio version. Backup files are not needed, 128 | # because we have git ;-) 129 | _UpgradeReport_Files/ 130 | Backup*/ 131 | UpgradeLog*.XML 132 | UpgradeLog*.htm 133 | 134 | # SQL Server files 135 | *.mdf 136 | *.ldf 137 | 138 | ### IDA 139 | *.id0 140 | *.id1 141 | *.id2 142 | *.nam 143 | *.til 144 | 145 | ### Custom user files 146 | # User scripts 147 | user*.bat 148 | 149 | # Premake binary 150 | #premake5.exe 151 | 152 | # text_dumper tmp files 153 | resources/text_dumper/obj 154 | resources/text_dumper/bin 155 | 156 | .cache/ 157 | .vscode/ 158 | /backend 159 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "deps/minhook"] 2 | path = deps/minhook 3 | url = https://github.com/TsudaKageyu/minhook.git 4 | [submodule "deps/rapidjson"] 5 | path = deps/rapidjson 6 | url = https://github.com/Tencent/rapidjson.git 7 | [submodule "resources/schinese"] 8 | path = resources/schinese 9 | url = https://github.com/chinosk6/SCSPTranslationData.git 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . -------------------------------------------------------------------------------- /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 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "il2cpp/il2cpp_symbols.hpp" 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include "local/local.hpp" 45 | #include "camera/camera.hpp" 46 | 47 | 48 | class CharaParam_t { 49 | public: 50 | CharaParam_t(float height, float bust, float head, float arm, float hand) : 51 | height(height), bust(bust), head(head), arm(arm), hand(hand) { 52 | objPtr = NULL; 53 | updateInitParam(); 54 | } 55 | 56 | CharaParam_t(float height, float bust, float head, float arm, float hand, void* objPtr) : 57 | height(height), bust(bust), head(head), arm(arm), hand(hand), objPtr(objPtr) { 58 | updateInitParam(); 59 | } 60 | 61 | void UpdateParam(float* height, float* bust, float* head, float* arm, float* hand) const { 62 | *height = this->height; 63 | *bust = this->bust; 64 | *head = this->head; 65 | *arm = this->arm; 66 | *hand = this->hand; 67 | } 68 | 69 | void SetObjPtr(void* ptr) { 70 | objPtr = ptr; 71 | } 72 | 73 | bool checkObjAlive() { 74 | if (!objPtr) return false; 75 | static auto Object_IsNativeObjectAlive = reinterpret_cast( 76 | il2cpp_symbols::get_method_pointer("UnityEngine.CoreModule.dll", "UnityEngine", 77 | "Object", "IsNativeObjectAlive", 1) 78 | ); 79 | const auto ret = Object_IsNativeObjectAlive(objPtr); 80 | if (!ret) objPtr = NULL; 81 | return ret; 82 | } 83 | 84 | void* getObjPtr() { 85 | checkObjAlive(); 86 | return objPtr; 87 | } 88 | 89 | void Reset() { 90 | height = init_height; 91 | bust = init_bust; 92 | head = init_head; 93 | arm = init_arm; 94 | hand = init_hand; 95 | } 96 | 97 | void Apply(); 98 | void ApplyOnMainThread(); 99 | 100 | float height; 101 | float bust; 102 | float head; 103 | float arm; 104 | float hand; 105 | bool gui_real_time_apply = false; 106 | private: 107 | void updateInitParam() { 108 | init_height = height; 109 | init_bust = bust; 110 | init_head = head; 111 | init_arm = arm; 112 | init_hand = hand; 113 | } 114 | 115 | void* objPtr; 116 | float init_height; 117 | float init_bust; 118 | float init_head; 119 | float init_arm; 120 | float init_hand; 121 | }; 122 | 123 | 124 | class CharaSwayStringParam_t { 125 | public: 126 | CharaSwayStringParam_t(float rate, float P_bendStrength, float P_baseGravity, 127 | float P_inertiaMoment, float P_airResistance, float P_deformResistance): 128 | rate(rate), P_bendStrength(P_bendStrength), P_baseGravity(P_baseGravity), 129 | P_inertiaMoment(P_inertiaMoment), P_airResistance(P_airResistance), P_deformResistance(P_deformResistance){ 130 | 131 | } 132 | 133 | CharaSwayStringParam_t() : 134 | rate(0), P_bendStrength(0), P_baseGravity(0), 135 | P_inertiaMoment(0), P_airResistance(0), P_deformResistance(0) { 136 | 137 | } 138 | 139 | bool isEdited() const { 140 | return (rate != 0 || P_bendStrength != 0 || P_baseGravity != 0 || 141 | P_inertiaMoment != 0 || P_airResistance != 0 || P_deformResistance != 0); 142 | } 143 | 144 | float rate; 145 | float P_bendStrength; 146 | float P_baseGravity; 147 | float P_inertiaMoment; 148 | float P_airResistance; 149 | float P_deformResistance; 150 | 151 | }; 152 | 153 | extern std::map swayTypes; 154 | extern std::map charaSwayStringOffset; 155 | 156 | extern std::function g_reload_all_data; 157 | extern bool g_enable_plugin; 158 | extern int g_max_fps; 159 | extern int g_vsync_count; 160 | extern bool g_enable_console; 161 | extern bool g_auto_dump_all_json; 162 | extern bool g_dump_untrans_lyrics; 163 | extern bool g_dump_untrans_unlocal; 164 | extern std::string g_custom_font_path; 165 | extern std::filesystem::path g_localify_base; 166 | extern std::list g_extra_assetbundle_paths; 167 | extern char hotKey; 168 | extern bool g_enable_free_camera; 169 | extern bool g_block_out_of_focus; 170 | extern float g_free_camera_mouse_speed; 171 | extern bool g_allow_use_tryon_costume; 172 | extern bool g_allow_same_idol; 173 | extern bool g_unlock_all_dress; 174 | extern bool g_unlock_all_headwear; 175 | extern bool g_enable_chara_param_edit; 176 | extern float g_font_size_offset; 177 | extern float g_3d_resolution_scale; 178 | extern bool g_unlock_PIdol_and_SChara_events; 179 | extern int g_start_resolution_w; 180 | extern int g_start_resolution_h; 181 | extern bool g_start_resolution_fullScreen; 182 | -------------------------------------------------------------------------------- /src/steam/steam.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace 4 | { 5 | const char* SteamAPI_GetSteamInstallPath() 6 | { 7 | static std::string install_path {}; 8 | if (!install_path.empty()) 9 | { 10 | return install_path.data(); 11 | } 12 | 13 | HKEY reg_key; 14 | if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\WOW6432Node\\Valve\\Steam", 0, KEY_QUERY_VALUE, 15 | ®_key) == 16 | ERROR_SUCCESS) 17 | { 18 | char path[MAX_PATH] = {0}; 19 | DWORD length = sizeof(path); 20 | RegQueryValueExA(reg_key, "InstallPath", nullptr, nullptr, reinterpret_cast(path), 21 | &length); 22 | RegCloseKey(reg_key); 23 | 24 | install_path = path; 25 | } 26 | 27 | return install_path.data(); 28 | } 29 | 30 | HMODULE steam_overlay_module, steam_client_module; 31 | 32 | void load_client() 33 | { 34 | const std::filesystem::path steam_path = SteamAPI_GetSteamInstallPath(); 35 | if (steam_path.empty()) 36 | return; 37 | 38 | LoadLibrary((steam_path / "tier0_s64.dll").string().data()); 39 | LoadLibrary((steam_path / "vstdlib_s64.dll").string().data()); 40 | steam_overlay_module = LoadLibrary((steam_path / "gameoverlayrenderer64.dll").string().data()); 41 | steam_client_module = LoadLibrary((steam_path / "steamclient64.dll").string().data()); 42 | 43 | if (!steam_client_module) 44 | return; 45 | 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /utils/bin/premake5.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chinosk6/scsp-localify/fc36b8a03d26dcff6aeaba0b2c77cf62f11a75c3/utils/bin/premake5.exe --------------------------------------------------------------------------------