Repository: nazonoSAUNA/patch.aul Branch: master Commit: 2441800fe810 Files: 167 Total size: 957.7 KB Directory structure: gitextract_6ahg5_lo/ ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── ------.md │ │ ├── aviutl--------------.md │ │ └── patch-aul------.md │ ├── pull_request_template.md │ └── workflows/ │ └── CI.yml ├── .gitignore ├── .gitmodules ├── COPYING ├── COPYING.LESSER ├── LICENSE ├── credits.md ├── patch/ │ ├── .editorconfig │ ├── add_dll_ref.hpp │ ├── clprogram.cl │ ├── config.hpp │ ├── config_rw.hpp │ ├── cryptostring.hpp │ ├── debug_log.hpp │ ├── gate.hpp │ ├── global.hpp │ ├── global_minimum.hpp │ ├── hash.hpp │ ├── init.cpp │ ├── init.hpp │ ├── json.h │ ├── macro.h │ ├── moduledata.hpp │ ├── multi_threading.hpp │ ├── mylua.hpp │ ├── mywindow.hpp │ ├── offset_address.hpp │ ├── overwrite_resource.cpp │ ├── overwrite_resource.hpp │ ├── packages.config │ ├── patch.cpp │ ├── patch.hpp │ ├── patch.rc │ ├── patch.vcxproj │ ├── patch.vcxproj.filters │ ├── patch_access_key.hpp │ ├── patch_add_extension.cpp │ ├── patch_add_extension.hpp │ ├── patch_alpha_bg.hpp │ ├── patch_aup_layer_setting.hpp │ ├── patch_aup_scene_setting.hpp │ ├── patch_aviutl_wndproc_override.cpp │ ├── patch_aviutl_wndproc_override.hpp │ ├── patch_base.hpp │ ├── patch_blend.cpp │ ├── patch_blend.hpp │ ├── patch_colorpalette_cache.hpp │ ├── patch_console.cpp │ ├── patch_console.hpp │ ├── patch_copybuffer_smem.hpp │ ├── patch_dialog_new_file.hpp │ ├── patch_exception_history.hpp │ ├── patch_exception_log.cpp │ ├── patch_exception_log.hpp │ ├── patch_exception_log_dialog.cpp │ ├── patch_exception_log_dialog.hpp │ ├── patch_exeditwindow_sizing.hpp │ ├── patch_exo_aviutlfilter.hpp │ ├── patch_exo_fold_gui.hpp │ ├── patch_exo_midpt_and_tra.hpp │ ├── patch_exo_sceneidx.hpp │ ├── patch_exo_specialcolorconv.hpp │ ├── patch_exo_trackminusval.cpp │ ├── patch_exo_trackminusval.hpp │ ├── patch_exo_trackparam.hpp │ ├── patch_failed_file_drop.hpp │ ├── patch_failed_longer_path.cpp │ ├── patch_failed_longer_path.hpp │ ├── patch_failed_sjis_msgbox.cpp │ ├── patch_failed_sjis_msgbox.hpp │ ├── patch_fast.hpp │ ├── patch_fast_border.cpp │ ├── patch_fast_border.hpp │ ├── patch_fast_cl.hpp │ ├── patch_fast_create_figure.cpp │ ├── patch_fast_create_figure.hpp │ ├── patch_fast_directionalblur.cpp │ ├── patch_fast_directionalblur.hpp │ ├── patch_fast_displacementmap.cpp │ ├── patch_fast_displacementmap.hpp │ ├── patch_fast_exeditwindow.cpp │ ├── patch_fast_exeditwindow.hpp │ ├── patch_fast_flash.cpp │ ├── patch_fast_flash.hpp │ ├── patch_fast_getputpixeldata.cpp │ ├── patch_fast_getputpixeldata.hpp │ ├── patch_fast_glow.cpp │ ├── patch_fast_glow.hpp │ ├── patch_fast_lensblur.cpp │ ├── patch_fast_lensblur.hpp │ ├── patch_fast_polortransform.cpp │ ├── patch_fast_polortransform.hpp │ ├── patch_fast_radiationalblur.cpp │ ├── patch_fast_radiationalblur.hpp │ ├── patch_fast_setting_dialog.cpp │ ├── patch_fast_setting_dialog.hpp │ ├── patch_fast_text.cpp │ ├── patch_fast_text.hpp │ ├── patch_fileinfo.hpp │ ├── patch_font_dialog.hpp │ ├── patch_helpful_msgbox.cpp │ ├── patch_helpful_msgbox.hpp │ ├── patch_ignore_media_param_reset.hpp │ ├── patch_lua.cpp │ ├── patch_lua.hpp │ ├── patch_lua_getvalueex.cpp │ ├── patch_lua_getvalueex.hpp │ ├── patch_lua_rand.cpp │ ├── patch_lua_rand.hpp │ ├── patch_lua_randex.cpp │ ├── patch_lua_randex.hpp │ ├── patch_obj_colorcorrection.cpp │ ├── patch_obj_colorcorrection.hpp │ ├── patch_obj_glow.hpp │ ├── patch_obj_lensblur.cpp │ ├── patch_obj_lensblur.hpp │ ├── patch_obj_noise.hpp │ ├── patch_obj_specialcolorconv.hpp │ ├── patch_playback_speed.hpp │ ├── patch_rclickmenu_delete.cpp │ ├── patch_rclickmenu_delete.hpp │ ├── patch_rclickmenu_split.cpp │ ├── patch_rclickmenu_split.hpp │ ├── patch_redo.cpp │ ├── patch_redo.hpp │ ├── patch_scroll_objdlg.hpp │ ├── patch_setting_dialog_excolorconfig.cpp │ ├── patch_setting_dialog_excolorconfig.hpp │ ├── patch_setting_dialog_move.hpp │ ├── patch_setting_dialog_wndproc_override.cpp │ ├── patch_setting_dialog_wndproc_override.hpp │ ├── patch_setting_gui.hpp │ ├── patch_setting_new_project.cpp │ ├── patch_setting_new_project.hpp │ ├── patch_splash.cpp │ ├── patch_splash.hpp │ ├── patch_susie_load.cpp │ ├── patch_susie_load.hpp │ ├── patch_sysinfo_write.hpp │ ├── patch_text_op_size.hpp │ ├── patch_theme_cc.hpp │ ├── patch_tra_aviutlfilter.hpp │ ├── patch_tra_change_drawfilter.cpp │ ├── patch_tra_change_drawfilter.hpp │ ├── patch_tra_specified_speed.hpp │ ├── patch_undo.cpp │ ├── patch_undo.hpp │ ├── resource.h │ ├── restorable_patch.hpp │ ├── stopwatch.hpp │ ├── timer.hpp │ ├── util.hpp │ ├── util_int.hpp │ ├── util_magic.hpp │ ├── util_others.cpp │ ├── util_others.hpp │ ├── util_pe.hpp │ ├── util_resource.hpp │ └── version.hpp ├── patch.aul.txt ├── patch.sln └── readme.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ ############################################################################### # Set default behavior to automatically normalize line endings. ############################################################################### * text=auto ############################################################################### # Set default behavior for command prompt diff. # # This is need for earlier builds of msysgit that does not have it on by # default for csharp files. # Note: This is only used by command line ############################################################################### #*.cs diff=csharp ############################################################################### # Set the merge driver for project and solution files # # Merging from the command prompt will add diff markers to the files if there # are conflicts (Merging from VS is not affected by the settings below, in VS # the diff markers are never inserted). Diff markers may cause the following # file extensions to fail to load in VS. An alternative would be to treat # these files as binary and thus will always conflict and require user # intervention with every merge. To do so, just uncomment the entries below ############################################################################### #*.sln merge=binary #*.csproj merge=binary #*.vbproj merge=binary #*.vcxproj merge=binary #*.vcproj merge=binary #*.dbproj merge=binary #*.fsproj merge=binary #*.lsproj merge=binary #*.wixproj merge=binary #*.modelproj merge=binary #*.sqlproj merge=binary #*.wwaproj merge=binary ############################################################################### # behavior for image files # # image files are treated as binary by default. ############################################################################### #*.jpg binary #*.png binary #*.gif binary ############################################################################### # diff behavior for common document formats # # Convert binary document formats to text before diffing them. This feature # is only available from the command line. Turn it on by uncommenting the # entries below. ############################################################################### #*.doc diff=astextplain #*.DOC diff=astextplain #*.docx diff=astextplain #*.DOCX diff=astextplain #*.dot diff=astextplain #*.DOT diff=astextplain #*.pdf diff=astextplain #*.PDF diff=astextplain #*.rtf diff=astextplain #*.RTF diff=astextplain ================================================ FILE: .github/ISSUE_TEMPLATE/------.md ================================================ --- name: 新機能の提案 about: 既存の挙動を変更する/新しい機能の追加 title: "+〇〇〇〇〇〇" labels: enhancement assignees: '' --- **背景** どのような理由でこの機能を提案するかの説明 **概要** 提案する機能はどのようなものなのかの説明 物によっては画像があると分かりやすい **没案** 他に検討した案 **その他** 他に書きたいことがあれば ================================================ FILE: .github/ISSUE_TEMPLATE/aviutl--------------.md ================================================ --- name: AviUtl/周辺プラグインのバグの報告 about: patch.aulに直してほしいバグ title: "*〇〇〇〇〇〇" labels: enhancement assignees: '' --- 【!】報告の前に必ずこの挙動がpatch.aulを導入していない状態で引き起こされる事象であることを確認してください patch.aulを導入した結果期待していない挙動になるのであれば、これはpatch.aulのバグとして扱い、別のテンプレートが用意されています **概要** 起こってしまうことの説明を簡単に 何かメッセージが表示されるのであれば、全文を正確にコピーする **再現手順** どのような操作をするとこのバグを観測できるのか (例) 1. XXXプラグイン version XXXを導入する 2. 新規プロジェクトにXXXオブジェクトを配置する 3. XXXオブジェクトの設定を開く **起こってほしかったこと** バグが起きなければどうなるのか **スクリーンショット** 必要だと思えば添付する **環境** AviUtl/拡張編集のバージョンは一応書いておく 導入しているフィルタ/入力/出力/色変換/その他のプラグインの情報をバージョンを添えて正確に書く もし例外が発生しているのであれば、詳細情報が書かれたファイルを添付することでも環境の説明になる **その他** もし他に何か書きたいことがあれば ================================================ FILE: .github/ISSUE_TEMPLATE/patch-aul------.md ================================================ --- name: patch.aulのバグの報告 about: patch.aulが起因であるバグはここから title: "/〇〇〇〇〇〇" labels: bug assignees: '' --- 【!】報告の前に必ずこの挙動がpatch.aulを導入したことにより引き起こされる事象であることを確認してください AviUtl/拡張編集/その他プラグインのバグの報告には別のテンプレートが用意されています **概要** 起こってしまうことの説明を簡単に 何かメッセージが表示されるのであれば、全文を正確にコピーする **再現手順** どのような操作をするとこのバグを観測できるのか (例) 1. XXXプラグイン version XXXを導入する 2. 新規プロジェクトにXXXオブジェクトを配置する 3. XXXオブジェクトの設定を開く **起こってほしかったこと** バグが起きなければどうなるのか **スクリーンショット** 必要だと思えば添付する **環境** AviUtl/拡張編集のバージョンは自明なので省略できる 導入しているフィルタ/入力/出力/色変換/その他のプラグインの情報をバージョンを添えて正確に書く もし例外が発生しているのであれば、詳細情報が書かれたファイルを添付することでも環境の説明になる **その他** もし他に何か書きたいことがあれば ================================================ FILE: .github/pull_request_template.md ================================================ **関係する Issue** 関係する Issue の番号を以下に書いてください。 - #0 を閉じる - #0 に関連 **変更点** この PR での変更点について教えてください。 - ○○の追加 - ○○の修正 **内容の精査** 以下の点について教えてください。 - [ ] コードにおかしな点がないことを確認しました。 - [ ] 実際にビルドして試しました。 **スクリーンショット(任意)** スクリーンショットを Ctrl+V で追加できます。 ================================================ FILE: .github/workflows/CI.yml ================================================ name: CI on: push: pull_request: jobs: build: runs-on: windows-2022 strategy: matrix: configuration: [Debug, Release] steps: - name: Checkout repository uses: actions/checkout@v2 with: submodules: recursive - name: Use Developer Command Prompt uses: ilammy/msvc-dev-cmd@v1 - name: Install CUDA Toolkit uses: Jimver/cuda-toolkit@v0.2.7 - name: Setup NuGet uses: nuget/setup-nuget@v1 - name: Restore NuGet package run : nuget restore patch.sln - name: Create Directories run : | mkdir pack mkdir test - name: Build patch.aul run : devenv patch.sln /Build "${{ matrix.configuration }}|x86" ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.rsuser *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Mono auto generated files mono_crash.* # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ [Ww][Ii][Nn]32/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ [Oo]ut/ [Ll]og/ [Ll]ogs/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUnit *.VisualState.xml TestResult.xml nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ # .NET Core project.lock.json project.fragment.lock.json artifacts/ # ASP.NET Scaffolding ScaffoldingReadMe.txt # StyleCop StyleCopReport.xml # Files built by Visual Studio *_i.c *_p.c *_h.h *.ilk *.meta *.obj *.iobj *.pch *.pdb *.ipdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *_wpftmp.csproj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # Visual Studio Trace Files *.e2e # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # AxoCover is a Code Coverage Tool .axoCover/* !.axoCover/settings.json # Coverlet is a free, cross platform Code Coverage Tool coverage*.json coverage*.xml coverage*.info # Visual Studio code coverage results *.coverage *.coveragexml # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # NuGet Symbol Packages *.snupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* # except build/, which is used as an MSBuild target. !**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/[Pp]ackages/repositories.config # NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt *.appx *.appxbundle *.appxupload # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !?*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings orleans.codegen.cs # Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm ServiceFabricBackup/ *.rptproj.bak # SQL Server files *.mdf *.ldf *.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings *.rptproj.rsuser *- [Bb]ackup.rdl *- [Bb]ackup ([0-9]).rdl *- [Bb]ackup ([0-9][0-9]).rdl # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat node_modules/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # CodeRush personal settings .cr/personal # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # Tabs Studio *.tss # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs # OpenCover UI analysis results OpenCover/ # Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log *.binlog # NVidia Nsight GPU debugger configuration file *.nvuser # MFractors (Xamarin productivity tool) working folder .mfractor/ # Local History for Visual Studio .localhistory/ # BeatPulse healthcheck temp database healthchecksdb # Backup folder for Package Reference Convert tool in Visual Studio 2017 MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ # Fody - auto-generated XML schema FodyWeavers.xsd # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # .vscode/ test/ pack/ Release_PDB/ ================================================ FILE: .gitmodules ================================================ [submodule "patch/aviutl_exedit_sdk"] path = patch/aviutl_exedit_sdk url = https://github.com/ePi5131/aviutl_exedit_sdk [submodule "patch/winwrap"] path = patch/winwrap url = https://github.com/ePi5131/winwrap ================================================ FILE: COPYING ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: COPYING.LESSER ================================================ GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. ================================================ FILE: LICENSE ================================================ © 2022-2023 ePi patch.aulはLGPLv3の元ライセンスする。ライセンスの詳細はCOPYING,COPYING.LESSERファイルを参照すること。 ================================================ FILE: credits.md ================================================ # 使用したライブラリについて ## Boost > Boost Software License - Version 1.0 - August 17th, 2003 > > Permission is hereby granted, free of charge, to any person or organization > obtaining a copy of the software and accompanying documentation covered by > this license (the "Software") to use, reproduce, display, distribute, > execute, and transmit the Software, and to prepare derivative works of the > Software, and to permit third-parties to whom the Software is furnished to > do so, all subject to the following: > > The copyright notices in the Software and this entire statement, including > the above license grant, this restriction and the following disclaimer, > must be included in all copies of the Software, in whole or in part, and > all derivative works of the Software, unless such copies or derivative > works are solely in the form of machine-executable object code generated by > a source language processor. > > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT > SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE > FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, > ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > DEALINGS IN THE SOFTWARE. ## aviutl_exedit_sdk ## winwrap これらは私が書いたライブラリであり、1条項BSDライセンスの下頒布している。文面は以下の通り。 > Copyright (c) 2022 > ePi All rights reserved. > > Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: > > Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. > THIS SOFTWARE IS PROVIDED BY ePi “AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ePi BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ## json.h このプログラムはUnlicenseで頒布されているが、ここに使用したことを記述しておく。 ================================================ FILE: patch/.editorconfig ================================================ # Rules in this file were initially inferred by Visual Studio IntelliCode from the D:\dev\patch\patch\ codebase based on best match to current usage at 2021/08/07 # You can modify the rules from these initially generated values to suit your own policies # You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference [*.{cpp,hpp}] charset = utf-8 ================================================ FILE: patch/add_dll_ref.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include "global.hpp" // 自身の参照カウントを増やす inline class add_dll_ref_t { inline static bool loading_self = false; public: bool dllmain_if_break() noexcept { return loading_self; } void add_ref() noexcept { loading_self = true; LoadLibraryW(GLOBAL::patchaul_path.c_str()); loading_self = false; } } add_dll_ref; ================================================ FILE: patch/clprogram.cl ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ kernel void PolorTransform(global short* dst, global short* src, int obj_w, int obj_h, int obj_line, int center_length, int radius, float angle, float uzu, float uzu_a){ int x = get_global_id(0); int y = get_global_id(1); int x_dist = x - radius; int y_dist = y - radius; float dist = sqrt((float)(x_dist * x_dist + y_dist * y_dist)); int range = (int)round((float)obj_w / max(dist, 1.0f) * 57.6115417480468f + uzu_a); int yy_t256 = (int)round((float)(((obj_h + center_length) << 8) / radius) * dist); int yy_range_fr = 0x100 - (yy_t256 & 0xff); int yy_begin = (yy_t256 >> 8) - center_length; int xx_t256 = (int)round((((float)radius - dist) * uzu + angle - atan2((float)y_dist, (float)x_dist)) * (float)obj_w * 40.7436637878417f) - range / 2; int xx_range_fr = 0x100 - (xx_t256 & 0xff); int xx_begin = (xx_t256 >> 8) % obj_w; range = max(0x100,range); int yy = yy_begin; int sum_y = 0; int sum_cb = 0; int sum_cr = 0; int sum_a = 0; global short* pix; int src_a; if (0 <= yy && yy < obj_h) { int range_remain = range; int xx = xx_begin; if (xx_range_fr) { pix = src + (xx + yy * obj_line) * 4; sum_a = pix[3] * xx_range_fr * yy_range_fr >> 16; sum_y = pix[0] * sum_a >> 12; sum_cb = pix[1] * sum_a >> 12; sum_cr = pix[2] * sum_a >> 12; range_remain -= xx_range_fr; xx++; xx %= obj_w; } int pix_range = range_remain >> 8; for(int i=0;i> 8; sum_y += pix[0] * src_a >> 12; sum_cb += pix[1] * src_a >> 12; sum_cr += pix[2] * src_a >> 12; sum_a += src_a; xx++; xx %= obj_w; } range_remain &= 0xff; if (range_remain) { pix = src + (xx + yy * obj_line) * 4; src_a = pix[3] * range_remain * yy_range_fr >> 16; sum_y += pix[0] * src_a >> 12; sum_cb += pix[1] * src_a >> 12; sum_cr += pix[2] * src_a >> 12; sum_a += src_a; } } yy++; yy_range_fr = 0x100 - yy_range_fr; if (0 <= yy && yy < obj_h) { int range_remain = range; int xx = xx_begin; if (xx_range_fr != 0x100) { pix = src + (xx + yy * obj_line) * 4; src_a = pix[3] * xx_range_fr * yy_range_fr >> 16; sum_y += pix[0] * src_a >> 12; sum_cb += pix[1] * src_a >> 12; sum_cr += pix[2] * src_a >> 12; sum_a += src_a; range_remain -= xx_range_fr; xx++; xx %= obj_w; } int pix_range = range_remain >> 8; for(int i=0;i> 8; sum_y += pix[0] * src_a>> 12; sum_cb += pix[1] * src_a >> 12; sum_cr += pix[2] * src_a >> 12; sum_a += src_a; xx++; xx %= obj_w; } range_remain &= 0xff; if (range_remain) { pix = src + (xx + yy * obj_line) * 4; src_a = pix[3] * range_remain * yy_range_fr >> 16; sum_y += pix[0] * src_a >> 12; sum_cb += pix[1] * src_a >> 12; sum_cr += pix[2] * src_a >> 12; sum_a += src_a; } } dst += (x + y * obj_line) * 4; if (sum_a) { float a_float = 4096.0f / (float)sum_a; dst[0] = (short)round((float)sum_y * a_float); dst[1] = (short)round((float)sum_cb * a_float); dst[2] = (short)round((float)sum_cr * a_float); dst[3] = (short)((sum_a << 8) / range); } else { dst[0] = dst[1] = dst[2] = dst[3] = 0; } } kernel void DisplacementMap_move(global short* dst, global short* src, global short* mem, int obj_w, int obj_h, int obj_line, int param0, int param1, int ox, int oy) { int x = get_global_id(0); int y = get_global_id(1); dst += (x + y * obj_line) * 4; mem += (x + y * obj_line) * 4; int p0 = min(mem[0], mem[obj_line * 4]); int p1 = max(mem[4], mem[obj_line * 4 + 4]); p0 = (p0 - 0x800) * param0 / 5; p1 = (p1 - 0x800) * param0 / 5 + 0x1000; if (p1 < p0) { int tmp = p0; p0 = p1; p1 = tmp; } int xx_range = p1 - p0; int xx_begin = p0 + (x << 12); int xx_end = xx_range + xx_begin; p0 = min(mem[1], mem[5]); p1 = max(mem[obj_line * 4 + 1], mem[obj_line * 4 + 5]); p0 = (p0 - 0x800) * param1 / 5; p1 = (p1 - 0x800) * param1 / 5 + 0x1000; if (p1 < p0) { int tmp = p0; p0 = p1; p1 = tmp; } int yy_range = p1 - p0; int yy_begin = p0 + (y << 12); int yy_end = yy_range + yy_begin; if (xx_range < 0x1000) { xx_begin += (xx_range - 0x1000) >> 1; xx_end = xx_begin + 0x1000; xx_range = 0x1000; } if (yy_range < 0x1000) { yy_begin += (yy_range - 0x1000) >> 1; yy_end = yy_begin + 0x1000; yy_range = 0x1000; } int xx_level = 12; int yy_level = 12; while (0x20000 < xx_range) { xx_begin >>= 1; xx_end++; xx_end >>= 1; xx_range = xx_end - xx_begin; xx_level--; } while (0x20000 < yy_range) { yy_begin >>= 1; yy_end++; yy_end >>= 1; yy_range = yy_end - yy_begin; yy_level--; } xx_level &= 0x1f; yy_level &= 0x1f; xx_begin = max(xx_begin, 0); xx_end = min(xx_end, obj_w << xx_level); yy_begin = max(yy_begin, 0); yy_end = min(yy_end, obj_h << yy_level); float dsum_y = 0.0f; float dsum_cb = 0.0f; float dsum_cr = 0.0f; float dsum_a = 0.0f; int yy = yy_begin; while (yy < yy_end) { int yy_itr = yy >> yy_level; int sum_y = 0; int sum_cb = 0; int sum_cr = 0; int sum_a = 0; int xx = xx_begin; while (xx < xx_end) { int xx_itr = xx >> xx_level; int fraction; if (xx & 0xfff) { fraction = -xx & 0xfff; } else { fraction = min(xx_end - xx, 0x1000); } global short* srct = src + (xx_itr + yy_itr * obj_line) * 4; int src_a = srct[3] * fraction >> 8; sum_y += srct[0] * src_a >> 16; sum_cb += srct[1] * src_a >> 16; sum_cr += srct[2] * src_a >> 16; sum_a += src_a; xx += fraction; } int fraction; if (yy & 0xfff) { fraction = -yy & 0xfff; } else { fraction = min(yy_end - yy, 0x1000); } float fraction_rate = (float)fraction * 0.000244140625f; dsum_y += (float)sum_y * fraction_rate; dsum_cb += (float)sum_cb * fraction_rate; dsum_cr += (float)sum_cr * fraction_rate; dsum_a += (float)sum_a * fraction_rate; yy += fraction; } if (256.0f <= dsum_a) { float inv_a = 65536.0f / dsum_a; dst[0] = (short)round(dsum_y * inv_a); dst[1] = (short)round(dsum_cb * inv_a); dst[2] = (short)round(dsum_cr * inv_a); dst[3] = (short)round(dsum_a / ((float)yy_range / 1024.0f) / ((float)xx_range / 1024.0f)); } else { dst[0] = dst[1] = dst[2] = dst[3] = 0; } } kernel void DisplacementMap_zoom(global short* dst, global short* src, global short* mem, int obj_w, int obj_h, int obj_line, int param0, int param1, int ox, int oy){ int x = get_global_id(0); int y = get_global_id(1); dst += (x + y * obj_line) * 4; mem += (x + y * obj_line) * 4; int xx_min, xx_max, yy_min, yy_max; int xx_temp, yy_temp; float zoom; float xxd = (float)(x * 0x1000 - ox); if (0 < param0) { zoom = (1024.0f / (float)(param0 + 1000) - 1.0) * 0.00048828125f; } else { zoom = (float)param0 * -0.00000048828125f; } float temp = xxd * zoom; xx_min = xx_max = x * 0x1000 + (int)((float)(mem[0] - 0x800) * temp); xx_temp = x * 0x1000 + (int)((float)(mem[obj_line * 4] - 0x800) * temp); xx_min = min(xx_min, xx_temp); xx_max = max(xx_max, xx_temp); temp = (xxd + 4096.0f) * zoom; xx_temp = (x + 1) * 0x1000 + (int)((float)(mem[4] - 0x800) * temp); xx_min = min(xx_min, xx_temp); xx_max = max(xx_max, xx_temp); xx_temp = (x + 1) * 0x1000 + (int)((float)(mem[(obj_line + 1) * 4] - 0x800) * temp); int xx_begin = min(xx_min, xx_temp); int xx_end = max(xx_max, xx_temp); float yyd = (float)(y * 0x1000 - oy); if (0 < param1) { zoom = (1024.0f / (float)(param1 + 1000) - 1.0) * 0.00048828125f; } else { zoom = (float)param1 * -0.00000048828125f; } temp = yyd * zoom; yy_min = yy_max = y * 0x1000 + (int)((float)(mem[1] - 0x800) * temp); yy_temp = y * 0x1000 + (int)((float)(mem[5] - 0x800) * temp); yy_min = min(yy_min, yy_temp); yy_max = max(yy_max, yy_temp); temp = (yyd + 4096.0f) * zoom; yy_temp = (y + 1) * 0x1000 + (int)((float)(mem[(obj_line + 1) * 4] - 0x800) * temp); yy_min = min(yy_min, yy_temp); yy_max = max(yy_max, yy_temp); yy_temp = (y + 1) * 0x1000 + (int)((float)(mem[obj_line * 4 + 5] - 0x800) * temp); int yy_begin = min(yy_min, yy_temp); int yy_end = max(yy_max, yy_temp); int xx_range = xx_end - xx_begin; int yy_range = yy_end - yy_begin; if (xx_range < 0x1000) { xx_begin += (xx_range - 0x1000) >> 1; xx_end = xx_begin + 0x1000; xx_range = 0x1000; } if (yy_range < 0x1000) { yy_begin += (yy_range - 0x1000) >> 1; yy_end = yy_begin + 0x1000; yy_range = 0x1000; } int xx_level = 12; int yy_level = 12; while (0x20000 < xx_range) { xx_begin >>= 1; xx_end++; xx_end >>= 1; xx_range = xx_end - xx_begin; xx_level--; } while (0x20000 < yy_range) { yy_begin >>= 1; yy_end++; yy_end >>= 1; yy_range = yy_end - yy_begin; yy_level--; } xx_level &= 0x1f; yy_level &= 0x1f; xx_begin = max(xx_begin, 0); xx_end = min(xx_end, obj_w << xx_level); yy_begin = max(yy_begin, 0); yy_end = min(yy_end, obj_h << yy_level); float dsum_y = 0.0f; float dsum_cb = 0.0f; float dsum_cr = 0.0f; float dsum_a = 0.0f; int yy = yy_begin; while (yy < yy_end) { int yy_itr = yy >> yy_level; int sum_y = 0; int sum_cb = 0; int sum_cr = 0; int sum_a = 0; int xx = xx_begin; while (xx < xx_end) { int xx_itr = xx >> xx_level; int fraction; if (xx & 0xfff) { fraction = -xx & 0xfff; } else { fraction = min(xx_end - xx, 0x1000); } global short* srct = src + (xx_itr + yy_itr * obj_line) * 4; int src_a = srct[3] * fraction >> 8; sum_y += srct[0] * src_a >> 16; sum_cb += srct[1] * src_a >> 16; sum_cr += srct[2] * src_a >> 16; sum_a += src_a; xx += fraction; } int fraction; if (yy & 0xfff) { fraction = -yy & 0xfff; } else { fraction = min(yy_end - yy, 0x1000); } float fraction_rate = (float)fraction * 0.000244140625f; dsum_y += (float)sum_y * fraction_rate; dsum_cb += (float)sum_cb * fraction_rate; dsum_cr += (float)sum_cr * fraction_rate; dsum_a += (float)sum_a * fraction_rate; yy += fraction; } if (256.0f <= dsum_a) { float inv_a = 65536.0f / dsum_a; dst[0] = (short)round(dsum_y * inv_a); dst[1] = (short)round(dsum_cb * inv_a); dst[2] = (short)round(dsum_cr * inv_a); dst[3] = (short)round(dsum_a / ((float)yy_range / 1024.0f) / ((float)xx_range / 1024.0f)); } else { dst[0] = dst[1] = dst[2] = dst[3] = 0; } } kernel void DisplacementMap_rot(global short* dst, global short* src, global short* mem, int obj_w, int obj_h, int obj_line, int param0, int param1, int ox, int oy){ int x = get_global_id(0); int y = get_global_id(1); dst += (x + y * obj_line) * 4; mem += (x + y * obj_line) * 4; int xx_min, xx_max, yy_min, yy_max; int xx_temp, yy_temp; float xxd = (float)((x << 12) - ox); float yyd = (float)((y << 12) - oy); float xxd_next = xxd + 4096.0f; float yyd_next = yyd + 4096.0f; float paramrad = (float)param0 * (float)-0.000003067961642955197f; float rad = (float)(mem[0] - 0x800) * paramrad; float sinv = sin(rad); float cosv = cos(rad); xx_min = xx_max = (int)(xxd * cosv - yyd * sinv); yy_min = yy_max = (int)(xxd * sinv + yyd * cosv); rad = (float)(mem[4] - 0x800) * paramrad; sinv = sin(rad); cosv = cos(rad); xx_temp = (int)(xxd_next * cosv - yyd * sinv); yy_temp = (int)(xxd_next * sinv + yyd * cosv); xx_min = min(xx_min, xx_temp); xx_max = max(xx_max, xx_temp); yy_min = min(yy_min, yy_temp); yy_max = max(yy_max, yy_temp); rad = (float)(mem[obj_line * 4] - 0x800) * paramrad; sinv = sin(rad); cosv = cos(rad); xx_temp = (int)(xxd * cosv - yyd_next * sinv); yy_temp = (int)(xxd * sinv + yyd_next * cosv); xx_min = min(xx_min, xx_temp); xx_max = max(xx_max, xx_temp); yy_min = min(yy_min, yy_temp); yy_max = max(yy_max, yy_temp); rad = (float)(mem[(obj_line + 1) * 4] - 0x800) * paramrad; sinv = sin(rad); cosv = cos(rad); xx_temp = (int)(xxd_next * cosv - yyd_next * sinv); yy_temp = (int)(xxd_next * sinv + yyd_next * cosv); int xx_begin = min(xx_min, xx_temp) + ox; int xx_end = max(xx_max, xx_temp) + ox; int yy_begin = min(yy_min, yy_temp) + oy; int yy_end = max(yy_max, yy_temp) + oy; int xx_range = xx_end - xx_begin; int yy_range = yy_end - yy_begin; if (xx_range < 0x1000) { xx_begin += (xx_range - 0x1000) >> 1; xx_end = xx_begin + 0x1000; xx_range = 0x1000; } if (yy_range < 0x1000) { yy_begin += (yy_range - 0x1000) >> 1; yy_end = yy_begin + 0x1000; yy_range = 0x1000; } int xx_level = 12; int yy_level = 12; while (0x20000 < xx_range) { xx_begin >>= 1; xx_end++; xx_end >>= 1; xx_range = xx_end - xx_begin; xx_level--; } while (0x20000 < yy_range) { yy_begin >>= 1; yy_end++; yy_end >>= 1; yy_range = yy_end - yy_begin; yy_level--; } xx_level &= 0x1f; yy_level &= 0x1f; xx_begin = max(xx_begin, 0); xx_end = min(xx_end, obj_w << xx_level); yy_begin = max(yy_begin, 0); yy_end = min(yy_end, obj_h << yy_level); float dsum_y = 0.0f; float dsum_cb = 0.0f; float dsum_cr = 0.0f; float dsum_a = 0.0f; int yy = yy_begin; while (yy < yy_end) { int yy_itr = yy >> yy_level; int sum_y = 0; int sum_cb = 0; int sum_cr = 0; int sum_a = 0; int xx = xx_begin; while (xx < xx_end) { int xx_itr = xx >> xx_level; int fraction; if (xx & 0xfff) { fraction = -xx & 0xfff; } else { fraction = min(xx_end - xx, 0x1000); } global short* srct = src + (xx_itr + yy_itr * obj_line) * 4; int src_a = srct[3] * fraction >> 8; sum_y += srct[0] * src_a >> 16; sum_cb += srct[1] * src_a >> 16; sum_cr += srct[2] * src_a >> 16; sum_a += src_a; xx += fraction; } int fraction; if (yy & 0xfff) { fraction = -yy & 0xfff; } else { fraction = min(yy_end - yy, 0x1000); } float fraction_rate = (float)fraction * 0.000244140625f; dsum_y += (float)sum_y * fraction_rate; dsum_cb += (float)sum_cb * fraction_rate; dsum_cr += (float)sum_cr * fraction_rate; dsum_a += (float)sum_a * fraction_rate; yy += fraction; } if (256.0f <= dsum_a) { float inv_a = 65536.0f / dsum_a; dst[0] = (short)round(dsum_y * inv_a); dst[1] = (short)round(dsum_cb * inv_a); dst[2] = (short)round(dsum_cr * inv_a); dst[3] = (short)round(dsum_a / ((float)yy_range / 1024.0f) / ((float)xx_range / 1024.0f)); } else { dst[0] = dst[1] = dst[2] = dst[3] = 0; } } kernel void RadiationalBlur_Media( global short* dst, global short* src, int src_w, int src_h, int buffer_line, int rb_blur_cx, int rb_blur_cy, int rb_obj_cx, int rb_obj_cy, int rb_range, int rb_pixel_range) { int x = get_global_id(0); int y = get_global_id(1); int pixel_itr = x + y * buffer_line; x += rb_obj_cx; y += rb_obj_cy; int cx = rb_blur_cx - x; int cy = rb_blur_cy - y; int c_dist_times8 = (int)round(sqrt((float)(cx * cx + cy * cy)) * 8.0f); int range = rb_range * c_dist_times8 / 1000; if (rb_pixel_range < c_dist_times8) { range = rb_pixel_range * rb_range / 1000; c_dist_times8 = rb_pixel_range; } else if (8 < c_dist_times8) { c_dist_times8 *= 8; range *= 8; } else if (4 < c_dist_times8) { c_dist_times8 *= 4; range *= 4; } else if (2 < c_dist_times8) { c_dist_times8 *= 2; range *= 2; } if (2 <= c_dist_times8 && 2 <= range) { int sum_a = 0; int sum_cr = 0; int sum_cb = 0; int sum_y = 0; for (int i = 0; i < range; i++) { int x_itr = x + i * cx / c_dist_times8; int y_itr = y + i * cy / c_dist_times8; if (0 <= x_itr && x_itr < src_w && 0 <= y_itr && y_itr < src_h) { short4 itr = vload4(x_itr + y_itr * buffer_line, src); int itr_a = itr.w; sum_a += itr_a; if (0x1000 < itr_a) { itr_a = 0x1000; } sum_y += itr.x * itr_a / 4096; sum_cb += itr.y * itr_a / 4096; sum_cr += itr.z * itr_a / 4096; } } if (sum_a != 0) { vstore4( (short4)( round(sum_y * 4096.0f / sum_a), round(sum_cb * 4096.0f / sum_a), round(sum_cr * 4096.0f / sum_a), sum_a / range ), pixel_itr, dst ); } else { dst[pixel_itr * 4 + 3] = 0; } } else { if (x < 0 || y < 0 || src_w <= x || src_h <= y) { vstore4((short4)(0, 0, 0, 0), pixel_itr, dst); } else { vstore4(vload4(x + y * buffer_line, src), pixel_itr, dst); } } } kernel void RadiationalBlur_Filter( global short* dst, global short* src, int buffer_line, int rb_blur_cx, int rb_blur_cy, int rb_range, int rb_pixel_range) { int x = get_global_id(0); int y = get_global_id(1); int cx = rb_blur_cx - x; int cy = rb_blur_cy - y; int c_dist_times8 = (int)round(sqrt((float)(cx * cx + cy * cy)) * 8.0f); int range = rb_range * c_dist_times8 / 1000; if (rb_pixel_range < c_dist_times8) { range = (rb_pixel_range * rb_range) / 1000; c_dist_times8 = rb_pixel_range; } else if (8 < c_dist_times8) { c_dist_times8 *= 8; range *= 8; } else if (4 < c_dist_times8) { c_dist_times8 *= 4; range *= 4; } else if (2 < c_dist_times8) { c_dist_times8 *= 2; range *= 2; } int offset = (x + y * buffer_line) * 3; if (2 <= c_dist_times8 && 2 <= range) { int sum_y = 0; int sum_cb = 0; int sum_cr = 0; for (int i = 0; i < range; i++) { int x_itr = x + i * cx / c_dist_times8; int y_itr = y + i * cy / c_dist_times8; int pix_offset = (x_itr + y_itr * buffer_line) * 3; sum_y += src[pix_offset]; sum_cb += src[++pix_offset]; sum_cr += src[++pix_offset]; } dst[offset] = (short)(sum_y / range); dst[++offset] = (short)(sum_cb / range); dst[++offset] = (short)(sum_cr / range); } else { dst[offset] = src[offset]; dst[offset + 1] = src[offset + 1]; dst[offset + 2] = src[offset + 2]; } } kernel void RadiationalBlur_Filter_Far( global short* dst, global short* src, int scene_w, int scene_h, int buffer_line, int rb_blur_cx, int rb_blur_cy, int rb_range, int rb_pixel_range) { int x = get_global_id(0); int y = get_global_id(1); int cx = rb_blur_cx - x; int cy = rb_blur_cy - y; int c_dist_times8 = (int)round(sqrt((float)(cx * cx + cy * cy)) * 8.0f); int range = rb_range * c_dist_times8 / 1000; if (rb_pixel_range < c_dist_times8) { range = (rb_pixel_range * rb_range) / 1000; c_dist_times8 = rb_pixel_range; } else if (8 < c_dist_times8) { c_dist_times8 *= 8; range *= 8; } else if (4 < c_dist_times8) { c_dist_times8 *= 4; range *= 4; } else if (2 < c_dist_times8) { c_dist_times8 *= 2; range *= 2; } int offset = (x + y * buffer_line) * 3; if (2 <= c_dist_times8 && 2 <= range) { int sum_y = 0; int sum_cb = 0; int sum_cr = 0; for (int i = 0; i < range; i++) { int x_itr = x + i * cx / c_dist_times8; int y_itr = y + i * cy / c_dist_times8; if (0 <= x_itr && 0 <= y_itr && x_itr < scene_w && y_itr < scene_h) { int pix_offset = (x_itr + y_itr * buffer_line) * 3; sum_y += src[pix_offset]; sum_cb += src[++pix_offset]; sum_cr += src[++pix_offset]; } } dst[offset] = (short)(sum_y / range); dst[++offset] = (short)(sum_cb / range); dst[++offset] = (short)(sum_cr / range); } else { dst[offset] = src[offset]; dst[offset + 1] = src[offset + 1]; dst[offset + 2] = src[offset + 2]; } } kernel void Flash(global short* dst, global short* src, int src_w, int src_h, int exedit_buffer_line, int g_cx, int g_cy, int g_range, int g_pixel_range, int g_temp_x, int g_temp_y, int g_r_intensity ) { int xi = get_global_id(0); int yi = get_global_id(1); int x = xi + g_temp_x; int y = yi + g_temp_y; int pixel_itr = xi + yi * exedit_buffer_line; int cx = g_cx - x; int cy = g_cy - y; int c_dist_times8 = (int)round(sqrt((float)(cx * cx + cy * cy)) * 8.0f); int range = g_range * c_dist_times8 / 1000; if (g_pixel_range < c_dist_times8) { range = g_pixel_range * g_range / 1000; c_dist_times8 = g_pixel_range; } else if (8 < c_dist_times8) { c_dist_times8 *= 8; range *= 8; } else if (4 < c_dist_times8) { c_dist_times8 *= 4; range *= 4; } else if (2 < c_dist_times8) { c_dist_times8 *= 2; range *= 2; } int sum_y, sum_cb, sum_cr; if (2 <= c_dist_times8 && 2 <= range) { sum_y = sum_cb = sum_cr = 0; for (int i = 0; i < range; i++) { int x_itr = x + i * cx / c_dist_times8; int y_itr = y + i * cy / c_dist_times8; if (0 <= x_itr && 0 <= y_itr && x_itr < src_w && y_itr < src_h) { short4 itr = vload4(x_itr + y_itr * exedit_buffer_line, src); if (itr.w != 0) { if (itr.w < 4096) { sum_y += itr.x * itr.w / 4096; sum_cb += itr.y * itr.w / 4096; sum_cr += itr.z * itr.w / 4096; } else { sum_y += itr.x; sum_cb += itr.y; sum_cr += itr.z; } } } } sum_y /= range; sum_cb /= range; sum_cr /= range; } else { if (x < 0 || y < 0 || src_w <= x || src_h <= y) { vstore4((short4)(0, 0, 0, 0), pixel_itr, dst); return; } else { short4 itr = vload4(x + y * exedit_buffer_line, src); sum_y = itr.x * itr.w / 4096; sum_cb = itr.y * itr.w / 4096; sum_cr = itr.z * itr.w / 4096; } } int ya = sum_y - g_r_intensity; if (ya < 1) { vstore4((short4)(0, 0, 0, 0), pixel_itr, dst); } else { sum_cb -= g_r_intensity * sum_cb / sum_y; sum_cr -= g_r_intensity * sum_cr / sum_y; if (ya < 4096) { vstore4( (short4)( 4096, sum_cb * 4096 / ya, sum_cr * 4096 / ya, ya ), pixel_itr, dst ); } else { vstore4( (short4)( ya, sum_cb, sum_cr, 4096 ), pixel_itr, dst ); } } } kernel void FlashColor(global short* dst, global short* src, int src_w, int src_h, int exedit_buffer_line, int g_cx, int g_cy, int g_range, int g_pixel_range, int g_temp_x, int g_temp_y, int g_r_intensity, short g_color_y, short g_color_cb, short g_color_cr ) { int xi = get_global_id(0); int yi = get_global_id(1); int x = xi + g_temp_x; int y = yi + g_temp_y; int pixel_itr = xi + yi * exedit_buffer_line; int cx = g_cx - x; int cy = g_cy - y; int c_dist_times8 = (int)round(sqrt((float)(cx * cx + cy * cy)) * 8.0f); int range = g_range * c_dist_times8 / 1000; if (g_pixel_range < c_dist_times8) { range = g_pixel_range * g_range / 1000; c_dist_times8 = g_pixel_range; } else if (8 < c_dist_times8) { c_dist_times8 *= 8; range *= 8; } else if (4 < c_dist_times8) { c_dist_times8 *= 4; range *= 4; } else if (2 < c_dist_times8) { c_dist_times8 *= 2; range *= 2; } int itr_y, itr_cb, itr_cr; if (2 <= c_dist_times8 && 2 <= range) { int sum_a = 0; for (int i = 0; i < range; i++) { int x_itr = x + i * cx / c_dist_times8; int y_itr = y + i * cy / c_dist_times8; if (0 <= x_itr && 0 <= y_itr && x_itr < src_w && y_itr < src_h) { short4 itr = vload4(x_itr + y_itr * exedit_buffer_line, src); int itr_a = itr.w; if (itr_a != 0) { if (itr_a < 4096) { sum_a += itr_a; } else { sum_a += 4096; } } } } sum_a /= range; itr_y = g_color_y * sum_a / 4096; itr_cb = g_color_cb * sum_a / 4096; itr_cr = g_color_cr * sum_a / 4096; } else { if (x < 0 || y < 0 || src_w <= x || src_h <= y) { vstore4((short4)(0, 0, 0, 0), pixel_itr, dst); return; } else { short4 itr = vload4(x + y * exedit_buffer_line, src); int itr_a = itr.w; itr_y = g_color_y * itr_a / 4096; itr_cb = g_color_cb * itr_a / 4096; itr_cr = g_color_cr * itr_a / 4096; } } int ya = itr_y - g_r_intensity; if (ya < 1) { vstore4((short4)(0, 0, 0, 0), pixel_itr, dst); } else { itr_cb -= g_r_intensity * itr_cb / itr_y; itr_cr -= g_r_intensity * itr_cr / itr_y; if (ya < 4096) { vstore4( (short4)( 4096, itr_cb * 4096 / ya, itr_cr * 4096 / ya, ya ), pixel_itr, dst ); } else { vstore4( (short4)( ya, itr_cb, itr_cr, 4096 ), pixel_itr, dst ); } } } kernel void DirectionalBlur_Media(global short* dst, global short* src, int obj_w, int obj_h, int obj_line, int x_begin, int x_end, int x_step, int y_begin, int y_end, int y_step, int range) { int x = get_global_id(0); int y = get_global_id(1); int pix_range = range * 2 + 1; dst += (x + y * obj_line) * 4; int sum_y = 0; int sum_cb = 0; int sum_cr = 0; int sum_a = 0; int x_itr = ((x + x_begin) << 16) + 0x8000 - range * x_step; int y_itr = ((y + y_begin) << 16) + 0x8000 - range * y_step; for (int n = 0; n < pix_range; n++) { int xx = x_itr >> 16; int yy = y_itr >> 16; if (0 <= xx && xx < obj_w && 0 <= yy && yy < obj_h) { global short* pix = src + (xx + yy * obj_line) * 4; int src_a = min((int)pix[3], 0x1000); sum_y += pix[0] * src_a >> 12; sum_cb += pix[1] * src_a >> 12; sum_cr += pix[2] * src_a >> 12; sum_a += src_a; } x_itr += x_step; y_itr += y_step; } if (0 < sum_a) { float a_float = 4096.0f / (float)sum_a; dst[0] = (short)round((float)sum_y * a_float); dst[1] = (short)round((float)sum_cb * a_float); dst[2] = (short)round((float)sum_cr * a_float); } else { dst[0] = dst[1] = dst[2] = 0; } dst[3] = (short)(sum_a / pix_range); } kernel void DirectionalBlur_original_size(global short* dst, global short* src, int obj_w, int obj_h, int obj_line, int x_step, int y_step, int range) { int x = get_global_id(0); int y = get_global_id(1); int pix_range = range * 2 + 1; dst += (x + y * obj_line) * 4; int x_itr = (x << 16) + 0x8000 - range * x_step; int y_itr = (y << 16) + 0x8000 - range * y_step; int sum_y = 0; int sum_cb = 0; int sum_cr = 0; int sum_a = 0; int cnt = 0; for (int n = 0; n < pix_range; n++) { int xx = x_itr >> 16; int yy = y_itr >> 16; if (0 <= xx && xx < obj_w && 0 <= yy && yy < obj_h) { global short* pix = src + (xx + yy * obj_line) * 4; int src_a = min((int)pix[3], 0x1000); sum_y += pix[0] * src_a >> 12; sum_cb += pix[1] * src_a >> 12; sum_cr += pix[2] * src_a >> 12; sum_a += src_a; cnt++; } x_itr += x_step; y_itr += y_step; } if(cnt == 0) cnt = 0xffffff; if (0 < sum_a) { float a_float = 4096.0f / (float)sum_a; dst[0] = (short)round((float)sum_y * a_float); dst[1] = (short)round((float)sum_cb * a_float); dst[2] = (short)round((float)sum_cr * a_float); } else { dst[0] = dst[1] = dst[2] = 0; } dst[3] = (short)(sum_a / cnt); } kernel void DirectionalBlur_Filter(global short* dst, global short* src, int scene_w, int scene_h, int scene_line, int x_step, int y_step, int range) { int x = get_global_id(0); int y = get_global_id(1); int pix_range = range * 2 + 1; dst += (x + y * scene_line) * 3; int x_itr = (x << 16) + 0x8000 - range * x_step; int y_itr = (y << 16) + 0x8000 - range * y_step; int sum_y = 0; int sum_cb = 0; int sum_cr = 0; int cnt = 0; for (int n = 0; n < pix_range; n++) { int xx = x_itr >> 16; int yy = y_itr >> 16; if (0 <= xx && xx < scene_w && 0 <= yy && yy < scene_h) { global short* pix = src + (xx + yy * scene_line) * 3; sum_y += pix[0]; sum_cb += pix[1]; sum_cr += pix[2]; cnt++; } x_itr += x_step; y_itr += y_step; } if(cnt == 0) cnt = 0xffffff; dst[0] = (short)(sum_y / cnt); dst[1] = (short)(sum_cb / cnt); dst[2] = (short)(sum_cr / cnt); } kernel void LensBlur_Media(global char* dst, global char* src, int obj_w, int obj_h, int obj_line, int range, int rangep05_sqr, int range_t3m1, int rangem1_sqr) { int x = get_global_id(0); int y = get_global_id(1); int top = -min(y, range); int bottom = min(obj_h - y - 1, range); int left = -min(x, range); int right = min(obj_w - x - 1, range); float sum_y = 0.0f; int sum_cb = 0; int sum_cr = 0; int sum_a = 0; int cor_sum = 0; int offset = (x + left + (y + top) * obj_line) * 8; for (int yy = top; yy <= bottom; yy++) { int sqr = yy * yy + left * left; int offset2 = offset; for (int xx = left; xx <= right; xx++) { if (sqr < rangep05_sqr) { int cor_a; if (rangem1_sqr < sqr) { cor_a = ((rangep05_sqr - sqr) << 12) / range_t3m1; } else { cor_a = 4096; } cor_sum += cor_a; cor_a = *(global short*)&src[offset2 + 6] * cor_a >> 12; sum_y += *(global float*)&src[offset2] * (float)cor_a; sum_cb += src[offset2 + 4] * cor_a; sum_cr += src[offset2 + 5] * cor_a; sum_a += cor_a; } sqr += 1 + xx * 2; offset2 += 8; } offset += obj_line * 8; } dst += (x + y * obj_line) * 8; if (0 < sum_a) { *(global float*)dst = sum_y / (float)sum_a; dst[4] = (char)(((sum_a >> 1) + sum_cb) / sum_a); dst[5] = (char)(((sum_a >> 1) + sum_cr) / sum_a); *(global short*)&dst[6] = (short)round((float)sum_a * (4096.0f / (float)cor_sum)); } else { *(global int*)dst = 0; *(global int*)&dst[4] = 0; } } kernel void LensBlur_Filter(global char* dst, global char* src, int scene_w, int scene_h, int scene_line, int range, int rangep05_sqr, int range_t3m1, int rangem1_sqr) { int x = get_global_id(0); int y = get_global_id(1); int top = -min(y, range); int bottom = min(scene_h - y - 1, range); int left = -min(x, range); int right = min(scene_w - x - 1, range); short tofloat[2]; float sum_y = 0.0f; int sum_cb = 0; int sum_cr = 0; int sum_a = 0; int offset = (x + left + (y + top) * scene_line) * 6; for (int yy = top; yy <= bottom; yy++) { int sqr = yy * yy + left * left; int offset2 = offset; for (int xx = left; xx <= right; xx++) { if (sqr < rangep05_sqr) { int cor_a; if (rangem1_sqr < sqr) { cor_a = ((rangep05_sqr - sqr) << 12) / range_t3m1; } else { cor_a = 4096; } tofloat[0] = *(global short*)&src[offset2]; tofloat[1] = *(global short*)&src[offset2 + 2]; sum_y += *(float*)tofloat * (float)cor_a; sum_cb += src[offset2 + 4] * cor_a; sum_cr += src[offset2 + 5] * cor_a; sum_a += cor_a; } sqr += 1 + xx * 2; offset2 += 6; } offset += scene_line * 6; } dst += (x + y * scene_line) * 6; *(float*)tofloat = sum_y / (float)sum_a; *(global short*)&dst[0] = tofloat[0]; *(global short*)&dst[2] = tofloat[1]; dst[4] = (char)(((sum_a >> 1) + sum_cb) / sum_a); dst[5] = (char)(((sum_a >> 1) + sum_cr) / sum_a); } ================================================ FILE: patch/config.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include #include "macro.h" #include "util_resource.hpp" #include "config_rw.hpp" #include "patch.hpp" class Config2 { bool invalid_json; public: void load(std::wstring_view path) { auto hFile = CreateFileW(path.data(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) return; DWORD ignore; auto size_low = GetFileSize(hFile, &ignore); auto file = std::make_unique(size_low); if (ReadFile(hFile, file.get(), size_low, &ignore, NULL) == FALSE) { patch_resource_message_stack.emplace_back(new patch_resource_message_class_w(PATCH_RS_PATCH_FAILED_TO_LOAD_SETTING, MB_TASKMODAL | MB_ICONEXCLAMATION)); return; } CloseHandle(hFile); json_value_s* root = nullptr; BOOST_SCOPE_EXIT_ALL(&root) { free(root); }; root = json_parse(file.get(), size_low); if (root == nullptr) { patch_resource_message_stack.emplace_back(new patch_resource_message_class_w(PATCH_RS_PATCH_INVALID_SETTING_JSON, MB_TASKMODAL | MB_ICONEXCLAMATION)); invalid_json = true; return; } ConfigReader cr(root); cr.regist("switch", [](json_value_s* value) { ConfigReader cr(value); #ifdef PATCH_SWITCH_ACCESS_KEY patch::access_key.switch_load(cr); #endif #ifdef PATCH_SWITCH_COLORPALETTE_CACHE patch::colorpalette_cache.switch_load(cr); #endif #ifdef PATCH_SWITCH_FILEINFO patch::fileinfo.switch_load(cr); #endif #ifdef PATCH_SWITCH_SUSIE_LOAD patch::susie_load.switch_load(cr); #endif #ifdef PATCH_SWITCH_SPLASH patch::splash.switch_load(cr); #endif #ifdef PATCH_SWITCH_AUP_SCENE_SETTING patch::aup_scene_setting.switch_load(cr); #endif #ifdef PATCH_SWITCH_AUP_LAYER_SETTING patch::aup_layer_setting.switch_load(cr); #endif #ifdef PATCH_SWITCH_EXO_AVIUTL_FILTER patch::exo_aviutlfilter.switch_load(cr); #endif #ifdef PATCH_SWITCH_EXO_SCENEIDX patch::exo_sceneidx.switch_load(cr); #endif #ifdef PATCH_SWITCH_EXO_TRACKPARAM patch::exo_trackparam.switch_load(cr); #endif #ifdef PATCH_SWITCH_EXO_TRACK_MINUSVAL patch::exo_trackminusval.switch_load(cr); #endif #ifdef PATCH_SWITCH_EXO_MIDPT_AND_TRA patch::exo_midpt_and_tra.switch_load(cr); #endif #ifdef PATCH_SWITCH_EXO_SPECIALCOLORCONV patch::exo_specialcolorconv.switch_load(cr); #endif #ifdef PATCH_SWITCH_EXO_FOLD_GUI patch::exo_fold_gui.switch_load(cr); #endif #ifdef PATCH_SWITCH_TRA_AVIUTL_FILTER patch::tra_aviutlfilter.switch_load(cr); #endif #ifdef PATCH_SWITCH_TRA_CHANGE_DRAWFILTER patch::tra_change_drawfilter.switch_load(cr); #endif #ifdef PATCH_SWITCH_TRA_SPECIFIED_SPEED patch::tra_specified_speed.switch_load(cr); #endif #ifdef PATCH_SWITCH_SETTING_NEW_PROJECT patch::setting_new_project.switch_load(cr); #endif #ifdef PATCH_SWITCH_TEXT_OP_SIZE patch::text_op_size.switch_load(cr); #endif #ifdef PATCH_SWITCH_IGNORE_MEDIA_PARAM_RESET patch::ignore_media_param_reset.switch_load(cr); #endif #ifdef PATCH_SWITCH_FONT_DIALOG patch::font_dialog.switch_load(cr); #endif #ifdef PATCH_SWITCH_SCROLL_OBJDLG patch::scroll_objdlg.switch_load(cr); #endif #ifdef PATCH_SWITCH_ALPHA_BG patch::alpha_bg.switch_load(cr); #endif #ifdef PATCH_SWITCH_HELPFUL_MSGBOX patch::helpful_msgbox.switch_load(cr); #endif #ifdef PATCH_SWITCH_FAILED_SJIS_MSGBOX patch::failed_sjis_msgbox.switch_load(cr); #endif #ifdef PATCH_SWITCH_FAILED_LONGER_PATH patch::failed_longer_path.switch_load(cr); #endif #ifdef PATCH_SWITCH_FAILED_FILE_DROP patch::failed_file_drop.switch_load(cr); #endif #ifdef PATCH_SWITCH_THEME_CC patch::theme_cc.switch_load(cr); #endif #ifdef PATCH_SWITCH_EXEDITWINDOW_SIZING patch::exeditwindow_sizing.switch_load(cr); #endif #ifdef PATCH_SWITCH_SETTINGDIALOG_MOVE patch::setting_dialog_move.switch_load(cr); #endif #ifdef PATCH_SWITCH_OBJ_COLORCORRECTION patch::ColorCorrection.switch_load(cr); #endif #ifdef PATCH_SWITCH_OBJ_GLOW patch::Glow.switch_load(cr); #endif #ifdef PATCH_SWITCH_OBJ_LENSBLUR patch::LensBlur.switch_load(cr); #endif #ifdef PATCH_SWITCH_OBJ_NOISE patch::Noise.switch_load(cr); #endif #ifdef PATCH_SWITCH_OBJ_SPECIALCOLORCONV patch::obj_specialcolorconv.switch_load(cr); #endif #ifdef PATCH_SWITCH_SETTINGDIALOG_EXCOLORCONFIG patch::excolorconfig.switch_load(cr); #endif #ifdef PATCH_SWITCH_RCLICKMENU_SPLIT patch::rclickmenu_split.switch_load(cr); #endif #ifdef PATCH_SWITCH_RCLICKMENU_DELETE patch::rclickmenu_delete.switch_load(cr); #endif #ifdef PATCH_SWITCH_BLEND patch::blend.switch_load(cr); #endif #ifdef PATCH_SWITCH_ADD_EXTENSION patch::add_extension.switch_load(cr); #endif #ifdef PATCH_SWITCH_DIALOG_NEW_FILE patch::dialog_new_file.switch_load(cr); #endif #ifdef PATCH_SWITCH_PLAYBACK_SPEED patch::playback_speed.switch_load(cr); #endif #ifdef PATCH_SWITCH_UNDO patch::undo.switch_load(cr); #ifdef PATCH_SWITCH_UNDO_REDO patch::redo.switch_load(cr); #endif #endif #ifdef PATCH_SWITCH_CONSOLE patch::console.switch_load(cr); #endif #ifdef PATCH_SWITCH_LUA patch::lua.switch_load(cr); #ifdef PATCH_SWITCH_LUA_GETVALUE patch::lua_getvalueex.switch_load(cr); #endif #ifdef PATCH_SWITCH_LUA_RAND patch::lua_rand.switch_load(cr); #endif #ifdef PATCH_SWITCH_LUA_RANDEX patch::lua_randex.switch_load(cr); #endif #endif #ifdef PATCH_SWITCH_FAST patch::fast::fast.switch_load(cr); #ifdef PATCH_SWITCH_FAST_EXEDITWINDOW patch::fast_exeditwindow.switch_load(cr); #endif #ifdef PATCH_SWITCH_FAST_SETTINGDIALOG patch::fast_setting_dialog.switch_load(cr); #endif #ifdef PATCH_SWITCH_FAST_TEXT patch::fast::text.switch_load(cr); #endif #ifdef PATCH_SWITCH_FAST_CREATE_FIGURE patch::fast::create_figure.switch_load(cr); #endif #ifdef PATCH_SWITCH_FAST_BORDER patch::fast::Border.switch_load(cr); #endif #ifdef PATCH_SWITCH_FAST_GLOW patch::fast::Glow.switch_load(cr); #endif #ifdef PATCH_SWITCH_CL patch::fast::cl.switch_load(cr); #ifdef PATCH_SWITCH_FAST_RADIATIONALBLUR patch::fast::RadiationalBlur.switch_load(cr); #endif #ifdef PATCH_SWITCH_FAST_POLORTRANSFORM patch::fast::PolorTransform.switch_load(cr); #endif #ifdef PATCH_SWITCH_FAST_DISPLACEMENTMAP patch::fast::DisplacementMap.switch_load(cr); #endif #ifdef PATCH_SWITCH_FAST_FLASH patch::fast::Flash.switch_load(cr); #endif #ifdef PATCH_SWITCH_FAST_DIRECTIONALBLUR patch::fast::DirectionalBlur.switch_load(cr); #endif #ifdef PATCH_SWITCH_FAST_LENSBLUR patch::fast::LensBlur.switch_load(cr); #endif #endif #endif cr.load(); }); #ifdef PATCH_SWITCH_CONSOLE cr.regist("console", [](json_value_s* value) { ConfigReader cr(value); patch::console.config_load(cr); cr.load(); }); #endif #ifdef PATCH_SWITCH_THEME_CC cr.regist("theme_cc", [](json_value_s* value) { ConfigReader cr(value); patch::theme_cc.config_load(cr); cr.load(); }); #endif #ifdef PATCH_SWITCH_UNDO_REDO cr.regist("redo", [](json_value_s* value) { ConfigReader cr(value); patch::redo.config_load(cr); cr.load(); }); #endif #ifdef PATCH_SWITCH_FAST_EXEDITWINDOW cr.regist("fast_exeditwindow", [](json_value_s* value) { ConfigReader cr(value); patch::fast_exeditwindow.config_load(cr); cr.load(); }); #endif #ifdef PATCH_SWITCH_FAST_TEXT cr.regist("fast_text", [](json_value_s* value) { ConfigReader cr(value); patch::fast::text.config_load(cr); cr.load(); }); #endif cr.load(); } void store(std::wstring_view path) { if (invalid_json)return; auto hFile = CreateFileW(path.data(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) { patch_resource_message_w(PATCH_RS_PATCH_FAILED_TO_SAVE_SETTING, MB_TASKMODAL | MB_ICONEXCLAMATION); return; } BOOST_SCOPE_EXIT_ALL(&hFile) { CloseHandle(hFile); }; int level = 0; ConfigWriter cw(level); #ifdef PATCH_SWITCH_CONSOLE { ConfigWriter console(++level); patch::console.config_store(console); std::stringstream ss; console.write(ss); cw.append("console", ss.str()); --level; } #endif #ifdef PATCH_SWITCH_THEME_CC { ConfigWriter theme_cc(++level); patch::theme_cc.config_store(theme_cc); std::stringstream ss; theme_cc.write(ss); cw.append("theme_cc", ss.str()); --level; } #endif #ifdef PATCH_SWITCH_UNDO_REDO { ConfigWriter redo(++level); patch::redo.config_store(redo); std::stringstream ss; redo.write(ss); cw.append("redo", ss.str()); --level; } #endif #ifdef PATCH_SWITCH_FAST_EXEDITWINDOW { ConfigWriter fast_exeditwindow(++level); patch::fast_exeditwindow.config_store(fast_exeditwindow); std::stringstream ss; fast_exeditwindow.write(ss); cw.append("fast_exeditwindow", ss.str()); --level; } #endif #ifdef PATCH_SWITCH_FAST_TEXT { ConfigWriter fast_text(++level); patch::fast::text.config_store(fast_text); std::stringstream ss; fast_text.write(ss); cw.append("fast_text", ss.str()); --level; } #endif { ConfigWriter switch_(++level); #ifdef PATCH_SWITCH_ACCESS_KEY patch::access_key.switch_store(switch_); #endif #ifdef PATCH_SWITCH_COLORPALETTE_CACHE patch::colorpalette_cache.switch_store(switch_); #endif #ifdef PATCH_SWITCH_FILEINFO patch::fileinfo.switch_store(switch_); #endif #ifdef PATCH_SWITCH_SUSIE_LOAD patch::susie_load.switch_store(switch_); #endif #ifdef PATCH_SWITCH_SPLASH patch::splash.switch_store(switch_); #endif #ifdef PATCH_SWITCH_AUP_SCENE_SETTING patch::aup_scene_setting.switch_store(switch_); #endif #ifdef PATCH_SWITCH_AUP_LAYER_SETTING patch::aup_layer_setting.switch_store(switch_); #endif #ifdef PATCH_SWITCH_EXO_AVIUTL_FILTER patch::exo_aviutlfilter.switch_store(switch_); #endif #ifdef PATCH_SWITCH_EXO_SCENEIDX patch::exo_sceneidx.switch_store(switch_); #endif #ifdef PATCH_SWITCH_EXO_TRACKPARAM patch::exo_trackparam.switch_store(switch_); #endif #ifdef PATCH_SWITCH_EXO_TRACK_MINUSVAL patch::exo_trackminusval.switch_store(switch_); #endif #ifdef PATCH_SWITCH_EXO_MIDPT_AND_TRA patch::exo_midpt_and_tra.switch_store(switch_); #endif #ifdef PATCH_SWITCH_EXO_SPECIALCOLORCONV patch::exo_specialcolorconv.switch_store(switch_); #endif #ifdef PATCH_SWITCH_EXO_FOLD_GUI patch::exo_fold_gui.switch_store(switch_); #endif #ifdef PATCH_SWITCH_TRA_AVIUTL_FILTER patch::tra_aviutlfilter.switch_store(switch_); #endif #ifdef PATCH_SWITCH_TRA_CHANGE_DRAWFILTER patch::tra_change_drawfilter.switch_store(switch_); #endif #ifdef PATCH_SWITCH_TRA_SPECIFIED_SPEED patch::tra_specified_speed.switch_store(switch_); #endif #ifdef PATCH_SWITCH_SETTING_NEW_PROJECT patch::setting_new_project.switch_store(switch_); #endif #ifdef PATCH_SWITCH_TEXT_OP_SIZE patch::text_op_size.switch_store(switch_); #endif #ifdef PATCH_SWITCH_IGNORE_MEDIA_PARAM_RESET patch::ignore_media_param_reset.switch_store(switch_); #endif #ifdef PATCH_SWITCH_FONT_DIALOG patch::font_dialog.switch_store(switch_); #endif #ifdef PATCH_SWITCH_SCROLL_OBJDLG patch::scroll_objdlg.switch_store(switch_); #endif #ifdef PATCH_SWITCH_ALPHA_BG patch::alpha_bg.switch_store(switch_); #endif #ifdef PATCH_SWITCH_HELPFUL_MSGBOX patch::helpful_msgbox.switch_store(switch_); #endif #ifdef PATCH_SWITCH_FAILED_SJIS_MSGBOX patch::failed_sjis_msgbox.switch_store(switch_); #endif #ifdef PATCH_SWITCH_FAILED_LONGER_PATH patch::failed_longer_path.switch_store(switch_); #endif #ifdef PATCH_SWITCH_FAILED_FILE_DROP patch::failed_file_drop.switch_store(switch_); #endif #ifdef PATCH_SWITCH_THEME_CC patch::theme_cc.switch_store(switch_); #endif #ifdef PATCH_SWITCH_EXEDITWINDOW_SIZING patch::exeditwindow_sizing.switch_store(switch_); #endif #ifdef PATCH_SWITCH_SETTINGDIALOG_MOVE patch::setting_dialog_move.switch_store(switch_); #endif #ifdef PATCH_SWITCH_OBJ_COLORCORRECTION patch::ColorCorrection.switch_store(switch_); #endif #ifdef PATCH_SWITCH_OBJ_GLOW patch::Glow.switch_store(switch_); #endif #ifdef PATCH_SWITCH_OBJ_LENSBLUR patch::LensBlur.switch_store(switch_); #endif #ifdef PATCH_SWITCH_OBJ_NOISE patch::Noise.switch_store(switch_); #endif #ifdef PATCH_SWITCH_OBJ_SPECIALCOLORCONV patch::obj_specialcolorconv.switch_store(switch_); #endif #ifdef PATCH_SWITCH_SETTINGDIALOG_EXCOLORCONFIG patch::excolorconfig.switch_store(switch_); #endif #ifdef PATCH_SWITCH_RCLICKMENU_SPLIT patch::rclickmenu_split.switch_store(switch_); #endif #ifdef PATCH_SWITCH_RCLICKMENU_DELETE patch::rclickmenu_delete.switch_store(switch_); #endif #ifdef PATCH_SWITCH_BLEND patch::blend.switch_store(switch_); #endif #ifdef PATCH_SWITCH_ADD_EXTENSION patch::add_extension.switch_store(switch_); #endif #ifdef PATCH_SWITCH_DIALOG_NEW_FILE patch::dialog_new_file .switch_store(switch_); #endif #ifdef PATCH_SWITCH_PLAYBACK_SPEED patch::playback_speed.switch_store(switch_); #endif #ifdef PATCH_SWITCH_UNDO patch::undo.switch_store(switch_); #ifdef PATCH_SWITCH_UNDO_REDO patch::redo.switch_store(switch_); #endif #endif #ifdef PATCH_SWITCH_CONSOLE patch::console.switch_store(switch_); #endif #ifdef PATCH_SWITCH_LUA patch::lua.switch_store(switch_); #ifdef PATCH_SWITCH_LUA_GETVALUE patch::lua_getvalueex.switch_store(switch_); #endif #ifdef PATCH_SWITCH_LUA_RAND patch::lua_rand.switch_store(switch_); #endif #ifdef PATCH_SWITCH_LUA_RANDEX patch::lua_randex.switch_store(switch_); #endif #endif #ifdef PATCH_SWITCH_FAST patch::fast::fast.switch_store(switch_); #ifdef PATCH_SWITCH_FAST_EXEDITWINDOW patch::fast_exeditwindow.switch_store(switch_); #endif #ifdef PATCH_SWITCH_FAST_SETTINGDIALOG patch::fast_setting_dialog.switch_store(switch_); #endif #ifdef PATCH_SWITCH_FAST_TEXT patch::fast::text.switch_store(switch_); #endif #ifdef PATCH_SWITCH_FAST_CREATE_FIGURE patch::fast::create_figure.switch_store(switch_); #endif #ifdef PATCH_SWITCH_FAST_BORDER patch::fast::Border.switch_store(switch_); #endif #ifdef PATCH_SWITCH_FAST_GLOW patch::fast::Glow.switch_store(switch_); #endif #ifdef PATCH_SWITCH_CL patch::fast::cl.switch_store(switch_); #ifdef PATCH_SWITCH_FAST_RADIATIONALBLUR patch::fast::RadiationalBlur.switch_store(switch_); #endif #ifdef PATCH_SWITCH_FAST_POLORTRANSFORM patch::fast::PolorTransform.switch_store(switch_); #endif #ifdef PATCH_SWITCH_FAST_DISPLACEMENTMAP patch::fast::DisplacementMap.switch_store(switch_); #endif #ifdef PATCH_SWITCH_FAST_FLASH patch::fast::Flash.switch_store(switch_); #endif #ifdef PATCH_SWITCH_FAST_DIRECTIONALBLUR patch::fast::DirectionalBlur.switch_store(switch_); #endif #ifdef PATCH_SWITCH_FAST_LENSBLUR patch::fast::LensBlur.switch_store(switch_); #endif #endif #endif std::stringstream ss; switch_.write(ss); cw.append("switch", ss.str()); --level; } std::stringstream ss; cw.write(ss); auto s = ss.str(); DWORD ignore; WriteFile(hFile, s.c_str(), s.size(), &ignore, nullptr); } }; inline Config2 config2; ================================================ FILE: patch/config_rw.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include #include #include #include #include #include #include #include #include #include "json.h" #include "util_others.hpp" namespace config_type { struct ColorBGR { union { struct { uint8_t b, g, r; uint8_t valid; }; uint32_t val; }; ColorBGR() : val{} {} ColorBGR(uint32_t x) : val(x) { val = x; valid = 1; } ColorBGR(int b, int g, int r) :b(b), g(g), r(r), valid(1) {} ColorBGR(std::string_view x) { if (x.size() < 6) { b = g = r = valid = 0; return; } auto itr = x.data(); std::from_chars(itr, itr + 2, r, 16); itr += 2; std::from_chars(itr, itr + 2, g, 16); itr += 2; std::from_chars(itr, itr + 2, b, 16); valid = 1; } inline static ColorBGR from_rgb(uint32_t x) { if (std::is_constant_evaluated()) { return (x >> 16 & 0xff) || (x & 0xff00) || (x << 16 & 0xff0000); } else { return _byteswap_ulong(x << 8); } } constexpr uint32_t to_col() const noexcept { return val & 0xffffff; } constexpr uint32_t to_col_rgb() const noexcept { if (std::is_constant_evaluated()) { return b << 16 | g << 8 | r; } else { return _byteswap_ulong(val) >> 8; } } std::string to_string() const { return "{:02x}{:02x}{:02x}"_fmt(r, g, b); } std::string to_jsonstring() const { if(valid) return "\"{:02x}{:02x}{:02x}\""_fmt(r, g, b); return std::string{}; } constexpr bool is_valid() const noexcept { return valid; } bool operator==(ColorBGR x) const { if (this->valid) { if (!x.valid)return false; else return (this->val & 0xffffff) == (x.val & 0xffffff); } else return !x.valid; } }; // ColorBGR2つの配列、またはColorBGR1つ、またはnulloptを表す // [ "ffffff", "ffffff" ] や ["ffffff"]、"ffffff" など struct ColorBGR2_Opt { std::array ary{}; ColorBGR2_Opt() : ary{} {} ColorBGR2_Opt(ColorBGR c1, ColorBGR c2) : ary{ c1,c2 } {} inline void load(json_value_s* value) { if (auto js = json_value_as_string(value)) { ary[0] = std::string_view(js->string, js->string_size); ary[1].valid = 0; } else if (auto ja = json_value_as_array(value)) { if (ja->length == 0) { ary[0].valid = 0; } else if (ja->length == 1) { if (auto js = json_value_as_string(ja->start->value)) { ary[0] = std::string_view(js->string, js->string_size); ary[1].valid = 0; } } else { auto v = ja->start; bool valid = true; for (size_t i = 0; i < 2; i++) { if (auto js = json_value_as_string(v->value)) { ary[i] = std::string_view(js->string, js->string_size); if (!ary[i].is_valid()) { valid = false; break; } } v = v->next; } if (!valid) ary[0].valid = 0; } } } std::string to_jsonstring() const { if (ary[0].is_valid()) { if (ary[1].is_valid()) return "[ {}, {} ]"_fmt(ary[0].to_jsonstring(), ary[1].to_jsonstring()); else return ary[0].to_jsonstring(); } return std::string{}; } constexpr bool has_value() const { return ary[0].is_valid(); } constexpr int count() const { if (!ary[0].is_valid()) return 0; return 1 + ary[1].is_valid(); } }; // ColorBGRを2つ持つかnullopt struct ColorBGR2 { std::array ary; ColorBGR2() : ary{} {} ColorBGR2(ColorBGR c1, ColorBGR c2) : ary{ c1,c2 } {} inline void load(json_value_s* value) { if (auto ja = json_value_as_array(value)) { if (ja->length > 1) { auto v = ja->start; bool valid = true; for (size_t i = 0; i < 2; i++) { if (auto js = json_value_as_string(v->value)) { ary[i] = std::string_view(js->string, js->string_size); if (!ary[i].is_valid()) { valid = false; break; } } v = v->next; } if (!valid) ary[0].valid = 0; } } } std::string to_jsonstring() const { if (ary[0].is_valid()) return "[ {}, {} ]"_fmt(ary[0].to_jsonstring(), ary[1].to_jsonstring()); return std::string{}; } constexpr bool has_value() const { return ary[0].is_valid(); } constexpr int count() const { if (!ary[0].is_valid()) return 0; return 1 + ary[1].is_valid(); } }; struct ColorBGR3 { std::array ary; ColorBGR3() : ary{} {} ColorBGR3(ColorBGR c1, ColorBGR c2, ColorBGR c3) : ary{ c1,c2,c3 } {} inline void load(json_value_s* value) { if (auto ja = json_value_as_array(value)) { if (ja->length > 2) { auto v = ja->start; bool valid = true; for (size_t i = 0; i < 3; i++) { if (auto js = json_value_as_string(v->value)) { ary[i] = std::string_view(js->string, js->string_size); if (!ary[i].is_valid()) { valid = false; break; } } v = v->next; } if (!valid) ary[0].valid = 0; } } } constexpr bool has_value() const { return ary[0].is_valid(); } std::string to_jsonstring() const { if (has_value()) return "[ {}, {}, {} ]"_fmt(ary[0].to_jsonstring(), ary[1].to_jsonstring(), ary[2].to_jsonstring()); return std::string{}; } }; } template concept ConfigWriterHasToJsonString = requires (T x) { x.to_jsonstring(); }; inline std::string mytostring(int x) { std::string ret(std::numeric_limits::digits10 + 2, '\0'); std::to_chars(ret.data(), ret.data() + ret.size(), x); ret.resize(ret.find_first_of('\0')); return ret; } inline std::string mytostring(double x) { std::string ret(std::numeric_limits::max_exponent10 + 9, '\0'); std::to_chars(ret.data(), ret.data() + ret.size(), x); ret.resize(ret.find_first_of('\0')); return ret; } template concept ConfigWriterCanToChars = requires(T x) { mytostring(x); }; template concept ConfigReaderHasLoad = requires(T x) { x.load(std::declval()); }; class ConfigWriter { std::stringstream ss; struct KeyAndValue { std::string key, value; }; std::vector vkv; int level; inline static void WriteLevel(std::stringstream& ss, int level) { for (int i = 0; i < level; i++) ss << '\t'; } // {\n を書く inline static void WriteBlockBegin(std::stringstream& ss) { ss << "{\n"; } // } を書く inline static void WriteBlockEnd(std::stringstream& ss) { ss << "}"; } // [["key" : ]] を書く inline static void WriteKey(std::stringstream& ss, std::string_view key) { ss << "\"" << key << "\" : "; } template inline static void WriteReturn(std::stringstream& ss) { if constexpr (comma) ss << ",\n"; else ss << "\n"; } public: ConfigWriter(int level) : level(level) {} void append(std::string_view key, std::string_view value) { if(value.size() && value[0] != '\0') vkv.emplace_back(std::string(key), std::string(value)); } template void append(std::string_view key, const T& value) { auto result = value.to_jsonstring(); if(result[0] != '\0') vkv.emplace_back(std::string(key), result); } void append(std::string_view key, bool value) { vkv.emplace_back(std::string(key), value ? "true" : "false"); } void append(std::string_view key, const RECT& value) { vkv.emplace_back(std::string(key), "[ {}, {}, {}, {} ]"_fmt(value.left, value.top, value.right, value.bottom)); } template void append(std::string_view key, const std::array& value) { if (value.size() > 0) { std::stringstream ss; ss << "[ "; const auto last = value.size() - 1; for (size_t i = 0; i < last; i++) { ss << value[i] << ", "; } ss << value[last] << " ]"; vkv.emplace_back(std::string(key), ss.str()); } else { vkv.emplace_back(std::string(key), "[]"); } } template void append(std::string_view key, const T& value) { vkv.emplace_back(std::string(key), mytostring(value)); } template void append(std::string_view key, const std::optional& value) { if (value) { append(key, *value); } } void write(std::stringstream& ss) const { auto s = vkv.size(); if (s == 0)return; WriteBlockBegin(ss); for (size_t i = 0; i < s - 1; i++) { WriteLevel(ss, level + 1); WriteKey(ss, vkv[i].key); ss << vkv[i].value; WriteReturn(ss); } WriteLevel(ss, level + 1); WriteKey(ss, vkv[s - 1].key); ss << vkv[s - 1].value; WriteReturn(ss); WriteLevel(ss, level); WriteBlockEnd(ss); } int get_level() const { return level; } }; class ConfigReader { json_value_s* value; using RegisterFunction = std::function; using MapType = std::unordered_map; MapType map; public: ConfigReader(json_value_s* value) : value(value) {} void load() { auto obj = json_value_as_object(value); if (obj == nullptr)return; for (auto elm = obj->start; elm != nullptr; elm = elm->next) { if (auto itr = map.find(elm->name->string); itr != map.end()) { itr->second(elm->value); } } } template void regist(const std::string& str, T func) { map.try_emplace(str, func); } inline static bool load_variable(json_value_s* jv, bool& value) { if (json_value_is_false(jv)) { value = false; return true; } else if (json_value_is_true(jv)) { value = true; return true; } return false; } template inline static bool load_variable(json_value_s* jv, Int& value) { if (auto n = json_value_as_number(jv); n) { Int ret{}; std::from_chars(n->number, n->number + n->number_size, ret); value = ret; return true; } return false; } template inline static bool load_variable(json_value_s* jv, Float& value) { if (auto n = json_value_as_number(jv); n) { Float ret; std::from_chars(n->number, n->number + n->number_size, ret); value = ret; return true; } return false; } inline static void load_variable(json_value_s* jv, config_type::ColorBGR& value) { if (auto s = json_value_as_string(jv); s) { value = config_type::ColorBGR(std::string_view(s->string, s->string_size)); } else { value.valid = 0; } } inline static void load_variable(json_value_s* jv, std::optional& value) { if (auto ja = json_value_as_array(jv); ja) { if (ja->length >= 4) { auto itr = ja->start; std::array buf; for (size_t i = 0; i < 4; i++, itr = itr->next) { if (auto jn = json_value_as_number(itr->value); jn) { std::from_chars(jn->number, jn->number + jn->number_size, buf[i]); } else { value = std::nullopt; return; } } value.emplace(RECT{ .left = buf[0], .top = buf[1], .right = buf[2], .bottom = buf[3] }); } else { value = std::nullopt; } } else { value = std::nullopt; } } template inline static void load_variable(json_value_s* jv, std::optional>& value) { if (auto ja = json_value_as_array(jv); ja) { if (ja->length >= N) { auto itr = ja->start; std::array buf; for (size_t i = 0; i < N; i++, itr = itr->next) { if (auto jn = json_value_as_number(itr->value); jn) { std::from_chars(jn->number, jn->number + jn->number_size, buf[i]); } else { value = std::nullopt; return; } } value = buf; } else { value = std::nullopt; return; } } else { int buf; if (auto jn = json_value_as_number(jv); jn) { std::from_chars(jn->number, jn->number + jn->number_size, buf); } else { value = std::nullopt; return; } value.emplace(); auto& v = value.value(); for (size_t i = 0; i < N; i++) { v[i] = buf; } return; } } template inline static void load_variable(json_value_s* jv, T& value) { value.load(jv); } template inline static void load_variable(json_value_s* jv, std::optional& value) { T t; if (load_variable(jv, t)) { value.emplace(std::move(t)); } else { value = std::nullopt; } } }; ================================================ FILE: patch/cryptostring.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include #include #include #include /// /// バイナリに生の文字列を残さないためのクラス /// template class cryptostring { template struct KeyV {}; template<> struct KeyV { inline static constexpr char value = 0b00101101i8; }; template<> struct KeyV { inline static constexpr wchar_t value = 0b1001010110001100i16; }; template [[nodiscard]] constexpr static T bit_rotate_l(const T x, size_t a) { auto ux = std::bit_cast>(x); return std::bit_cast(std::rotl(ux, a)); } template [[nodiscard]] constexpr static T bit_rotate_r(const T x, size_t a) { auto ux = std::bit_cast>(x); return std::bit_cast(std::rotr(ux, a)); } std::array ary; bool decrypted = false; public: constexpr cryptostring(const CharT(&str)[N]) { for (size_t i = 0; i < N; i++) ary[i] = str[i] ^ bit_rotate_l(KeyV::value, (i * 3) % (CHAR_BIT * sizeof(CharT))); } [[nodiscard]] CharT* get() { if (!decrypted) [[unlikely]] { for (size_t i = 0; i < N; i++) ary[i] ^= bit_rotate_l(KeyV::value, (i * 3) % (CHAR_BIT * sizeof(CharT))); decrypted = true; } return ary.data(); } void re_encrypt() { if (decrypted) [[likely]] { for (size_t i = 0; i < N; i++) ary[i] ^= bit_rotate_l(KeyV::value, (i * 3) % (CHAR_BIT * sizeof(CharT))); decrypted = false; } } }; template inline constexpr cryptostring make_cryptostring(const CharT(&str)[N]) { return cryptostring(str); } inline cryptostring cstr_kernel32_dll("KERNEL32.DLL"); inline cryptostring cstr_user32_dll("USER32.DLL"); inline cryptostring cstr_EnumResourceLanguagesA("EnumResourceLanguagesA"); inline cryptostring cstr_LoadLibraryA("LoadLibraryA"); inline cryptostring cstr_LoadLibraryW("LoadLibraryW"); inline cryptostring cstr_MessageBoxA("MessageBoxA"); inline cryptostring cstr_gdi32_dll("GDI32.DLL"); inline cryptostring cstr_GetGlyphOutlineW("GetGlyphOutlineW"); inline cryptostring cstr_DeleteObject("DeleteObject"); inline cryptostring cstr_CreateFontIndirectW("CreateFontIndirectW"); inline cryptostring cstr_GetModuleHandleA("GetModuleHandleA"); inline cryptostring cstr_GetModuleHandleW("GetModuleHandleW"); inline cryptostring cstr_Module32First("Module32First"); inline cryptostring cstr_Module32FirstW("Module32FirstW"); inline cryptostring cstr_Module32Next("Module32Next"); inline cryptostring cstr_Module32NextW("Module32NextW"); ================================================ FILE: patch/debug_log.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include #include "util_others.hpp" inline class debug_log_t { private: std::mutex mtx; public: template void operator()(const T& v) { std::lock_guard lock(mtx); std::cout << v << std::endl; } template void operator()(Args... args) { std::lock_guard lock(mtx); format_to_os(std::cout, args...); std::endl(std::cout); } } debug_log; ================================================ FILE: patch/gate.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include class Gate { std::mutex mtx; std::condition_variable cond; bool flag; public: Gate() :mtx{}, cond{}, flag{} {} Gate(bool opened) :mtx{}, cond{}, flag{opened} {} void open() { { std::lock_guard lock(mtx); flag = true; } cond.notify_one(); } void wait() { std::unique_lock lock(mtx); cond.wait(lock, [this] { return flag; }); flag = false; } }; ================================================ FILE: patch/global.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include #include #include #include "global_minimum.hpp" namespace GLOBAL { inline HMODULE exedit_hmod; inline uint32_t& exedit_base = (uint32_t&)exedit_hmod; inline std::byte executable_memory[USN_PAGE_SIZE * 16]; inline std::byte* executable_memory_cursor = executable_memory; inline std::wstring patchaul_path; inline std::wstring patchaul_config_path; inline std::string patchaul_path_a; } ================================================ FILE: patch/global_minimum.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include #include namespace GLOBAL { inline HMODULE aviutl_hmod; inline uint32_t& aviutl_base = (uint32_t&)aviutl_hmod; inline HINSTANCE patchaul_hinst; inline void init_minimum(HINSTANCE patch_hmod) { GLOBAL::patchaul_hinst = patch_hmod; GLOBAL::aviutl_base = std::bit_cast(GetModuleHandleA(NULL)); } } ================================================ FILE: patch/hash.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include #include #include #include #include struct SHA256 { private: inline constexpr static uint32_t K[] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, }; inline constexpr static uint32_t H0[] = { 0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19 }; static uint32_t Sigma0(uint32_t x) { return std::rotr(x, 2) ^ std::rotr(x, 13) ^ std::rotr(x, 22); } static uint32_t Sigma1(uint32_t x) { return std::rotr(x, 6) ^ std::rotr(x, 11) ^ std::rotr(x, 25); } static uint32_t sigma0(uint32_t x) { return std::rotr(x, 7) ^ std::rotr(x, 18) ^ (x >> 3); } static uint32_t sigma1(uint32_t x) { return std::rotr(x, 17) ^ std::rotr(x, 19) ^ (x >> 10); } static uint32_t Ch(uint32_t x, uint32_t y, uint32_t z) { return (x & y) ^ (~x & z); } static uint32_t Maj(uint32_t x, uint32_t y, uint32_t z) { return (x & y) ^ (y & z) ^ (z & x); } public: std::byte data[32]; SHA256(std::string_view filename) { #if _DEBUG && 1 // 重いので std::fill(std::begin(data), std::end(data), std::byte{}); #else std::vector buf; { auto hFile = CreateFileA(filename.data(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) throw std::runtime_error("Failed to open file."); BOOST_SCOPE_EXIT_ALL(hFile) { CloseHandle(hFile); }; DWORD sizehigh; auto sizelow = GetFileSize(hFile, &sizehigh); buf.resize(sizelow); DWORD read; if (!ReadFile(hFile, buf.data(), sizelow, &read, nullptr)) throw std::runtime_error("Failed to read file."); } uint32_t H[8]; std::memcpy(H, H0, sizeof(H0)); auto process = [&](const byte* msg) { uint32_t W[64]; for (size_t t = 0; t < 16; t++) { W[t] = _byteswap_ulong(*reinterpret_cast(msg + t * 4)); } for (size_t t = 16; t < 64; t++) { W[t] = sigma1(W[t - 2]) + W[t - 7] + sigma0(W[t - 15]) + W[t - 16]; } auto a = H[0]; auto b = H[1]; auto c = H[2]; auto d = H[3]; auto e = H[4]; auto f = H[5]; auto g = H[6]; auto h = H[7]; for (size_t t = 0; t < 64; t++) { auto T1 = h + Sigma1(e) + Ch(e, f, g) + K[t] + W[t]; auto T2 = Sigma0(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; } H[0] += a; H[1] += b; H[2] += c; H[3] += d; H[4] += e; H[5] += f; H[6] += g; H[7] += h; }; auto buf_size_d64 = buf.size() / 64; auto buf_size_m64 = buf.size() % 64; for (size_t i = 0; i < buf_size_d64; i++) process(&buf[i * 64]); uint8_t last_msg[64]; std::memcpy(last_msg, buf.data() + buf_size_d64 * 64, buf_size_m64); last_msg[buf_size_m64] = 0x80; if (buf_size_m64 < 56) { std::memset(last_msg + buf_size_m64 + 1, 0, 58 - buf_size_m64); auto size = buf.size(); last_msg[59] = static_cast(size >> 29); last_msg[60] = static_cast(size >> 21); last_msg[61] = static_cast(size >> 13); last_msg[62] = static_cast(size >> 5); last_msg[63] = static_cast(size << 3); process(last_msg); } else { std::memset(last_msg + buf_size_m64 + 1, 0, 63 - buf_size_m64); process(last_msg); std::memset(last_msg, 0, 59); auto size = buf.size(); last_msg[59] = static_cast(size >> 29); last_msg[60] = static_cast(size >> 21); last_msg[61] = static_cast(size >> 13); last_msg[62] = static_cast(size >> 5); last_msg[63] = static_cast(size << 3); process(last_msg); } for (size_t i = 0; i < 8; i++) { *reinterpret_cast(data + i * 4) = _byteswap_ulong(H[i]); } #endif } template requires(sizeof...(T) == std::extent_v) constexpr SHA256(T&&... list) noexcept : data{ static_cast(std::forward(list))... } {} static std::optional make_opt(std::string_view filename) { try { return SHA256(filename); } catch (const std::runtime_error&) { return std::nullopt; } } std::string tostring() const { std::string ret; ret.reserve(64); static const char chs[] = "0123456789ABCDEF"; for (auto b : data) { ret.append(1, chs[(std::to_integer(b) >> 4) & 0xf]); ret.append(1, chs[std::to_integer(b) & 0xf]); } return ret; } }; inline bool operator==(const SHA256& a, const SHA256& b) { return std::equal(std::begin(a.data), std::end(a.data), std::begin(b.data)); } ================================================ FILE: patch/init.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "init.hpp" #include #include #include "cryptostring.hpp" #include "util_others.hpp" #include "util_resource.hpp" #include "config.hpp" void init_t::InitAtDllMain() { ExchangeFunction(GLOBAL::aviutl_hmod, cstr_kernel32_dll.get(), cstr_EnumResourceLanguagesA.get(), EnumResourceLanguagesA_Wrap); } void init_t::InitAtPatchLoaded() { { static const char aviutl_version_str[] = { '1','.','1','0','\0','\0','\0','\0' }; if (memcmp(reinterpret_cast(GLOBAL::aviutl_base + OFS::AviUtl::VersionString), aviutl_version_str, sizeof(aviutl_version_str)) != 0) { MessageBoxW(NULL, L"patch.aul requires AviUtl *1.10*.\nAviUtl version 1.10以外では動作しません.", L"patch.aul", MB_ICONEXCLAMATION); return; } } GLOBAL::patchaul_path = WinWrap::Module{ GLOBAL::patchaul_hinst }.getFileNameW(); GLOBAL::patchaul_path_a = WinWrap::Module{ GLOBAL::patchaul_hinst }.getFileNameA(); GLOBAL::patchaul_config_path = GLOBAL::patchaul_path + L".json"; //GLOBAL::config.load(GLOBAL::patchaul_config_path); config2.load(GLOBAL::patchaul_config_path); add_dll_ref.add_ref(); ModulesData::update(); { DWORD oldProtect; VirtualProtect(GLOBAL::executable_memory, sizeof(GLOBAL::executable_memory), PAGE_EXECUTE_READWRITE, &oldProtect); } InjectFunction_fastcall(GLOBAL::aviutl_base + OFS::AviUtl::InitAuf, InitAufBefore, 10); ExchangeFunction(GLOBAL::aviutl_hmod, cstr_kernel32_dll.get(), cstr_LoadLibraryA.get(), LoadLibraryAWrap); overwrite_resource(); #ifdef PATCH_SWITCH_SPLASH if (PATCH_SWITCHER_MEMBER(PATCH_SWITCH_SPLASH)) { patch::splash.init(); patch::splash.set_phase(L"patch.aulの準備中", L""); patch::splash.start(); } #endif #ifdef PATCH_SWITCH_CONSOLE patch::console.init(); #endif #ifdef PATCH_SWITCH_EXCEPTION_LOG patch::exception_log(); #endif #ifdef PATCH_SWITCH_SYSINFO_MODIFY patch::sysinfo_info_write(); #endif #ifdef PATCH_SWITCH_ACCESS_KEY patch::access_key.init(); #endif #ifdef PATCH_SWITCH_COLORPALETTE_CACHE patch::colorpalette_cache.init(); #endif #ifdef PATCH_SWITCH_FILEINFO patch::fileinfo.init(); #endif } void init_t::InitAtExeditLoad() { mywindow.init(); #ifdef PATCH_SWITCH_THEME_CC patch::theme_cc.init(); #endif #ifdef PATCH_SWITCH_AUP_SCENE_SETTING patch::aup_scene_setting.init(); #endif #ifdef PATCH_SWITCH_TRA_AVIUTL_FILTER patch::tra_aviutlfilter.init(); #endif #ifdef PATCH_SWITCH_TRA_CHANGE_DRAWFILTER patch::tra_change_drawfilter.init(); #endif #ifdef PATCH_SWITCH_TRA_SPECIFIED_SPEED patch::tra_specified_speed.init(); #endif #ifdef PATCH_SWITCH_SETTING_NEW_PROJECT patch::setting_new_project.init(); #endif #ifdef PATCH_SWITCH_AUP_LAYER_SETTING patch::aup_layer_setting.init(); #endif #ifdef PATCH_SWITCH_EXO_AVIUTL_FILTER patch::exo_aviutlfilter.init(); #endif #ifdef PATCH_SWITCH_EXO_SCENEIDX patch::exo_sceneidx.init(); #endif #ifdef PATCH_SWITCH_EXO_TRACKPARAM patch::exo_trackparam.init(); #endif #ifdef PATCH_SWITCH_EXO_TRACK_MINUSVAL patch::exo_trackminusval.init(); #endif #ifdef PATCH_SWITCH_EXO_MIDPT_AND_TRA patch::exo_midpt_and_tra.init(); #endif #ifdef PATCH_SWITCH_EXO_SPECIALCOLORCONV patch::exo_specialcolorconv.init(); #endif #ifdef PATCH_SWITCH_EXO_FOLD_GUI patch::exo_fold_gui.init(); #endif #ifdef PATCH_SWITCH_CONSOLE patch::console.init_at_exedit_init(); #endif #ifdef PATCH_SWITCH_TEXT_OP_SIZE patch::text_op_size.init(); #endif #ifdef PATCH_SWITCH_IGNORE_MEDIA_PARAM_RESET patch::ignore_media_param_reset.init(); #endif #ifdef PATCH_SWITCH_SCROLL_OBJDLG patch::scroll_objdlg.init(); #endif #ifdef PATCH_SWITCH_SUSIE_LOAD patch::susie_load.init(); #endif #ifdef PATCH_SWITCH_HELPFUL_MSGBOX patch::helpful_msgbox.init(); #endif #ifdef PATCH_SWITCH_FAILED_SJIS_MSGBOX patch::failed_sjis_msgbox.init(); #endif #ifdef PATCH_SWITCH_FAILED_LONGER_PATH patch::failed_longer_path.init(); #endif #ifdef PATCH_SWITCH_FAILED_FILE_DROP patch::failed_file_drop.init(); #endif #ifdef PATCH_SWITCH_OBJ_COLORCORRECTION patch::ColorCorrection.init(); #endif #ifdef PATCH_SWITCH_OBJ_GLOW patch::Glow.init(); #endif #ifdef PATCH_SWITCH_OBJ_LENSBLUR patch::LensBlur.init(); #endif #ifdef PATCH_SWITCH_OBJ_NOISE patch::Noise.init(); #endif #ifdef PATCH_SWITCH_OBJ_SPECIALCOLORCONV patch::obj_specialcolorconv.init(); #endif #ifdef PATCH_SWITCH_SETTINGDIALOG_EXCOLORCONFIG patch::excolorconfig.init(); #endif #ifdef PATCH_SWITCH_RCLICKMENU_SPLIT patch::rclickmenu_split.init(); #endif #ifdef PATCH_SWITCH_RCLICKMENU_DELETE patch::rclickmenu_delete.init(); #endif #ifdef PATCH_SWITCH_BLEND patch::blend.init(); #endif #ifdef PATCH_SWITCH_ADD_EXTENSION patch::add_extension.init(); #endif #ifdef PATCH_SWITCH_DIALOG_NEW_FILE patch::dialog_new_file.init(); #endif #ifdef PATCH_SWITCH_PLAYBACK_SPEED patch::playback_speed.init(); #endif patch::setting_dialog(); #ifdef PATCH_SWITCH_FAST patch::fast::fast.init(); if (patch::fast::fast.is_enabled_i()) { #ifdef PATCH_SWITCH_FAST_GETPUTPIXELDATA patch::fast::getputpixeldata(); #endif #ifdef PATCH_SWITCH_FAST_SETTINGDIALOG patch::fast_setting_dialog.init(); #endif #ifdef PATCH_SWITCH_FAST_EXEDITWINDOW patch::fast_exeditwindow.init(); #endif #ifdef PATCH_SWITCH_FAST_TEXT patch::fast::text.init(); #endif #ifdef PATCH_SWITCH_FAST_CREATE_FIGURE patch::fast::create_figure.init(); #endif #ifdef PATCH_SWITCH_FAST_BORDER patch::fast::Border.init(); #endif #ifdef PATCH_SWITCH_FAST_GLOW patch::fast::Glow.init(); #endif #ifdef PATCH_SWITCH_CL if (patch::fast::cl.init()) { if (patch::fast::cl.is_enabled_i()) { #ifdef PATCH_SWITCH_FAST_POLORTRANSFORM patch::fast::PolorTransform.init(); #endif #ifdef PATCH_SWITCH_FAST_DISPLACEMENTMAP patch::fast::DisplacementMap.init(); #endif #ifdef PATCH_SWITCH_FAST_RADIATIONALBLUR patch::fast::RadiationalBlur.init(); #endif #ifdef PATCH_SWITCH_FAST_FLASH patch::fast::Flash.init(); #endif #ifdef PATCH_SWITCH_FAST_DIRECTIONALBLUR patch::fast::DirectionalBlur.init(); #endif #ifdef PATCH_SWITCH_FAST_LENSBLUR patch::fast::LensBlur.init(); #endif } } else { patch_resource_message_w(PATCH_RS_PATCH_CANT_USE_CL, MB_TASKMODAL | MB_ICONEXCLAMATION); } #endif } #endif #ifdef PATCH_SWITCH_UNDO patch::undo.init(); if (patch::undo.is_enabled_i()) { #ifdef PATCH_SWITCH_UNDO_REDO patch::redo.init(); #endif } #endif //GLOBAL::config.store(GLOBAL::patchaul_config_path); config2.store(GLOBAL::patchaul_config_path); } void init_t::InitAufBefore() { patch::aviutl_wndproc_override.go(); } BOOL WINAPI init_t::EnumResourceLanguagesA_Wrap(HMODULE hModule, LPCSTR lpType, LPCSTR lpName, ENUMRESLANGPROCA lpEnumFunc, LONG_PTR lParam) { ExchangeFunction((HMODULE)GLOBAL::aviutl_base, cstr_kernel32_dll.get(), cstr_EnumResourceLanguagesA.get(), EnumResourceLanguagesA); InitAtPatchLoaded(); return FALSE; } HMODULE WINAPI init_t::LoadLibraryAWrap(LPCSTR lpLibFileName) { HMODULE ret = LoadLibraryA(lpLibFileName); if (ret == NULL)return NULL; LPCSTR filename = PathFindFileNameA(lpLibFileName); if (lstrcmpiA(filename, "exedit.auf") == 0) { GLOBAL::exedit_hmod = ret; auto filters = reinterpret_cast(GetProcAddress(ret, AviUtl::GetFilterTableListName))(); if (strcmp(filters[0]->information, "拡張編集(exedit) version 0.92 by KENくん") != 0) { MessageBoxW(NULL, L"patch.aul requires Exedit version *0.92*.\n拡張編集 version 0.92以外では動作しません.", L"patch.aul", MB_ICONEXCLAMATION); return ret; } original_func_init = std::exchange(filters[0]->func_init, func_initWrap); original_func_WndProc = std::exchange(filters[0]->func_WndProc, func_WndProcWrap); #ifdef _DEBUG original_func_proc = std::exchange(filters[0]->func_proc, func_procWrap); #endif InitAtExeditLoad(); } #ifdef PATCH_SWITCH_CANCEL_BOOST_CONFLICT else if (lstrcmpiA(filename, "Boost.auf") == 0) { if (auto ptr = search_import(ret, cstr_kernel32_dll.get(), cstr_GetModuleHandleA.get())) { OverWriteOnProtectHelper(ptr, 4).store_i32(0, &init_t::Boost_GetModuleHandleA_Wrap); } if (auto ptr = search_import(ret, cstr_kernel32_dll.get(), cstr_GetModuleHandleW.get())) { OverWriteOnProtectHelper(ptr, 4).store_i32(0, &init_t::Boost_GetModuleHandleW_Wrap); } if (auto ptr = search_import(ret, cstr_kernel32_dll.get(), cstr_LoadLibraryA.get())) { OverWriteOnProtectHelper(ptr, 4).store_i32(0, &init_t::Boost_LoadLibraryA_Wrap); } if (auto ptr = search_import(ret, cstr_kernel32_dll.get(), cstr_LoadLibraryW.get())) { OverWriteOnProtectHelper(ptr, 4).store_i32(0, &init_t::Boost_LoadLibraryW_Wrap); } if (auto ptr = search_import(ret, cstr_kernel32_dll.get(), cstr_Module32First.get())) { OverWriteOnProtectHelper(ptr, 4).store_i32(0, &init_t::Boost_Module32First_Wrap); } if (auto ptr = search_import(ret, cstr_kernel32_dll.get(), cstr_Module32FirstW.get())) { OverWriteOnProtectHelper(ptr, 4).store_i32(0, &init_t::Boost_Module32FirstW_Wrap); } if (auto ptr = search_import(ret, cstr_kernel32_dll.get(), cstr_Module32Next.get())) { OverWriteOnProtectHelper(ptr, 4).store_i32(0, &init_t::Boost_Module32Next_Wrap); } if (auto ptr = search_import(ret, cstr_kernel32_dll.get(), cstr_Module32NextW.get())) { OverWriteOnProtectHelper(ptr, 4).store_i32(0, &init_t::Boost_Module32NextW_Wrap); } } #endif #ifdef PATCH_SWITCH_WARNING_OLD_LSW else if (lstrcmpiA(filename, "lwcolor.auc") == 0) { static const SHA256 r940_hash(0xc7, 0xe2, 0x51, 0xde, 0xd2, 0xf8, 0x21, 0xcb, 0x1b, 0xc6, 0xb1, 0x9a, 0x66, 0x43, 0xd3, 0x0d, 0xa4, 0xeb, 0xd6, 0x97, 0x1e, 0x34, 0x1a, 0xb2, 0x11, 0xd9, 0x41, 0x1d, 0xcc, 0xbf, 0x9a, 0x18); SHA256 hash(lpLibFileName); if (hash == r940_hash) { auto ret = patch_resource_message_w(PATCH_RS_PATCH_OLD_LSW, MB_ICONEXCLAMATION | MB_YESNO); if (ret == IDYES) { static cryptostring lsw_url(L"https://scrapbox.io/aviutl/L-SMASH_Works"); web_confirm(lsw_url.get()); } } } #endif else { static std::set list = { "bakusoku.auf", "eclipse_fast.auf", "redo.auf", }; std::string check = filename; std::transform(check.begin(), check.end(), check.begin(), [](auto c) { return std::tolower(c); }); if (list.find(check) != list.end()) { FreeLibrary(ret); auto ret = patch_resource_message_w(PATCH_RS_PATCH_CONFLICT_PLUGIN, MB_TASKMODAL | MB_ICONINFORMATION | MB_YESNO, string_convert_A2W(filename)); if (ret) { switch (*ret) { case IDYES: DeleteFileA(lpLibFileName); } } return NULL; } } return ret; } BOOL __cdecl init_t::func_WndProcWrap(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam, AviUtl::EditHandle* editp, AviUtl::FilterPlugin* fp) { switch (message) { #ifdef PATCH_SWITCH_EXEDITWINDOW_SIZING case WM_SIZING: if (auto ret = patch::exeditwindow_sizing.wndproc(wparam, lparam) == -1) break; else return ret; #endif case AviUtl::FilterPlugin::WindowMessage::Command: #ifdef PATCH_SWITCH_UNDO_REDO if (wparam == PATCH_EXEDITMENU_REDO) { if (patch::redo.is_enabled_i()) { patch::redo.run_redo(); } return TRUE; } #endif } return original_func_WndProc(hwnd, message, wparam, lparam, editp, fp); } BOOL __cdecl init_t::func_initWrap(AviUtl::FilterPlugin* fp) { if (original_func_init(fp) == FALSE) return FALSE; #ifdef PATCH_SWITCH_UNDO_REDO fp->exfunc->add_menu_item(fp, "やり直す", fp->hwnd, PATCH_EXEDITMENU_REDO, 'Y', AviUtl::ExFunc::AddMenuItemFlag::Ctrl); #endif #ifdef PATCH_SWITCH_LUA patch::lua.init(); #ifdef PATCH_SWITCH_LUA_RAND patch::lua_rand.init(); #endif #ifdef PATCH_SWITCH_LUA_RANDEX patch::lua_randex.init(); #endif #ifdef PATCH_SWITCH_LUA_GETVALUE patch::lua_getvalueex.init(); #endif #endif return TRUE; } BOOL __cdecl init_t::func_procWrap(AviUtl::FilterPlugin* fp, AviUtl::FilterProcInfo* fpip) { //std::cout << " = = = = = = " << std::endl; #ifdef PATCH_SWITCH_ALPHA_BG patch::alpha_bg.func_proc(fp, fpip); #endif return original_func_proc(fp, fpip); } #ifdef PATCH_SWITCH_CANCEL_BOOST_CONFLICT HMODULE WINAPI init_t::Boost_GetModuleHandleA_Wrap(LPCSTR lpModuleName) { auto filename = PathFindFileNameA(lpModuleName); if (lstrcmpiA(filename, "patch.aul") == 0) { return NULL; } return GetModuleHandleA(lpModuleName); } HMODULE WINAPI init_t::Boost_GetModuleHandleW_Wrap(LPCWSTR lpModuleName) { auto filename = PathFindFileNameW(lpModuleName); if (lstrcmpiW(filename, L"patch.aul") == 0) { return NULL; } return GetModuleHandleW(lpModuleName); } HMODULE WINAPI init_t::Boost_LoadLibraryA_Wrap(LPCSTR lpLibFileName) { auto filename = PathFindFileNameA(lpLibFileName); if (lstrcmpiA(filename, "patch.aul") == 0) { return NULL; } return LoadLibraryA(lpLibFileName); } HMODULE WINAPI init_t::Boost_LoadLibraryW_Wrap(LPCWSTR lpLibFileName) { auto filename = PathFindFileNameW(lpLibFileName); if (lstrcmpiW(filename, L"patch.aul") == 0) { return NULL; } return LoadLibraryW(lpLibFileName); } BOOL WINAPI init_t::Boost_Module32First_Wrap(HANDLE hSnapshot, LPMODULEENTRY32 lpme) { auto ret = Module32First(hSnapshot, lpme); if (ret && lstrcmpiA(lpme->szModule, "patch.aul") == 0) { return Module32Next(hSnapshot, lpme); } return ret; } BOOL WINAPI init_t::Boost_Module32FirstW_Wrap(HANDLE hSnapshot, LPMODULEENTRY32W lpme) { auto ret = Module32FirstW(hSnapshot, lpme); if (ret && lstrcmpiW(lpme->szModule, L"patch.aul") == 0) { return Module32NextW(hSnapshot, lpme); } return ret; } BOOL WINAPI init_t::Boost_Module32Next_Wrap(HANDLE hSnapshot, LPMODULEENTRY32 lpme) { auto ret = Module32Next(hSnapshot, lpme); if (ret && lstrcmpiA(lpme->szModule, "patch.aul") == 0) { return Module32Next(hSnapshot, lpme); } return ret; } BOOL WINAPI init_t::Boost_Module32NextW_Wrap(HANDLE hSnapshot, LPMODULEENTRY32W lpme) { auto ret = Module32NextW(hSnapshot, lpme); if (ret && lstrcmpiW(lpme->szModule, L"patch.aul") == 0) { return Module32NextW(hSnapshot, lpme); } return ret; } #endif ================================================ FILE: patch/init.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include "cryptostring.hpp" #include "add_dll_ref.hpp" #include "util.hpp" #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "patch.hpp" #include "debug_log.hpp" #include "overwrite_resource.hpp" #include "patch_exception_log.hpp" #include "mywindow.hpp" inline class init_t { public: inline static BOOL(__cdecl* original_func_WndProc)(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam, AviUtl::EditHandle* editp, AviUtl::FilterPlugin* fp); inline static BOOL(__cdecl* original_func_init)(AviUtl::FilterPlugin* fp); inline static BOOL(__cdecl* original_func_proc)(AviUtl::FilterPlugin* fp, AviUtl::FilterProcInfo* fpip); static BOOL __cdecl func_WndProcWrap(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam, AviUtl::EditHandle* editp, AviUtl::FilterPlugin* fp); static BOOL __cdecl func_initWrap(AviUtl::FilterPlugin* fp); static BOOL __cdecl func_procWrap(AviUtl::FilterPlugin* fp, AviUtl::FilterProcInfo* fpip); static BOOL WINAPI EnumResourceLanguagesA_Wrap(HMODULE hModule, LPCSTR lpType, LPCSTR lpName, ENUMRESLANGPROCA lpEnumFunc, LONG_PTR lParam); static HMODULE WINAPI LoadLibraryAWrap(LPCSTR lpLibFileName); #ifdef PATCH_SWITCH_CANCEL_BOOST_CONFLICT static HMODULE WINAPI Boost_GetModuleHandleA_Wrap(LPCSTR lpModuleName); static HMODULE WINAPI Boost_GetModuleHandleW_Wrap(LPCWSTR lpModuleName); static HMODULE WINAPI Boost_LoadLibraryA_Wrap(LPCSTR lpLibFileName); static HMODULE WINAPI Boost_LoadLibraryW_Wrap(LPCWSTR lpLibFileName); static BOOL WINAPI Boost_Module32First_Wrap(HANDLE hSnapshot, LPMODULEENTRY32 lpme); static BOOL WINAPI Boost_Module32FirstW_Wrap(HANDLE hSnapshot, LPMODULEENTRY32W lpme); static BOOL WINAPI Boost_Module32Next_Wrap(HANDLE hSnapshot, LPMODULEENTRY32 lpme); static BOOL WINAPI Boost_Module32NextW_Wrap(HANDLE hSnapshot, LPMODULEENTRY32W lpme); #endif // DllMain呼び出しのタイミングでやる処理 // できるだけ少なくしたい static void InitAtDllMain(); // LoadLibrary("patch.aul")直後にやる処理 // EnumResourceLanguagesAの乗っ取りで実現 // EnumResourceLanguagesAが失敗したことにして,patch.aulは正しい言語拡張リソースではないことにする static void InitAtPatchLoaded(); // exedit.aufのLoadLibrary直後にやる処理 // 拡張編集へのインジェクションはここでやる static void InitAtExeditLoad(); // フィルタプラグインの読み込みを開始するタイミングでやる処理 static void InitAufBefore(); } init; ================================================ FILE: patch/json.h ================================================ /* The latest version of this library is available on GitHub; https://github.com/sheredom/json.h. */ /* This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to . */ #ifndef SHEREDOM_JSON_H_INCLUDED #define SHEREDOM_JSON_H_INCLUDED #if defined(_MSC_VER) #pragma warning(push) /* disable warning: no function prototype given: converting '()' to '(void)' */ #pragma warning(disable : 4255) /* disable warning: '__cplusplus' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ #pragma warning(disable : 4668) /* disable warning: 'bytes padding added after construct' */ #pragma warning(disable : 4820) #endif #include #include #if defined(_MSC_VER) #define json_weak __inline #elif defined(__clang__) || defined(__GNUC__) #define json_weak __attribute__((weak)) #else #error Non clang, non gcc, non MSVC compiler found! #endif #ifdef __cplusplus extern "C" { #endif struct json_value_s; struct json_parse_result_s; enum json_parse_flags_e { json_parse_flags_default = 0, /* allow trailing commas in objects and arrays. For example, both [true,] and {"a" : null,} would be allowed with this option on. */ json_parse_flags_allow_trailing_comma = 0x1, /* allow unquoted keys for objects. For example, {a : null} would be allowed with this option on. */ json_parse_flags_allow_unquoted_keys = 0x2, /* allow a global unbracketed object. For example, a : null, b : true, c : {} would be allowed with this option on. */ json_parse_flags_allow_global_object = 0x4, /* allow objects to use '=' instead of ':' between key/value pairs. For example, a = null, b : true would be allowed with this option on. */ json_parse_flags_allow_equals_in_object = 0x8, /* allow that objects don't have to have comma separators between key/value pairs. */ json_parse_flags_allow_no_commas = 0x10, /* allow c-style comments (either variants) to be ignored in the input JSON file. */ json_parse_flags_allow_c_style_comments = 0x20, /* deprecated flag, unused. */ json_parse_flags_deprecated = 0x40, /* record location information for each value. */ json_parse_flags_allow_location_information = 0x80, /* allow strings to be 'single quoted'. */ json_parse_flags_allow_single_quoted_strings = 0x100, /* allow numbers to be hexadecimal. */ json_parse_flags_allow_hexadecimal_numbers = 0x200, /* allow numbers like +123 to be parsed. */ json_parse_flags_allow_leading_plus_sign = 0x400, /* allow numbers like .0123 or 123. to be parsed. */ json_parse_flags_allow_leading_or_trailing_decimal_point = 0x800, /* allow Infinity, -Infinity, NaN, -NaN. */ json_parse_flags_allow_inf_and_nan = 0x1000, /* allow multi line string values. */ json_parse_flags_allow_multi_line_strings = 0x2000, /* allow simplified JSON to be parsed. Simplified JSON is an enabling of a set of other parsing options. */ json_parse_flags_allow_simplified_json = (json_parse_flags_allow_trailing_comma | json_parse_flags_allow_unquoted_keys | json_parse_flags_allow_global_object | json_parse_flags_allow_equals_in_object | json_parse_flags_allow_no_commas), /* allow JSON5 to be parsed. JSON5 is an enabling of a set of other parsing options. */ json_parse_flags_allow_json5 = (json_parse_flags_allow_trailing_comma | json_parse_flags_allow_unquoted_keys | json_parse_flags_allow_c_style_comments | json_parse_flags_allow_single_quoted_strings | json_parse_flags_allow_hexadecimal_numbers | json_parse_flags_allow_leading_plus_sign | json_parse_flags_allow_leading_or_trailing_decimal_point | json_parse_flags_allow_inf_and_nan | json_parse_flags_allow_multi_line_strings) }; /* Parse a JSON text file, returning a pointer to the root of the JSON * structure. json_parse performs 1 call to malloc for the entire encoding. * Returns 0 if an error occurred (malformed JSON input, or malloc failed). */ json_weak struct json_value_s *json_parse(const void *src, size_t src_size); /* Parse a JSON text file, returning a pointer to the root of the JSON * structure. json_parse performs 1 call to alloc_func_ptr for the entire * encoding. Returns 0 if an error occurred (malformed JSON input, or malloc * failed). If an error occurred, the result struct (if not NULL) will explain * the type of error, and the location in the input it occurred. If * alloc_func_ptr is null then malloc is used. */ json_weak struct json_value_s * json_parse_ex(const void *src, size_t src_size, size_t flags_bitset, void *(*alloc_func_ptr)(void *, size_t), void *user_data, struct json_parse_result_s *result); /* Extracts a value and all the data that makes it up into a newly created * value. json_extract_value performs 1 call to malloc for the entire encoding. */ json_weak struct json_value_s * json_extract_value(const struct json_value_s *value); /* Extracts a value and all the data that makes it up into a newly created * value. json_extract_value performs 1 call to alloc_func_ptr for the entire * encoding. If alloc_func_ptr is null then malloc is used. */ json_weak struct json_value_s * json_extract_value_ex(const struct json_value_s *value, void *(*alloc_func_ptr)(void *, size_t), void *user_data); /* Write out a minified JSON utf-8 string. This string is an encoding of the * minimal string characters required to still encode the same data. * json_write_minified performs 1 call to malloc for the entire encoding. Return * 0 if an error occurred (malformed JSON input, or malloc failed). The out_size * parameter is optional as the utf-8 string is null terminated. */ json_weak void *json_write_minified(const struct json_value_s *value, size_t *out_size); /* Write out a pretty JSON utf-8 string. This string is encoded such that the * resultant JSON is pretty in that it is easily human readable. The indent and * newline parameters allow a user to specify what kind of indentation and * newline they want (two spaces / three spaces / tabs? \r, \n, \r\n ?). Both * indent and newline can be NULL, indent defaults to two spaces (" "), and * newline defaults to linux newlines ('\n' as the newline character). * json_write_pretty performs 1 call to malloc for the entire encoding. Return 0 * if an error occurred (malformed JSON input, or malloc failed). The out_size * parameter is optional as the utf-8 string is null terminated. */ json_weak void *json_write_pretty(const struct json_value_s *value, const char *indent, const char *newline, size_t *out_size); /* Reinterpret a JSON value as a string. Returns null is the value was not a * string. */ json_weak struct json_string_s * json_value_as_string(struct json_value_s *const value); /* Reinterpret a JSON value as a number. Returns null is the value was not a * number. */ json_weak struct json_number_s * json_value_as_number(struct json_value_s *const value); /* Reinterpret a JSON value as an object. Returns null is the value was not an * object. */ json_weak struct json_object_s * json_value_as_object(struct json_value_s *const value); /* Reinterpret a JSON value as an array. Returns null is the value was not an * array. */ json_weak struct json_array_s * json_value_as_array(struct json_value_s *const value); /* Whether the value is true. */ json_weak int json_value_is_true(const struct json_value_s *const value); /* Whether the value is false. */ json_weak int json_value_is_false(const struct json_value_s *const value); /* Whether the value is null. */ json_weak int json_value_is_null(const struct json_value_s *const value); /* The various types JSON values can be. Used to identify what a value is. */ enum json_type_e { json_type_string, json_type_number, json_type_object, json_type_array, json_type_true, json_type_false, json_type_null }; /* A JSON string value. */ struct json_string_s { /* utf-8 string */ const char *string; /* The size (in bytes) of the string */ size_t string_size; }; /* A JSON string value (extended). */ struct json_string_ex_s { /* The JSON string this extends. */ struct json_string_s string; /* The character offset for the value in the JSON input. */ size_t offset; /* The line number for the value in the JSON input. */ size_t line_no; /* The row number for the value in the JSON input, in bytes. */ size_t row_no; }; /* A JSON number value. */ struct json_number_s { /* ASCII string containing representation of the number. */ const char *number; /* the size (in bytes) of the number. */ size_t number_size; }; /* an element of a JSON object. */ struct json_object_element_s { /* the name of this element. */ struct json_string_s *name; /* the value of this element. */ struct json_value_s *value; /* the next object element (can be NULL if the last element in the object). */ struct json_object_element_s *next; }; /* a JSON object value. */ struct json_object_s { /* a linked list of the elements in the object. */ struct json_object_element_s *start; /* the number of elements in the object. */ size_t length; }; /* an element of a JSON array. */ struct json_array_element_s { /* the value of this element. */ struct json_value_s *value; /* the next array element (can be NULL if the last element in the array). */ struct json_array_element_s *next; }; /* a JSON array value. */ struct json_array_s { /* a linked list of the elements in the array. */ struct json_array_element_s *start; /* the number of elements in the array. */ size_t length; }; /* a JSON value. */ struct json_value_s { /* a pointer to either a json_string_s, json_number_s, json_object_s, or. */ /* json_array_s. Should be cast to the appropriate struct type based on what. */ /* the type of this value is. */ void *payload; /* must be one of json_type_e. If type is json_type_true, json_type_false, or. */ /* json_type_null, payload will be NULL. */ size_t type; }; /* a JSON value (extended). */ struct json_value_ex_s { /* the JSON value this extends. */ struct json_value_s value; /* the character offset for the value in the JSON input. */ size_t offset; /* the line number for the value in the JSON input. */ size_t line_no; /* the row number for the value in the JSON input, in bytes. */ size_t row_no; }; /* a parsing error code. */ enum json_parse_error_e { /* no error occurred (huzzah!). */ json_parse_error_none = 0, /* expected either a comma or a closing '}' or ']' to close an object or. */ /* array! */ json_parse_error_expected_comma_or_closing_bracket, /* colon separating name/value pair was missing! */ json_parse_error_expected_colon, /* expected string to begin with '"'! */ json_parse_error_expected_opening_quote, /* invalid escaped sequence in string! */ json_parse_error_invalid_string_escape_sequence, /* invalid number format! */ json_parse_error_invalid_number_format, /* invalid value! */ json_parse_error_invalid_value, /* reached end of buffer before object/array was complete! */ json_parse_error_premature_end_of_buffer, /* string was malformed! */ json_parse_error_invalid_string, /* a call to malloc, or a user provider allocator, failed. */ json_parse_error_allocator_failed, /* the JSON input had unexpected trailing characters that weren't part of the. */ /* JSON value. */ json_parse_error_unexpected_trailing_characters, /* catch-all error for everything else that exploded (real bad chi!). */ json_parse_error_unknown }; /* error report from json_parse_ex(). */ struct json_parse_result_s { /* the error code (one of json_parse_error_e). */ size_t error; /* the character offset for the error in the JSON input. */ size_t error_offset; /* the line number for the error in the JSON input. */ size_t error_line_no; /* the row number for the error, in bytes. */ size_t error_row_no; }; #ifdef __cplusplus } /* extern "C". */ #endif #include #if defined(_MSC_VER) #pragma warning(pop) #endif #if defined(_MSC_VER) && (_MSC_VER < 1920) #define json_uintmax_t unsigned __int64 #else #include #define json_uintmax_t uintmax_t #endif #if defined(_MSC_VER) #define json_strtoumax _strtoui64 #else #define json_strtoumax strtoumax #endif #if defined(__cplusplus) && (__cplusplus >= 201103L) #define json_null nullptr #else #define json_null 0 #endif #if defined(__clang__) #pragma clang diagnostic push /* we do one big allocation via malloc, then cast aligned slices of this for. */ /* our structures - we don't have a way to tell the compiler we know what we. */ /* are doing, so disable the warning instead! */ #pragma clang diagnostic ignored "-Wcast-align" /* We use C style casts everywhere. */ #pragma clang diagnostic ignored "-Wold-style-cast" /* We need long long for strtoull. */ #pragma clang diagnostic ignored "-Wc++11-long-long" /* Who cares if nullptr doesn't work with C++98, we don't use it there! */ #pragma clang diagnostic ignored "-Wc++98-compat" #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" #elif defined(_MSC_VER) #pragma warning(push) /* disable 'function selected for inline expansion' warning. */ #pragma warning(disable : 4711) /* disable '#pragma warning: there is no warning number' warning. */ #pragma warning(disable : 4619) /* disable 'warning number not a valid compiler warning' warning. */ #pragma warning(disable : 4616) /* disable 'Compiler will insert Spectre mitigation for memory load if * /Qspectre. */ /* switch specified' warning. */ #pragma warning(disable : 5045) #endif struct json_parse_state_s { const char *src; size_t size; size_t offset; size_t flags_bitset; char *data; char *dom; size_t dom_size; size_t data_size; size_t line_no; /* line counter for error reporting. */ size_t line_offset; /* (offset-line_offset) is the character number (in bytes). */ size_t error; }; json_weak int json_hexadecimal_digit(const char c); int json_hexadecimal_digit(const char c) { if ('0' <= c && c <= '9') { return c - '0'; } if ('a' <= c && c <= 'f') { return c - 'a' + 10; } if ('A' <= c && c <= 'F') { return c - 'A' + 10; } return -1; } json_weak int json_hexadecimal_value(const char *c, const unsigned long size, unsigned long *result); int json_hexadecimal_value(const char *c, const unsigned long size, unsigned long *result) { const char *p; int digit; if (size > sizeof(unsigned long) * 2) { return 0; } *result = 0; for (p = c; (unsigned long)(p - c) < size; ++p) { *result <<= 4; digit = json_hexadecimal_digit(*p); if (digit < 0 || digit > 15) { return 0; } *result |= (unsigned char)digit; } return 1; } json_weak int json_skip_whitespace(struct json_parse_state_s *state); int json_skip_whitespace(struct json_parse_state_s *state) { size_t offset = state->offset; const size_t size = state->size; const char *const src = state->src; /* the only valid whitespace according to ECMA-404 is ' ', '\n', '\r' and * '\t'. */ switch (src[offset]) { default: return 0; case ' ': case '\r': case '\t': case '\n': break; } do { switch (src[offset]) { default: /* Update offset. */ state->offset = offset; return 1; case ' ': case '\r': case '\t': break; case '\n': state->line_no++; state->line_offset = offset; break; } offset++; } while (offset < size); /* Update offset. */ state->offset = offset; return 1; } json_weak int json_skip_c_style_comments(struct json_parse_state_s *state); int json_skip_c_style_comments(struct json_parse_state_s *state) { /* do we have a comment?. */ if ('/' == state->src[state->offset]) { /* skip '/'. */ state->offset++; if ('/' == state->src[state->offset]) { /* we had a comment of the form //. */ /* skip second '/'. */ state->offset++; while (state->offset < state->size) { switch (state->src[state->offset]) { default: /* skip the character in the comment. */ state->offset++; break; case '\n': /* if we have a newline, our comment has ended! Skip the newline. */ state->offset++; /* we entered a newline, so move our line info forward. */ state->line_no++; state->line_offset = state->offset; return 1; } } /* we reached the end of the JSON file! */ return 1; } else if ('*' == state->src[state->offset]) { /* we had a comment in the C-style long form. */ /* skip '*'. */ state->offset++; while (state->offset + 1 < state->size) { if (('*' == state->src[state->offset]) && ('/' == state->src[state->offset + 1])) { /* we reached the end of our comment! */ state->offset += 2; return 1; } else if ('\n' == state->src[state->offset]) { /* we entered a newline, so move our line info forward. */ state->line_no++; state->line_offset = state->offset; } /* skip character within comment. */ state->offset++; } /* Comment wasn't ended correctly which is a failure. */ return 1; } } /* we didn't have any comment, which is ok too! */ return 0; } json_weak int json_skip_all_skippables(struct json_parse_state_s *state); int json_skip_all_skippables(struct json_parse_state_s *state) { /* skip all whitespace and other skippables until there are none left. note * that the previous version suffered from read past errors should. the * stream end on json_skip_c_style_comments eg. '{"a" ' with comments flag. */ int did_consume = 0; const size_t size = state->size; if (json_parse_flags_allow_c_style_comments & state->flags_bitset) { do { if (state->offset == size) { state->error = json_parse_error_premature_end_of_buffer; return 1; } did_consume = json_skip_whitespace(state); /* This should really be checked on access, not in front of every call. */ if (state->offset == size) { state->error = json_parse_error_premature_end_of_buffer; return 1; } did_consume |= json_skip_c_style_comments(state); } while (0 != did_consume); } else { do { if (state->offset == size) { state->error = json_parse_error_premature_end_of_buffer; return 1; } did_consume = json_skip_whitespace(state); } while (0 != did_consume); } if (state->offset == size) { state->error = json_parse_error_premature_end_of_buffer; return 1; } return 0; } json_weak int json_get_value_size(struct json_parse_state_s *state, int is_global_object); json_weak int json_get_string_size(struct json_parse_state_s *state, size_t is_key); int json_get_string_size(struct json_parse_state_s *state, size_t is_key) { size_t offset = state->offset; const size_t size = state->size; size_t data_size = 0; const char *const src = state->src; const int is_single_quote = '\'' == src[offset]; const char quote_to_use = is_single_quote ? '\'' : '"'; const size_t flags_bitset = state->flags_bitset; unsigned long codepoint; unsigned long high_surrogate = 0; if ((json_parse_flags_allow_location_information & flags_bitset) != 0 && is_key != 0) { state->dom_size += sizeof(struct json_string_ex_s); } else { state->dom_size += sizeof(struct json_string_s); } if ('"' != src[offset]) { /* if we are allowed single quoted strings check for that too. */ if (!((json_parse_flags_allow_single_quoted_strings & flags_bitset) && is_single_quote)) { state->error = json_parse_error_expected_opening_quote; state->offset = offset; return 1; } } /* skip leading '"' or '\''. */ offset++; while ((offset < size) && (quote_to_use != src[offset])) { /* add space for the character. */ data_size++; switch (src[offset]) { default: break; case '\0': case '\t': state->error = json_parse_error_invalid_string; state->offset = offset; return 1; } if ('\\' == src[offset]) { /* skip reverse solidus character. */ offset++; if (offset == size) { state->error = json_parse_error_premature_end_of_buffer; state->offset = offset; return 1; } switch (src[offset]) { default: state->error = json_parse_error_invalid_string_escape_sequence; state->offset = offset; return 1; case '"': case '\\': case '/': case 'b': case 'f': case 'n': case 'r': case 't': /* all valid characters! */ offset++; break; case 'u': if (!(offset + 5 < size)) { /* invalid escaped unicode sequence! */ state->error = json_parse_error_invalid_string_escape_sequence; state->offset = offset; return 1; } codepoint = 0; if (!json_hexadecimal_value(&src[offset + 1], 4, &codepoint)) { /* escaped unicode sequences must contain 4 hexadecimal digits! */ state->error = json_parse_error_invalid_string_escape_sequence; state->offset = offset; return 1; } /* Valid sequence! * see: https://en.wikipedia.org/wiki/UTF-8#Invalid_code_points. * 1 7 U + 0000 U + 007F 0xxxxxxx. * 2 11 U + 0080 U + 07FF 110xxxxx * 10xxxxxx. * 3 16 U + 0800 U + FFFF 1110xxxx * 10xxxxxx 10xxxxxx. * 4 21 U + 10000 U + 10FFFF 11110xxx * 10xxxxxx 10xxxxxx 10xxxxxx. * Note: the high and low surrogate halves used by UTF-16 (U+D800 * through U+DFFF) and code points not encodable by UTF-16 (those after * U+10FFFF) are not legal Unicode values, and their UTF-8 encoding must * be treated as an invalid byte sequence. */ if (high_surrogate != 0) { /* we previously read the high half of the \uxxxx\uxxxx pair, so now * we expect the low half. */ if (codepoint >= 0xdc00 && codepoint <= 0xdfff) { /* low surrogate range. */ data_size += 3; high_surrogate = 0; } else { state->error = json_parse_error_invalid_string_escape_sequence; state->offset = offset; return 1; } } else if (codepoint <= 0x7f) { data_size += 0; } else if (codepoint <= 0x7ff) { data_size += 1; } else if (codepoint >= 0xd800 && codepoint <= 0xdbff) { /* high surrogate range. */ /* The codepoint is the first half of a "utf-16 surrogate pair". so we * need the other half for it to be valid: \uHHHH\uLLLL. */ if (offset + 11 > size || '\\' != src[offset + 5] || 'u' != src[offset + 6]) { state->error = json_parse_error_invalid_string_escape_sequence; state->offset = offset; return 1; } high_surrogate = codepoint; } else if (codepoint >= 0xd800 && codepoint <= 0xdfff) { /* low surrogate range. */ /* we did not read the other half before. */ state->error = json_parse_error_invalid_string_escape_sequence; state->offset = offset; return 1; } else { data_size += 2; } /* escaped codepoints after 0xffff are supported in json through utf-16 * surrogate pairs: \uD83D\uDD25 for U+1F525. */ offset += 5; break; } } else if (('\r' == src[offset]) || ('\n' == src[offset])) { if (!(json_parse_flags_allow_multi_line_strings & flags_bitset)) { /* invalid escaped unicode sequence! */ state->error = json_parse_error_invalid_string_escape_sequence; state->offset = offset; return 1; } offset++; } else { /* skip character (valid part of sequence). */ offset++; } } /* If the offset is equal to the size, we had a non-terminated string! */ if (offset == size) { state->error = json_parse_error_premature_end_of_buffer; state->offset = offset - 1; return 1; } /* skip trailing '"' or '\''. */ offset++; /* add enough space to store the string. */ state->data_size += data_size; /* one more byte for null terminator ending the string! */ state->data_size++; /* update offset. */ state->offset = offset; return 0; } json_weak int is_valid_unquoted_key_char(const char c); int is_valid_unquoted_key_char(const char c) { return (('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('_' == c)); } json_weak int json_get_key_size(struct json_parse_state_s *state); int json_get_key_size(struct json_parse_state_s *state) { const size_t flags_bitset = state->flags_bitset; if (json_parse_flags_allow_unquoted_keys & flags_bitset) { size_t offset = state->offset; const size_t size = state->size; const char *const src = state->src; size_t data_size = state->data_size; /* if we are allowing unquoted keys, first grok for a quote... */ if ('"' == src[offset]) { /* ... if we got a comma, just parse the key as a string as normal. */ return json_get_string_size(state, 1); } else if ((json_parse_flags_allow_single_quoted_strings & flags_bitset) && ('\'' == src[offset])) { /* ... if we got a comma, just parse the key as a string as normal. */ return json_get_string_size(state, 1); } else { while ((offset < size) && is_valid_unquoted_key_char(src[offset])) { offset++; data_size++; } /* one more byte for null terminator ending the string! */ data_size++; if (json_parse_flags_allow_location_information & flags_bitset) { state->dom_size += sizeof(struct json_string_ex_s); } else { state->dom_size += sizeof(struct json_string_s); } /* update offset. */ state->offset = offset; /* update data_size. */ state->data_size = data_size; return 0; } } else { /* we are only allowed to have quoted keys, so just parse a string! */ return json_get_string_size(state, 1); } } json_weak int json_get_object_size(struct json_parse_state_s *state, int is_global_object); int json_get_object_size(struct json_parse_state_s *state, int is_global_object) { const size_t flags_bitset = state->flags_bitset; const char *const src = state->src; const size_t size = state->size; size_t elements = 0; int allow_comma = 0; int found_closing_brace = 0; if (is_global_object) { /* if we found an opening '{' of an object, we actually have a normal JSON * object at the root of the DOM... */ if (!json_skip_all_skippables(state) && '{' == state->src[state->offset]) { /* . and we don't actually have a global object after all! */ is_global_object = 0; } } if (!is_global_object) { if ('{' != src[state->offset]) { state->error = json_parse_error_unknown; return 1; } /* skip leading '{'. */ state->offset++; } state->dom_size += sizeof(struct json_object_s); if ((state->offset == size) && !is_global_object) { state->error = json_parse_error_premature_end_of_buffer; return 1; } do { if (!is_global_object) { if (json_skip_all_skippables(state)) { state->error = json_parse_error_premature_end_of_buffer; return 1; } if ('}' == src[state->offset]) { /* skip trailing '}'. */ state->offset++; found_closing_brace = 1; /* finished the object! */ break; } } else { /* we don't require brackets, so that means the object ends when the input * stream ends! */ if (json_skip_all_skippables(state)) { break; } } /* if we parsed at least once element previously, grok for a comma. */ if (allow_comma) { if (',' == src[state->offset]) { /* skip comma. */ state->offset++; allow_comma = 0; } else if (json_parse_flags_allow_no_commas & flags_bitset) { /* we don't require a comma, and we didn't find one, which is ok! */ allow_comma = 0; } else { /* otherwise we are required to have a comma, and we found none. */ state->error = json_parse_error_expected_comma_or_closing_bracket; return 1; } if (json_parse_flags_allow_trailing_comma & flags_bitset) { continue; } else { if (json_skip_all_skippables(state)) { state->error = json_parse_error_premature_end_of_buffer; return 1; } } } if (json_get_key_size(state)) { /* key parsing failed! */ state->error = json_parse_error_invalid_string; return 1; } if (json_skip_all_skippables(state)) { state->error = json_parse_error_premature_end_of_buffer; return 1; } if (json_parse_flags_allow_equals_in_object & flags_bitset) { const char current = src[state->offset]; if ((':' != current) && ('=' != current)) { state->error = json_parse_error_expected_colon; return 1; } } else { if (':' != src[state->offset]) { state->error = json_parse_error_expected_colon; return 1; } } /* skip colon. */ state->offset++; if (json_skip_all_skippables(state)) { state->error = json_parse_error_premature_end_of_buffer; return 1; } if (json_get_value_size(state, /* is_global_object = */ 0)) { /* value parsing failed! */ return 1; } /* successfully parsed a name/value pair! */ elements++; allow_comma = 1; } while (state->offset < size); if ((state->offset == size) && !is_global_object && !found_closing_brace) { state->error = json_parse_error_premature_end_of_buffer; return 1; } state->dom_size += sizeof(struct json_object_element_s) * elements; return 0; } json_weak int json_get_array_size(struct json_parse_state_s *state); int json_get_array_size(struct json_parse_state_s *state) { const size_t flags_bitset = state->flags_bitset; size_t elements = 0; int allow_comma = 0; const char *const src = state->src; const size_t size = state->size; if ('[' != src[state->offset]) { /* expected array to begin with leading '['. */ state->error = json_parse_error_unknown; return 1; } /* skip leading '['. */ state->offset++; state->dom_size += sizeof(struct json_array_s); while (state->offset < size) { if (json_skip_all_skippables(state)) { state->error = json_parse_error_premature_end_of_buffer; return 1; } if (']' == src[state->offset]) { /* skip trailing ']'. */ state->offset++; state->dom_size += sizeof(struct json_array_element_s) * elements; /* finished the object! */ return 0; } /* if we parsed at least once element previously, grok for a comma. */ if (allow_comma) { if (',' == src[state->offset]) { /* skip comma. */ state->offset++; allow_comma = 0; } else if (!(json_parse_flags_allow_no_commas & flags_bitset)) { state->error = json_parse_error_expected_comma_or_closing_bracket; return 1; } if (json_parse_flags_allow_trailing_comma & flags_bitset) { allow_comma = 0; continue; } else { if (json_skip_all_skippables(state)) { state->error = json_parse_error_premature_end_of_buffer; return 1; } } } if (json_get_value_size(state, /* is_global_object = */ 0)) { /* value parsing failed! */ return 1; } /* successfully parsed an array element! */ elements++; allow_comma = 1; } /* we consumed the entire input before finding the closing ']' of the array! */ state->error = json_parse_error_premature_end_of_buffer; return 1; } json_weak int json_get_number_size(struct json_parse_state_s *state); int json_get_number_size(struct json_parse_state_s *state) { const size_t flags_bitset = state->flags_bitset; size_t offset = state->offset; const size_t size = state->size; int had_leading_digits = 0; const char *const src = state->src; state->dom_size += sizeof(struct json_number_s); if ((json_parse_flags_allow_hexadecimal_numbers & flags_bitset) && (offset + 1 < size) && ('0' == src[offset]) && (('x' == src[offset + 1]) || ('X' == src[offset + 1]))) { /* skip the leading 0x that identifies a hexadecimal number. */ offset += 2; /* consume hexadecimal digits. */ while ((offset < size) && (('0' <= src[offset] && src[offset] <= '9') || ('a' <= src[offset] && src[offset] <= 'f') || ('A' <= src[offset] && src[offset] <= 'F'))) { offset++; } } else { int found_sign = 0; int inf_or_nan = 0; if ((offset < size) && (('-' == src[offset]) || ((json_parse_flags_allow_leading_plus_sign & flags_bitset) && ('+' == src[offset])))) { /* skip valid leading '-' or '+'. */ offset++; found_sign = 1; } if (json_parse_flags_allow_inf_and_nan & flags_bitset) { const char inf[9] = "Infinity"; const size_t inf_strlen = sizeof(inf) - 1; const char nan[4] = "NaN"; const size_t nan_strlen = sizeof(nan) - 1; if (offset + inf_strlen < size) { int found = 1; size_t i; for (i = 0; i < inf_strlen; i++) { if (inf[i] != src[offset + i]) { found = 0; break; } } if (found) { /* We found our special 'Infinity' keyword! */ offset += inf_strlen; inf_or_nan = 1; } } if (offset + nan_strlen < size) { int found = 1; size_t i; for (i = 0; i < nan_strlen; i++) { if (nan[i] != src[offset + i]) { found = 0; break; } } if (found) { /* We found our special 'NaN' keyword! */ offset += nan_strlen; inf_or_nan = 1; } } } if (found_sign && !inf_or_nan && (offset < size) && !('0' <= src[offset] && src[offset] <= '9')) { /* check if we are allowing leading '.'. */ if (!(json_parse_flags_allow_leading_or_trailing_decimal_point & flags_bitset) || ('.' != src[offset])) { /* a leading '-' must be immediately followed by any digit! */ state->error = json_parse_error_invalid_number_format; state->offset = offset; return 1; } } if ((offset < size) && ('0' == src[offset])) { /* skip valid '0'. */ offset++; /* we need to record whether we had any leading digits for checks later. */ had_leading_digits = 1; if ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')) { /* a leading '0' must not be immediately followed by any digit! */ state->error = json_parse_error_invalid_number_format; state->offset = offset; return 1; } } /* the main digits of our number next. */ while ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')) { offset++; /* we need to record whether we had any leading digits for checks later. */ had_leading_digits = 1; } if ((offset < size) && ('.' == src[offset])) { offset++; if (!('0' <= src[offset] && src[offset] <= '9')) { if (!(json_parse_flags_allow_leading_or_trailing_decimal_point & flags_bitset) || !had_leading_digits) { /* a decimal point must be followed by at least one digit. */ state->error = json_parse_error_invalid_number_format; state->offset = offset; return 1; } } /* a decimal point can be followed by more digits of course! */ while ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')) { offset++; } } if ((offset < size) && ('e' == src[offset] || 'E' == src[offset])) { /* our number has an exponent! Skip 'e' or 'E'. */ offset++; if ((offset < size) && ('-' == src[offset] || '+' == src[offset])) { /* skip optional '-' or '+'. */ offset++; } if ((offset < size) && !('0' <= src[offset] && src[offset] <= '9')) { /* an exponent must have at least one digit! */ state->error = json_parse_error_invalid_number_format; state->offset = offset; return 1; } /* consume exponent digits. */ do { offset++; } while ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')); } } if (offset < size) { switch (src[offset]) { case ' ': case '\t': case '\r': case '\n': case '}': case ',': case ']': /* all of the above are ok. */ break; case '=': if (json_parse_flags_allow_equals_in_object & flags_bitset) { break; } state->error = json_parse_error_invalid_number_format; state->offset = offset; return 1; default: state->error = json_parse_error_invalid_number_format; state->offset = offset; return 1; } } state->data_size += offset - state->offset; /* one more byte for null terminator ending the number string! */ state->data_size++; /* update offset. */ state->offset = offset; return 0; } json_weak int json_get_value_size(struct json_parse_state_s *state, int is_global_object); int json_get_value_size(struct json_parse_state_s *state, int is_global_object) { const size_t flags_bitset = state->flags_bitset; const char *const src = state->src; size_t offset; const size_t size = state->size; if (json_parse_flags_allow_location_information & flags_bitset) { state->dom_size += sizeof(struct json_value_ex_s); } else { state->dom_size += sizeof(struct json_value_s); } if (is_global_object) { return json_get_object_size(state, /* is_global_object = */ 1); } else { if (json_skip_all_skippables(state)) { state->error = json_parse_error_premature_end_of_buffer; return 1; } /* can cache offset now. */ offset = state->offset; switch (src[offset]) { case '"': return json_get_string_size(state, 0); case '\'': if (json_parse_flags_allow_single_quoted_strings & flags_bitset) { return json_get_string_size(state, 0); } else { /* invalid value! */ state->error = json_parse_error_invalid_value; return 1; } case '{': return json_get_object_size(state, /* is_global_object = */ 0); case '[': return json_get_array_size(state); case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return json_get_number_size(state); case '+': if (json_parse_flags_allow_leading_plus_sign & flags_bitset) { return json_get_number_size(state); } else { /* invalid value! */ state->error = json_parse_error_invalid_number_format; return 1; } case '.': if (json_parse_flags_allow_leading_or_trailing_decimal_point & flags_bitset) { return json_get_number_size(state); } else { /* invalid value! */ state->error = json_parse_error_invalid_number_format; return 1; } default: if ((offset + 4) <= size && 't' == src[offset + 0] && 'r' == src[offset + 1] && 'u' == src[offset + 2] && 'e' == src[offset + 3]) { state->offset += 4; return 0; } else if ((offset + 5) <= size && 'f' == src[offset + 0] && 'a' == src[offset + 1] && 'l' == src[offset + 2] && 's' == src[offset + 3] && 'e' == src[offset + 4]) { state->offset += 5; return 0; } else if ((offset + 4) <= size && 'n' == state->src[offset + 0] && 'u' == state->src[offset + 1] && 'l' == state->src[offset + 2] && 'l' == state->src[offset + 3]) { state->offset += 4; return 0; } else if ((json_parse_flags_allow_inf_and_nan & flags_bitset) && (offset + 3) <= size && 'N' == src[offset + 0] && 'a' == src[offset + 1] && 'N' == src[offset + 2]) { return json_get_number_size(state); } else if ((json_parse_flags_allow_inf_and_nan & flags_bitset) && (offset + 8) <= size && 'I' == src[offset + 0] && 'n' == src[offset + 1] && 'f' == src[offset + 2] && 'i' == src[offset + 3] && 'n' == src[offset + 4] && 'i' == src[offset + 5] && 't' == src[offset + 6] && 'y' == src[offset + 7]) { return json_get_number_size(state); } /* invalid value! */ state->error = json_parse_error_invalid_value; return 1; } } } json_weak void json_parse_value(struct json_parse_state_s *state, int is_global_object, struct json_value_s *value); json_weak void json_parse_string(struct json_parse_state_s *state, struct json_string_s *string); void json_parse_string(struct json_parse_state_s *state, struct json_string_s *string) { size_t offset = state->offset; size_t bytes_written = 0; const char *const src = state->src; const char quote_to_use = '\'' == src[offset] ? '\'' : '"'; char *data = state->data; unsigned long high_surrogate = 0; unsigned long codepoint; string->string = data; /* skip leading '"' or '\''. */ offset++; while (quote_to_use != src[offset]) { if ('\\' == src[offset]) { /* skip the reverse solidus. */ offset++; switch (src[offset++]) { default: return; /* we cannot ever reach here. */ case 'u': { codepoint = 0; if (!json_hexadecimal_value(&src[offset], 4, &codepoint)) { return; /* this shouldn't happen as the value was already validated. */ } offset += 4; if (codepoint <= 0x7fu) { data[bytes_written++] = (char)codepoint; /* 0xxxxxxx. */ } else if (codepoint <= 0x7ffu) { data[bytes_written++] = (char)(0xc0u | (codepoint >> 6)); /* 110xxxxx. */ data[bytes_written++] = (char)(0x80u | (codepoint & 0x3fu)); /* 10xxxxxx. */ } else if (codepoint >= 0xd800 && codepoint <= 0xdbff) { /* high surrogate. */ high_surrogate = codepoint; continue; /* we need the low half to form a complete codepoint. */ } else if (codepoint >= 0xdc00 && codepoint <= 0xdfff) { /* low surrogate. */ /* combine with the previously read half to obtain the complete * codepoint. */ const unsigned long surrogate_offset = 0x10000u - (0xD800u << 10) - 0xDC00u; codepoint = (high_surrogate << 10) + codepoint + surrogate_offset; high_surrogate = 0; data[bytes_written++] = (char)(0xF0u | (codepoint >> 18)); /* 11110xxx. */ data[bytes_written++] = (char)(0x80u | ((codepoint >> 12) & 0x3fu)); /* 10xxxxxx. */ data[bytes_written++] = (char)(0x80u | ((codepoint >> 6) & 0x3fu)); /* 10xxxxxx. */ data[bytes_written++] = (char)(0x80u | (codepoint & 0x3fu)); /* 10xxxxxx. */ } else { /* we assume the value was validated and thus is within the valid * range. */ data[bytes_written++] = (char)(0xe0u | (codepoint >> 12)); /* 1110xxxx. */ data[bytes_written++] = (char)(0x80u | ((codepoint >> 6) & 0x3fu)); /* 10xxxxxx. */ data[bytes_written++] = (char)(0x80u | (codepoint & 0x3fu)); /* 10xxxxxx. */ } } break; case '"': data[bytes_written++] = '"'; break; case '\\': data[bytes_written++] = '\\'; break; case '/': data[bytes_written++] = '/'; break; case 'b': data[bytes_written++] = '\b'; break; case 'f': data[bytes_written++] = '\f'; break; case 'n': data[bytes_written++] = '\n'; break; case 'r': data[bytes_written++] = '\r'; break; case 't': data[bytes_written++] = '\t'; break; case '\r': data[bytes_written++] = '\r'; /* check if we have a "\r\n" sequence. */ if ('\n' == src[offset]) { data[bytes_written++] = '\n'; offset++; } break; case '\n': data[bytes_written++] = '\n'; break; } } else { /* copy the character. */ data[bytes_written++] = src[offset++]; } } /* skip trailing '"' or '\''. */ offset++; /* record the size of the string. */ string->string_size = bytes_written; /* add null terminator to string. */ data[bytes_written++] = '\0'; /* move data along. */ state->data += bytes_written; /* update offset. */ state->offset = offset; } json_weak void json_parse_key(struct json_parse_state_s *state, struct json_string_s *string); void json_parse_key(struct json_parse_state_s *state, struct json_string_s *string) { if (json_parse_flags_allow_unquoted_keys & state->flags_bitset) { const char *const src = state->src; char *const data = state->data; size_t offset = state->offset; /* if we are allowing unquoted keys, check for quoted anyway... */ if (('"' == src[offset]) || ('\'' == src[offset])) { /* ... if we got a quote, just parse the key as a string as normal. */ json_parse_string(state, string); } else { size_t size = 0; string->string = state->data; while (is_valid_unquoted_key_char(src[offset])) { data[size++] = src[offset++]; } /* add null terminator to string. */ data[size] = '\0'; /* record the size of the string. */ string->string_size = size++; /* move data along. */ state->data += size; /* update offset. */ state->offset = offset; } } else { /* we are only allowed to have quoted keys, so just parse a string! */ json_parse_string(state, string); } } json_weak void json_parse_object(struct json_parse_state_s *state, int is_global_object, struct json_object_s *object); void json_parse_object(struct json_parse_state_s *state, int is_global_object, struct json_object_s *object) { const size_t flags_bitset = state->flags_bitset; const size_t size = state->size; const char *const src = state->src; size_t elements = 0; int allow_comma = 0; struct json_object_element_s *previous = json_null; if (is_global_object) { /* if we skipped some whitespace, and then found an opening '{' of an. */ /* object, we actually have a normal JSON object at the root of the DOM... */ if ('{' == src[state->offset]) { /* . and we don't actually have a global object after all! */ is_global_object = 0; } } if (!is_global_object) { /* skip leading '{'. */ state->offset++; } (void)json_skip_all_skippables(state); /* reset elements. */ elements = 0; while (state->offset < size) { struct json_object_element_s *element = json_null; struct json_string_s *string = json_null; struct json_value_s *value = json_null; if (!is_global_object) { (void)json_skip_all_skippables(state); if ('}' == src[state->offset]) { /* skip trailing '}'. */ state->offset++; /* finished the object! */ break; } } else { if (json_skip_all_skippables(state)) { /* global object ends when the file ends! */ break; } } /* if we parsed at least one element previously, grok for a comma. */ if (allow_comma) { if (',' == src[state->offset]) { /* skip comma. */ state->offset++; allow_comma = 0; continue; } } element = (struct json_object_element_s *)state->dom; state->dom += sizeof(struct json_object_element_s); if (json_null == previous) { /* this is our first element, so record it in our object. */ object->start = element; } else { previous->next = element; } previous = element; if (json_parse_flags_allow_location_information & flags_bitset) { struct json_string_ex_s *string_ex = (struct json_string_ex_s *)state->dom; state->dom += sizeof(struct json_string_ex_s); string_ex->offset = state->offset; string_ex->line_no = state->line_no; string_ex->row_no = state->offset - state->line_offset; string = &(string_ex->string); } else { string = (struct json_string_s *)state->dom; state->dom += sizeof(struct json_string_s); } element->name = string; (void)json_parse_key(state, string); (void)json_skip_all_skippables(state); /* skip colon or equals. */ state->offset++; (void)json_skip_all_skippables(state); if (json_parse_flags_allow_location_information & flags_bitset) { struct json_value_ex_s *value_ex = (struct json_value_ex_s *)state->dom; state->dom += sizeof(struct json_value_ex_s); value_ex->offset = state->offset; value_ex->line_no = state->line_no; value_ex->row_no = state->offset - state->line_offset; value = &(value_ex->value); } else { value = (struct json_value_s *)state->dom; state->dom += sizeof(struct json_value_s); } element->value = value; json_parse_value(state, /* is_global_object = */ 0, value); /* successfully parsed a name/value pair! */ elements++; allow_comma = 1; } /* if we had at least one element, end the linked list. */ if (previous) { previous->next = json_null; } if (0 == elements) { object->start = json_null; } object->length = elements; } json_weak void json_parse_array(struct json_parse_state_s *state, struct json_array_s *array); void json_parse_array(struct json_parse_state_s *state, struct json_array_s *array) { const char *const src = state->src; const size_t size = state->size; size_t elements = 0; int allow_comma = 0; struct json_array_element_s *previous = json_null; /* skip leading '['. */ state->offset++; (void)json_skip_all_skippables(state); /* reset elements. */ elements = 0; do { struct json_array_element_s *element = json_null; struct json_value_s *value = json_null; (void)json_skip_all_skippables(state); if (']' == src[state->offset]) { /* skip trailing ']'. */ state->offset++; /* finished the array! */ break; } /* if we parsed at least one element previously, grok for a comma. */ if (allow_comma) { if (',' == src[state->offset]) { /* skip comma. */ state->offset++; allow_comma = 0; continue; } } element = (struct json_array_element_s *)state->dom; state->dom += sizeof(struct json_array_element_s); if (json_null == previous) { /* this is our first element, so record it in our array. */ array->start = element; } else { previous->next = element; } previous = element; if (json_parse_flags_allow_location_information & state->flags_bitset) { struct json_value_ex_s *value_ex = (struct json_value_ex_s *)state->dom; state->dom += sizeof(struct json_value_ex_s); value_ex->offset = state->offset; value_ex->line_no = state->line_no; value_ex->row_no = state->offset - state->line_offset; value = &(value_ex->value); } else { value = (struct json_value_s *)state->dom; state->dom += sizeof(struct json_value_s); } element->value = value; json_parse_value(state, /* is_global_object = */ 0, value); /* successfully parsed an array element! */ elements++; allow_comma = 1; } while (state->offset < size); /* end the linked list. */ if (previous) { previous->next = json_null; } if (0 == elements) { array->start = json_null; } array->length = elements; } json_weak void json_parse_number(struct json_parse_state_s *state, struct json_number_s *number); void json_parse_number(struct json_parse_state_s *state, struct json_number_s *number) { const size_t flags_bitset = state->flags_bitset; size_t offset = state->offset; const size_t size = state->size; size_t bytes_written = 0; const char *const src = state->src; char *data = state->data; number->number = data; if (json_parse_flags_allow_hexadecimal_numbers & flags_bitset) { if (('0' == src[offset]) && (('x' == src[offset + 1]) || ('X' == src[offset + 1]))) { /* consume hexadecimal digits. */ while ((offset < size) && (('0' <= src[offset] && src[offset] <= '9') || ('a' <= src[offset] && src[offset] <= 'f') || ('A' <= src[offset] && src[offset] <= 'F') || ('x' == src[offset]) || ('X' == src[offset]))) { data[bytes_written++] = src[offset++]; } } } while (offset < size) { int end = 0; switch (src[offset]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': case 'e': case 'E': case '+': case '-': data[bytes_written++] = src[offset++]; break; default: end = 1; break; } if (0 != end) { break; } } if (json_parse_flags_allow_inf_and_nan & flags_bitset) { const size_t inf_strlen = 8; /* = strlen("Infinity");. */ const size_t nan_strlen = 3; /* = strlen("NaN");. */ if (offset + inf_strlen < size) { if ('I' == src[offset]) { size_t i; /* We found our special 'Infinity' keyword! */ for (i = 0; i < inf_strlen; i++) { data[bytes_written++] = src[offset++]; } } } if (offset + nan_strlen < size) { if ('N' == src[offset]) { size_t i; /* We found our special 'NaN' keyword! */ for (i = 0; i < nan_strlen; i++) { data[bytes_written++] = src[offset++]; } } } } /* record the size of the number. */ number->number_size = bytes_written; /* add null terminator to number string. */ data[bytes_written++] = '\0'; /* move data along. */ state->data += bytes_written; /* update offset. */ state->offset = offset; } json_weak void json_parse_value(struct json_parse_state_s *state, int is_global_object, struct json_value_s *value); void json_parse_value(struct json_parse_state_s *state, int is_global_object, struct json_value_s *value) { const size_t flags_bitset = state->flags_bitset; const char *const src = state->src; const size_t size = state->size; size_t offset; (void)json_skip_all_skippables(state); /* cache offset now. */ offset = state->offset; if (is_global_object) { value->type = json_type_object; value->payload = state->dom; state->dom += sizeof(struct json_object_s); json_parse_object(state, /* is_global_object = */ 1, (struct json_object_s *)value->payload); } else { switch (src[offset]) { case '"': case '\'': value->type = json_type_string; value->payload = state->dom; state->dom += sizeof(struct json_string_s); json_parse_string(state, (struct json_string_s *)value->payload); break; case '{': value->type = json_type_object; value->payload = state->dom; state->dom += sizeof(struct json_object_s); json_parse_object(state, /* is_global_object = */ 0, (struct json_object_s *)value->payload); break; case '[': value->type = json_type_array; value->payload = state->dom; state->dom += sizeof(struct json_array_s); json_parse_array(state, (struct json_array_s *)value->payload); break; case '-': case '+': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': value->type = json_type_number; value->payload = state->dom; state->dom += sizeof(struct json_number_s); json_parse_number(state, (struct json_number_s *)value->payload); break; default: if ((offset + 4) <= size && 't' == src[offset + 0] && 'r' == src[offset + 1] && 'u' == src[offset + 2] && 'e' == src[offset + 3]) { value->type = json_type_true; value->payload = json_null; state->offset += 4; } else if ((offset + 5) <= size && 'f' == src[offset + 0] && 'a' == src[offset + 1] && 'l' == src[offset + 2] && 's' == src[offset + 3] && 'e' == src[offset + 4]) { value->type = json_type_false; value->payload = json_null; state->offset += 5; } else if ((offset + 4) <= size && 'n' == src[offset + 0] && 'u' == src[offset + 1] && 'l' == src[offset + 2] && 'l' == src[offset + 3]) { value->type = json_type_null; value->payload = json_null; state->offset += 4; } else if ((json_parse_flags_allow_inf_and_nan & flags_bitset) && (offset + 3) <= size && 'N' == src[offset + 0] && 'a' == src[offset + 1] && 'N' == src[offset + 2]) { value->type = json_type_number; value->payload = state->dom; state->dom += sizeof(struct json_number_s); json_parse_number(state, (struct json_number_s *)value->payload); } else if ((json_parse_flags_allow_inf_and_nan & flags_bitset) && (offset + 8) <= size && 'I' == src[offset + 0] && 'n' == src[offset + 1] && 'f' == src[offset + 2] && 'i' == src[offset + 3] && 'n' == src[offset + 4] && 'i' == src[offset + 5] && 't' == src[offset + 6] && 'y' == src[offset + 7]) { value->type = json_type_number; value->payload = state->dom; state->dom += sizeof(struct json_number_s); json_parse_number(state, (struct json_number_s *)value->payload); } break; } } } struct json_value_s * json_parse_ex(const void *src, size_t src_size, size_t flags_bitset, void *(*alloc_func_ptr)(void *user_data, size_t size), void *user_data, struct json_parse_result_s *result) { struct json_parse_state_s state; void *allocation; struct json_value_s *value; size_t total_size; int input_error; if (result) { result->error = json_parse_error_none; result->error_offset = 0; result->error_line_no = 0; result->error_row_no = 0; } if (json_null == src) { /* invalid src pointer was null! */ return json_null; } state.src = (const char *)src; state.size = src_size; state.offset = 0; state.line_no = 1; state.line_offset = 0; state.error = json_parse_error_none; state.dom_size = 0; state.data_size = 0; state.flags_bitset = flags_bitset; input_error = json_get_value_size( &state, (int)(json_parse_flags_allow_global_object & state.flags_bitset)); if (0 == input_error) { json_skip_all_skippables(&state); if (state.offset != state.size) { /* our parsing didn't have an error, but there are characters remaining in * the input that weren't part of the JSON! */ state.error = json_parse_error_unexpected_trailing_characters; input_error = 1; } } if (input_error) { /* parsing value's size failed (most likely an invalid JSON DOM!). */ if (result) { result->error = state.error; result->error_offset = state.offset; result->error_line_no = state.line_no; result->error_row_no = state.offset - state.line_offset; } return json_null; } /* our total allocation is the combination of the dom and data sizes (we. */ /* first encode the structure of the JSON, and then the data referenced by. */ /* the JSON values). */ total_size = state.dom_size + state.data_size; if (json_null == alloc_func_ptr) { allocation = malloc(total_size); } else { allocation = alloc_func_ptr(user_data, total_size); } if (json_null == allocation) { /* malloc failed! */ if (result) { result->error = json_parse_error_allocator_failed; result->error_offset = 0; result->error_line_no = 0; result->error_row_no = 0; } return json_null; } /* reset offset so we can reuse it. */ state.offset = 0; /* reset the line information so we can reuse it. */ state.line_no = 1; state.line_offset = 0; state.dom = (char *)allocation; state.data = state.dom + state.dom_size; if (json_parse_flags_allow_location_information & state.flags_bitset) { struct json_value_ex_s *value_ex = (struct json_value_ex_s *)state.dom; state.dom += sizeof(struct json_value_ex_s); value_ex->offset = state.offset; value_ex->line_no = state.line_no; value_ex->row_no = state.offset - state.line_offset; value = &(value_ex->value); } else { value = (struct json_value_s *)state.dom; state.dom += sizeof(struct json_value_s); } json_parse_value( &state, (int)(json_parse_flags_allow_global_object & state.flags_bitset), value); return (struct json_value_s *)allocation; } struct json_value_s *json_parse(const void *src, size_t src_size) { return json_parse_ex(src, src_size, json_parse_flags_default, json_null, json_null, json_null); } struct json_extract_result_s { size_t dom_size; size_t data_size; }; struct json_value_s *json_extract_value(const struct json_value_s *value) { return json_extract_value_ex(value, json_null, json_null); } json_weak struct json_extract_result_s json_extract_get_number_size(const struct json_number_s *const number); json_weak struct json_extract_result_s json_extract_get_string_size(const struct json_string_s *const string); json_weak struct json_extract_result_s json_extract_get_object_size(const struct json_object_s *const object); json_weak struct json_extract_result_s json_extract_get_array_size(const struct json_array_s *const array); json_weak struct json_extract_result_s json_extract_get_value_size(const struct json_value_s *const value); struct json_extract_result_s json_extract_get_number_size(const struct json_number_s *const number) { struct json_extract_result_s result; result.dom_size = sizeof(struct json_number_s); result.data_size = number->number_size; return result; } struct json_extract_result_s json_extract_get_string_size(const struct json_string_s *const string) { struct json_extract_result_s result; result.dom_size = sizeof(struct json_string_s); result.data_size = string->string_size + 1; return result; } struct json_extract_result_s json_extract_get_object_size(const struct json_object_s *const object) { struct json_extract_result_s result; size_t i; const struct json_object_element_s *element = object->start; result.dom_size = sizeof(struct json_object_s) + (sizeof(struct json_object_element_s) * object->length); result.data_size = 0; for (i = 0; i < object->length; i++) { const struct json_extract_result_s string_result = json_extract_get_string_size(element->name); const struct json_extract_result_s value_result = json_extract_get_value_size(element->value); result.dom_size += string_result.dom_size; result.data_size += string_result.data_size; result.dom_size += value_result.dom_size; result.data_size += value_result.data_size; element = element->next; } return result; } struct json_extract_result_s json_extract_get_array_size(const struct json_array_s *const array) { struct json_extract_result_s result; size_t i; const struct json_array_element_s *element = array->start; result.dom_size = sizeof(struct json_array_s) + (sizeof(struct json_array_element_s) * array->length); result.data_size = 0; for (i = 0; i < array->length; i++) { const struct json_extract_result_s value_result = json_extract_get_value_size(element->value); result.dom_size += value_result.dom_size; result.data_size += value_result.data_size; element = element->next; } return result; } struct json_extract_result_s json_extract_get_value_size(const struct json_value_s *const value) { struct json_extract_result_s result = {0, 0}; switch (value->type) { default: break; case json_type_object: result = json_extract_get_object_size( (const struct json_object_s *)value->payload); break; case json_type_array: result = json_extract_get_array_size( (const struct json_array_s *)value->payload); break; case json_type_number: result = json_extract_get_number_size( (const struct json_number_s *)value->payload); break; case json_type_string: result = json_extract_get_string_size( (const struct json_string_s *)value->payload); break; } result.dom_size += sizeof(struct json_value_s); return result; } struct json_extract_state_s { char *dom; char *data; }; json_weak void json_extract_copy_value(struct json_extract_state_s *const state, const struct json_value_s *const value); void json_extract_copy_value(struct json_extract_state_s *const state, const struct json_value_s *const value) { struct json_string_s *string; struct json_number_s *number; struct json_object_s *object; struct json_array_s *array; struct json_value_s *new_value; memcpy(state->dom, value, sizeof(struct json_value_s)); new_value = (struct json_value_s *)state->dom; state->dom += sizeof(struct json_value_s); new_value->payload = state->dom; if (json_type_string == value->type) { memcpy(state->dom, value->payload, sizeof(struct json_string_s)); string = (struct json_string_s *)state->dom; state->dom += sizeof(struct json_string_s); memcpy(state->data, string->string, string->string_size + 1); string->string = state->data; state->data += string->string_size + 1; } else if (json_type_number == value->type) { memcpy(state->dom, value->payload, sizeof(struct json_number_s)); number = (struct json_number_s *)state->dom; state->dom += sizeof(struct json_number_s); memcpy(state->data, number->number, number->number_size); number->number = state->data; state->data += number->number_size; } else if (json_type_object == value->type) { struct json_object_element_s *element; size_t i; memcpy(state->dom, value->payload, sizeof(struct json_object_s)); object = (struct json_object_s *)state->dom; state->dom += sizeof(struct json_object_s); element = object->start; object->start = (struct json_object_element_s *)state->dom; for (i = 0; i < object->length; i++) { struct json_value_s *previous_value; struct json_object_element_s *previous_element; memcpy(state->dom, element, sizeof(struct json_object_element_s)); element = (struct json_object_element_s *)state->dom; state->dom += sizeof(struct json_object_element_s); string = element->name; memcpy(state->dom, string, sizeof(struct json_string_s)); string = (struct json_string_s *)state->dom; state->dom += sizeof(struct json_string_s); element->name = string; memcpy(state->data, string->string, string->string_size + 1); string->string = state->data; state->data += string->string_size + 1; previous_value = element->value; element->value = (struct json_value_s *)state->dom; json_extract_copy_value(state, previous_value); previous_element = element; element = element->next; if (element) { previous_element->next = (struct json_object_element_s *)state->dom; } } } else if (json_type_array == value->type) { struct json_array_element_s *element; size_t i; memcpy(state->dom, value->payload, sizeof(struct json_array_s)); array = (struct json_array_s *)state->dom; state->dom += sizeof(struct json_array_s); element = array->start; array->start = (struct json_array_element_s *)state->dom; for (i = 0; i < array->length; i++) { struct json_value_s *previous_value; struct json_array_element_s *previous_element; memcpy(state->dom, element, sizeof(struct json_array_element_s)); element = (struct json_array_element_s *)state->dom; state->dom += sizeof(struct json_array_element_s); previous_value = element->value; element->value = (struct json_value_s *)state->dom; json_extract_copy_value(state, previous_value); previous_element = element; element = element->next; if (element) { previous_element->next = (struct json_array_element_s *)state->dom; } } } } struct json_value_s *json_extract_value_ex(const struct json_value_s *value, void *(*alloc_func_ptr)(void *, size_t), void *user_data) { void *allocation; struct json_extract_result_s result; struct json_extract_state_s state; size_t total_size; if (json_null == value) { /* invalid value was null! */ return json_null; } result = json_extract_get_value_size(value); total_size = result.dom_size + result.data_size; if (json_null == alloc_func_ptr) { allocation = malloc(total_size); } else { allocation = alloc_func_ptr(user_data, total_size); } state.dom = (char *)allocation; state.data = state.dom + result.dom_size; json_extract_copy_value(&state, value); return (struct json_value_s *)allocation; } struct json_string_s *json_value_as_string(struct json_value_s *const value) { if (value->type != json_type_string) { return json_null; } return (struct json_string_s *)value->payload; } struct json_number_s *json_value_as_number(struct json_value_s *const value) { if (value->type != json_type_number) { return json_null; } return (struct json_number_s *)value->payload; } struct json_object_s *json_value_as_object(struct json_value_s *const value) { if (value->type != json_type_object) { return json_null; } return (struct json_object_s *)value->payload; } struct json_array_s *json_value_as_array(struct json_value_s *const value) { if (value->type != json_type_array) { return json_null; } return (struct json_array_s *)value->payload; } int json_value_is_true(const struct json_value_s *const value) { return value->type == json_type_true; } int json_value_is_false(const struct json_value_s *const value) { return value->type == json_type_false; } int json_value_is_null(const struct json_value_s *const value) { return value->type == json_type_null; } json_weak int json_write_minified_get_value_size(const struct json_value_s *value, size_t *size); json_weak int json_write_get_number_size(const struct json_number_s *number, size_t *size); int json_write_get_number_size(const struct json_number_s *number, size_t *size) { json_uintmax_t parsed_number; size_t i; if (number->number_size >= 2) { switch (number->number[1]) { default: break; case 'x': case 'X': /* the number is a json_parse_flags_allow_hexadecimal_numbers hexadecimal * so we have to do extra work to convert it to a non-hexadecimal for JSON * output. */ parsed_number = json_strtoumax(number->number, json_null, 0); i = 0; while (0 != parsed_number) { parsed_number /= 10; i++; } *size += i; return 0; } } /* check to see if the number has leading/trailing decimal point. */ i = 0; /* skip any leading '+' or '-'. */ if ((i < number->number_size) && (('+' == number->number[i]) || ('-' == number->number[i]))) { i++; } /* check if we have infinity. */ if ((i < number->number_size) && ('I' == number->number[i])) { const char *inf = "Infinity"; size_t k; for (k = i; k < number->number_size; k++) { const char c = *inf++; /* Check if we found the Infinity string! */ if ('\0' == c) { break; } else if (c != number->number[k]) { break; } } if ('\0' == *inf) { /* Inf becomes 1.7976931348623158e308 because JSON can't support it. */ *size += 22; /* if we had a leading '-' we need to record it in the JSON output. */ if ('-' == number->number[0]) { *size += 1; } } return 0; } /* check if we have nan. */ if ((i < number->number_size) && ('N' == number->number[i])) { const char *nan = "NaN"; size_t k; for (k = i; k < number->number_size; k++) { const char c = *nan++; /* Check if we found the NaN string! */ if ('\0' == c) { break; } else if (c != number->number[k]) { break; } } if ('\0' == *nan) { /* NaN becomes 1 because JSON can't support it. */ *size += 1; return 0; } } /* if we had a leading decimal point. */ if ((i < number->number_size) && ('.' == number->number[i])) { /* 1 + because we had a leading decimal point. */ *size += 1; goto cleanup; } for (; i < number->number_size; i++) { const char c = number->number[i]; if (!('0' <= c && c <= '9')) { break; } } /* if we had a trailing decimal point. */ if ((i + 1 == number->number_size) && ('.' == number->number[i])) { /* 1 + because we had a trailing decimal point. */ *size += 1; goto cleanup; } cleanup: *size += number->number_size; /* the actual string of the number. */ /* if we had a leading '+' we don't record it in the JSON output. */ if ('+' == number->number[0]) { *size -= 1; } return 0; } json_weak int json_write_get_string_size(const struct json_string_s *string, size_t *size); int json_write_get_string_size(const struct json_string_s *string, size_t *size) { size_t i; for (i = 0; i < string->string_size; i++) { switch (string->string[i]) { case '"': case '\\': case '\b': case '\f': case '\n': case '\r': case '\t': *size += 2; break; default: *size += 1; break; } } *size += 2; /* need to encode the surrounding '"' characters. */ return 0; } json_weak int json_write_minified_get_array_size(const struct json_array_s *array, size_t *size); int json_write_minified_get_array_size(const struct json_array_s *array, size_t *size) { struct json_array_element_s *element; *size += 2; /* '[' and ']'. */ if (1 < array->length) { *size += array->length - 1; /* ','s seperate each element. */ } for (element = array->start; json_null != element; element = element->next) { if (json_write_minified_get_value_size(element->value, size)) { /* value was malformed! */ return 1; } } return 0; } json_weak int json_write_minified_get_object_size(const struct json_object_s *object, size_t *size); int json_write_minified_get_object_size(const struct json_object_s *object, size_t *size) { struct json_object_element_s *element; *size += 2; /* '{' and '}'. */ *size += object->length; /* ':'s seperate each name/value pair. */ if (1 < object->length) { *size += object->length - 1; /* ','s seperate each element. */ } for (element = object->start; json_null != element; element = element->next) { if (json_write_get_string_size(element->name, size)) { /* string was malformed! */ return 1; } if (json_write_minified_get_value_size(element->value, size)) { /* value was malformed! */ return 1; } } return 0; } json_weak int json_write_minified_get_value_size(const struct json_value_s *value, size_t *size); int json_write_minified_get_value_size(const struct json_value_s *value, size_t *size) { switch (value->type) { default: /* unknown value type found! */ return 1; case json_type_number: return json_write_get_number_size((struct json_number_s *)value->payload, size); case json_type_string: return json_write_get_string_size((struct json_string_s *)value->payload, size); case json_type_array: return json_write_minified_get_array_size( (struct json_array_s *)value->payload, size); case json_type_object: return json_write_minified_get_object_size( (struct json_object_s *)value->payload, size); case json_type_true: *size += 4; /* the string "true". */ return 0; case json_type_false: *size += 5; /* the string "false". */ return 0; case json_type_null: *size += 4; /* the string "null". */ return 0; } } json_weak char *json_write_minified_value(const struct json_value_s *value, char *data); json_weak char *json_write_number(const struct json_number_s *number, char *data); char *json_write_number(const struct json_number_s *number, char *data) { json_uintmax_t parsed_number, backup; size_t i; if (number->number_size >= 2) { switch (number->number[1]) { default: break; case 'x': case 'X': /* The number is a json_parse_flags_allow_hexadecimal_numbers hexadecimal * so we have to do extra work to convert it to a non-hexadecimal for JSON * output. */ parsed_number = json_strtoumax(number->number, json_null, 0); /* We need a copy of parsed number twice, so take a backup of it. */ backup = parsed_number; i = 0; while (0 != parsed_number) { parsed_number /= 10; i++; } /* Restore parsed_number to its original value stored in the backup. */ parsed_number = backup; /* Now use backup to take a copy of i, or the length of the string. */ backup = i; do { *(data + i - 1) = '0' + (char)(parsed_number % 10); parsed_number /= 10; i--; } while (0 != parsed_number); data += backup; return data; } } /* check to see if the number has leading/trailing decimal point. */ i = 0; /* skip any leading '-'. */ if ((i < number->number_size) && (('+' == number->number[i]) || ('-' == number->number[i]))) { i++; } /* check if we have infinity. */ if ((i < number->number_size) && ('I' == number->number[i])) { const char *inf = "Infinity"; size_t k; for (k = i; k < number->number_size; k++) { const char c = *inf++; /* Check if we found the Infinity string! */ if ('\0' == c) { break; } else if (c != number->number[k]) { break; } } if ('\0' == *inf++) { const char *dbl_max; /* if we had a leading '-' we need to record it in the JSON output. */ if ('-' == number->number[0]) { *data++ = '-'; } /* Inf becomes 1.7976931348623158e308 because JSON can't support it. */ for (dbl_max = "1.7976931348623158e308"; '\0' != *dbl_max; dbl_max++) { *data++ = *dbl_max; } return data; } } /* check if we have nan. */ if ((i < number->number_size) && ('N' == number->number[i])) { const char *nan = "NaN"; size_t k; for (k = i; k < number->number_size; k++) { const char c = *nan++; /* Check if we found the NaN string! */ if ('\0' == c) { break; } else if (c != number->number[k]) { break; } } if ('\0' == *nan++) { /* NaN becomes 0 because JSON can't support it. */ *data++ = '0'; return data; } } /* if we had a leading decimal point. */ if ((i < number->number_size) && ('.' == number->number[i])) { i = 0; /* skip any leading '+'. */ if ('+' == number->number[i]) { i++; } /* output the leading '-' if we had one. */ if ('-' == number->number[i]) { *data++ = '-'; i++; } /* insert a '0' to fix the leading decimal point for JSON output. */ *data++ = '0'; /* and output the rest of the number as normal. */ for (; i < number->number_size; i++) { *data++ = number->number[i]; } return data; } for (; i < number->number_size; i++) { const char c = number->number[i]; if (!('0' <= c && c <= '9')) { break; } } /* if we had a trailing decimal point. */ if ((i + 1 == number->number_size) && ('.' == number->number[i])) { i = 0; /* skip any leading '+'. */ if ('+' == number->number[i]) { i++; } /* output the leading '-' if we had one. */ if ('-' == number->number[i]) { *data++ = '-'; i++; } /* and output the rest of the number as normal. */ for (; i < number->number_size; i++) { *data++ = number->number[i]; } /* insert a '0' to fix the trailing decimal point for JSON output. */ *data++ = '0'; return data; } i = 0; /* skip any leading '+'. */ if ('+' == number->number[i]) { i++; } for (; i < number->number_size; i++) { *data++ = number->number[i]; } return data; } json_weak char *json_write_string(const struct json_string_s *string, char *data); char *json_write_string(const struct json_string_s *string, char *data) { size_t i; *data++ = '"'; /* open the string. */ for (i = 0; i < string->string_size; i++) { switch (string->string[i]) { case '"': *data++ = '\\'; /* escape the control character. */ *data++ = '"'; break; case '\\': *data++ = '\\'; /* escape the control character. */ *data++ = '\\'; break; case '\b': *data++ = '\\'; /* escape the control character. */ *data++ = 'b'; break; case '\f': *data++ = '\\'; /* escape the control character. */ *data++ = 'f'; break; case '\n': *data++ = '\\'; /* escape the control character. */ *data++ = 'n'; break; case '\r': *data++ = '\\'; /* escape the control character. */ *data++ = 'r'; break; case '\t': *data++ = '\\'; /* escape the control character. */ *data++ = 't'; break; default: *data++ = string->string[i]; break; } } *data++ = '"'; /* close the string. */ return data; } json_weak char *json_write_minified_array(const struct json_array_s *array, char *data); char *json_write_minified_array(const struct json_array_s *array, char *data) { struct json_array_element_s *element = json_null; *data++ = '['; /* open the array. */ for (element = array->start; json_null != element; element = element->next) { if (element != array->start) { *data++ = ','; /* ','s seperate each element. */ } data = json_write_minified_value(element->value, data); if (json_null == data) { /* value was malformed! */ return json_null; } } *data++ = ']'; /* close the array. */ return data; } json_weak char *json_write_minified_object(const struct json_object_s *object, char *data); char *json_write_minified_object(const struct json_object_s *object, char *data) { struct json_object_element_s *element = json_null; *data++ = '{'; /* open the object. */ for (element = object->start; json_null != element; element = element->next) { if (element != object->start) { *data++ = ','; /* ','s seperate each element. */ } data = json_write_string(element->name, data); if (json_null == data) { /* string was malformed! */ return json_null; } *data++ = ':'; /* ':'s seperate each name/value pair. */ data = json_write_minified_value(element->value, data); if (json_null == data) { /* value was malformed! */ return json_null; } } *data++ = '}'; /* close the object. */ return data; } json_weak char *json_write_minified_value(const struct json_value_s *value, char *data); char *json_write_minified_value(const struct json_value_s *value, char *data) { switch (value->type) { default: /* unknown value type found! */ return json_null; case json_type_number: return json_write_number((struct json_number_s *)value->payload, data); case json_type_string: return json_write_string((struct json_string_s *)value->payload, data); case json_type_array: return json_write_minified_array((struct json_array_s *)value->payload, data); case json_type_object: return json_write_minified_object((struct json_object_s *)value->payload, data); case json_type_true: data[0] = 't'; data[1] = 'r'; data[2] = 'u'; data[3] = 'e'; return data + 4; case json_type_false: data[0] = 'f'; data[1] = 'a'; data[2] = 'l'; data[3] = 's'; data[4] = 'e'; return data + 5; case json_type_null: data[0] = 'n'; data[1] = 'u'; data[2] = 'l'; data[3] = 'l'; return data + 4; } } void *json_write_minified(const struct json_value_s *value, size_t *out_size) { size_t size = 0; char *data = json_null; char *data_end = json_null; if (json_null == value) { return json_null; } if (json_write_minified_get_value_size(value, &size)) { /* value was malformed! */ return json_null; } size += 1; /* for the '\0' null terminating character. */ data = (char *)malloc(size); if (json_null == data) { /* malloc failed! */ return json_null; } data_end = json_write_minified_value(value, data); if (json_null == data_end) { /* bad chi occurred! */ free(data); return json_null; } /* null terminated the string. */ *data_end = '\0'; if (json_null != out_size) { *out_size = size; } return data; } json_weak int json_write_pretty_get_value_size(const struct json_value_s *value, size_t depth, size_t indent_size, size_t newline_size, size_t *size); json_weak int json_write_pretty_get_array_size(const struct json_array_s *array, size_t depth, size_t indent_size, size_t newline_size, size_t *size); int json_write_pretty_get_array_size(const struct json_array_s *array, size_t depth, size_t indent_size, size_t newline_size, size_t *size) { struct json_array_element_s *element; *size += 1; /* '['. */ if (0 < array->length) { /* if we have any elements we need to add a newline after our '['. */ *size += newline_size; *size += array->length - 1; /* ','s seperate each element. */ for (element = array->start; json_null != element; element = element->next) { /* each element gets an indent. */ *size += (depth + 1) * indent_size; if (json_write_pretty_get_value_size(element->value, depth + 1, indent_size, newline_size, size)) { /* value was malformed! */ return 1; } /* each element gets a newline too. */ *size += newline_size; } /* since we wrote out some elements, need to add a newline and indentation. */ /* to the trailing ']'. */ *size += depth * indent_size; } *size += 1; /* ']'. */ return 0; } json_weak int json_write_pretty_get_object_size(const struct json_object_s *object, size_t depth, size_t indent_size, size_t newline_size, size_t *size); int json_write_pretty_get_object_size(const struct json_object_s *object, size_t depth, size_t indent_size, size_t newline_size, size_t *size) { struct json_object_element_s *element; *size += 1; /* '{'. */ if (0 < object->length) { *size += newline_size; /* need a newline next. */ *size += object->length - 1; /* ','s seperate each element. */ for (element = object->start; json_null != element; element = element->next) { /* each element gets an indent and newline. */ *size += (depth + 1) * indent_size; *size += newline_size; if (json_write_get_string_size(element->name, size)) { /* string was malformed! */ return 1; } *size += 3; /* seperate each name/value pair with " : ". */ if (json_write_pretty_get_value_size(element->value, depth + 1, indent_size, newline_size, size)) { /* value was malformed! */ return 1; } } *size += depth * indent_size; } *size += 1; /* '}'. */ return 0; } json_weak int json_write_pretty_get_value_size(const struct json_value_s *value, size_t depth, size_t indent_size, size_t newline_size, size_t *size); int json_write_pretty_get_value_size(const struct json_value_s *value, size_t depth, size_t indent_size, size_t newline_size, size_t *size) { switch (value->type) { default: /* unknown value type found! */ return 1; case json_type_number: return json_write_get_number_size((struct json_number_s *)value->payload, size); case json_type_string: return json_write_get_string_size((struct json_string_s *)value->payload, size); case json_type_array: return json_write_pretty_get_array_size( (struct json_array_s *)value->payload, depth, indent_size, newline_size, size); case json_type_object: return json_write_pretty_get_object_size( (struct json_object_s *)value->payload, depth, indent_size, newline_size, size); case json_type_true: *size += 4; /* the string "true". */ return 0; case json_type_false: *size += 5; /* the string "false". */ return 0; case json_type_null: *size += 4; /* the string "null". */ return 0; } } json_weak char *json_write_pretty_value(const struct json_value_s *value, size_t depth, const char *indent, const char *newline, char *data); json_weak char *json_write_pretty_array(const struct json_array_s *array, size_t depth, const char *indent, const char *newline, char *data); char *json_write_pretty_array(const struct json_array_s *array, size_t depth, const char *indent, const char *newline, char *data) { size_t k, m; struct json_array_element_s *element; *data++ = '['; /* open the array. */ if (0 < array->length) { for (k = 0; '\0' != newline[k]; k++) { *data++ = newline[k]; } for (element = array->start; json_null != element; element = element->next) { if (element != array->start) { *data++ = ','; /* ','s seperate each element. */ for (k = 0; '\0' != newline[k]; k++) { *data++ = newline[k]; } } for (k = 0; k < depth + 1; k++) { for (m = 0; '\0' != indent[m]; m++) { *data++ = indent[m]; } } data = json_write_pretty_value(element->value, depth + 1, indent, newline, data); if (json_null == data) { /* value was malformed! */ return json_null; } } for (k = 0; '\0' != newline[k]; k++) { *data++ = newline[k]; } for (k = 0; k < depth; k++) { for (m = 0; '\0' != indent[m]; m++) { *data++ = indent[m]; } } } *data++ = ']'; /* close the array. */ return data; } json_weak char *json_write_pretty_object(const struct json_object_s *object, size_t depth, const char *indent, const char *newline, char *data); char *json_write_pretty_object(const struct json_object_s *object, size_t depth, const char *indent, const char *newline, char *data) { size_t k, m; struct json_object_element_s *element; *data++ = '{'; /* open the object. */ if (0 < object->length) { for (k = 0; '\0' != newline[k]; k++) { *data++ = newline[k]; } for (element = object->start; json_null != element; element = element->next) { if (element != object->start) { *data++ = ','; /* ','s seperate each element. */ for (k = 0; '\0' != newline[k]; k++) { *data++ = newline[k]; } } for (k = 0; k < depth + 1; k++) { for (m = 0; '\0' != indent[m]; m++) { *data++ = indent[m]; } } data = json_write_string(element->name, data); if (json_null == data) { /* string was malformed! */ return json_null; } /* " : "s seperate each name/value pair. */ *data++ = ' '; *data++ = ':'; *data++ = ' '; data = json_write_pretty_value(element->value, depth + 1, indent, newline, data); if (json_null == data) { /* value was malformed! */ return json_null; } } for (k = 0; '\0' != newline[k]; k++) { *data++ = newline[k]; } for (k = 0; k < depth; k++) { for (m = 0; '\0' != indent[m]; m++) { *data++ = indent[m]; } } } *data++ = '}'; /* close the object. */ return data; } json_weak char *json_write_pretty_value(const struct json_value_s *value, size_t depth, const char *indent, const char *newline, char *data); char *json_write_pretty_value(const struct json_value_s *value, size_t depth, const char *indent, const char *newline, char *data) { switch (value->type) { default: /* unknown value type found! */ return json_null; case json_type_number: return json_write_number((struct json_number_s *)value->payload, data); case json_type_string: return json_write_string((struct json_string_s *)value->payload, data); case json_type_array: return json_write_pretty_array((struct json_array_s *)value->payload, depth, indent, newline, data); case json_type_object: return json_write_pretty_object((struct json_object_s *)value->payload, depth, indent, newline, data); case json_type_true: data[0] = 't'; data[1] = 'r'; data[2] = 'u'; data[3] = 'e'; return data + 4; case json_type_false: data[0] = 'f'; data[1] = 'a'; data[2] = 'l'; data[3] = 's'; data[4] = 'e'; return data + 5; case json_type_null: data[0] = 'n'; data[1] = 'u'; data[2] = 'l'; data[3] = 'l'; return data + 4; } } void *json_write_pretty(const struct json_value_s *value, const char *indent, const char *newline, size_t *out_size) { size_t size = 0; size_t indent_size = 0; size_t newline_size = 0; char *data = json_null; char *data_end = json_null; if (json_null == value) { return json_null; } if (json_null == indent) { indent = " "; /* default to two spaces. */ } if (json_null == newline) { newline = "\n"; /* default to linux newlines. */ } while ('\0' != indent[indent_size]) { ++indent_size; /* skip non-null terminating characters. */ } while ('\0' != newline[newline_size]) { ++newline_size; /* skip non-null terminating characters. */ } if (json_write_pretty_get_value_size(value, 0, indent_size, newline_size, &size)) { /* value was malformed! */ return json_null; } size += 1; /* for the '\0' null terminating character. */ data = (char *)malloc(size); if (json_null == data) { /* malloc failed! */ return json_null; } data_end = json_write_pretty_value(value, 0, indent, newline, data); if (json_null == data_end) { /* bad chi occurred! */ free(data); return json_null; } /* null terminated the string. */ *data_end = '\0'; if (json_null != out_size) { *out_size = size; } return data; } #if defined(__clang__) #pragma clang diagnostic pop #elif defined(_MSC_VER) #pragma warning(pop) #endif #endif /* SHEREDOM_JSON_H_INCLUDED. */ ================================================ FILE: patch/macro.h ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once //#define PATCH_INTERNAL #define PATCH_VERSION_NAME "patch.aul " PATCH_VERSION_STR #ifdef PATCH_INTERNAL #define PATCH_VERSION_STR "internal build:" __DATE__ " " __TIME__ "" #define PATCH_SWITCH_EXCEPTION_LOG #define PATCH_SWITCH_SYSINFO_MODIFY #define PATCH_SWITCH_TRANSRATE #define PATCH_SWITCH_SETTING_GUI #define PATCH_SWITCH_ACCESS_KEY access_key #define PATCH_SWITCH_FILEINFO file_info #define PATCH_SWITCH_SUSIE_LOAD susie_load #define PATCH_SWITCH_SPLASH splash #define PATCH_SWITCH_TRA_AVIUTL_FILTER tra_aviutl_filter #define PATCH_SWITCH_EXO_AVIUTL_FILTER exo_aviutl_filter #define PATCH_SWITCH_EXO_TRACK_MINUSVAL exo_track_minusval #define PATCH_SWITCH_EXO_SCENEIDX exo_sceneidx #define PATCH_SWITCH_EXO_TRACKPARAM exo_trackparam #define PATCH_SWITCH_EXO_SPECIALCOLORCONV exo_specialcolorconv #define PATCH_SWITCH_TEXT_OP_SIZE text_op_size #define PATCH_SWITCH_IGNORE_MEDIA_PARAM_RESET ignore_media_param_reset #define PATCH_SWITCH_FONT_DIALOG font_dialog #define PATCH_SWITCH_SCROLL_OBJDLG scroll_objdlg #define PATCH_SWITCH_ALPHA_BG alpha_bg #define PATCH_SWITCH_HELPFUL_MSGBOX helpful_msgbox #define PATCH_SWITCH_THEME_CC theme_cc #define PATCH_SWITCH_EXEDITWINDOW_SIZING exeditwindow_sizing #define PATCH_SWITCH_SETTINGDIALOG_MOVE settingdialog_move #define PATCH_SWITCH_SETTINGDIALOG_EXCOLORCONFIG settingdialog_excolorconfig #define PATCH_SWITCH_UNDO undo #ifdef PATCH_SWITCH_UNDO #define PATCH_SWITCH_UNDO_REDO undo_redo #endif #define PATCH_SWITCH_CONSOLE console #ifdef PATCH_SWITCH_CONSOLE #define PATCH_SWITCH_DEBUGSTRING console_debug_string #endif // ifdef PATCH_SWITCH_CONSOLE #define PATCH_SWITCH_LUA lua #ifdef PATCH_SWITCH_LUA #define PATCH_SWITCH_LUA_ENV lua_env #define PATCH_SWITCH_LUA_GETVALUE lua_getvalueex #define PATCH_SWITCH_LUA_RAND lua_rand #define PATCH_SWITCH_LUA_RANDEX lua_randex #define PATCH_SWITCH_LUA_PATH lua_path //#define PATCH_SWITCH_LUA_COPYBUFFER_SMEM lua_copybuffer_smem #endif // ifdef PATCH_SWITCH_LUA #define PATCH_SWITCH_FAST fast #ifdef PATCH_SWITCH_FAST #define PATCH_SWITCH_FAST_GETPUTPIXELDATA fast_getputpixeldata #define PATCH_SWITCH_FAST_SETTINGDIALOG fast_settingdialog #define PATCH_SWITCH_FAST_EXEDITWINDOW fast_exeditwindow #define PATCH_SWITCH_CL cl #ifdef PATCH_SWITCH_CL #define PATCH_SWITCH_FAST_POLORTRANSFORM fast_polortransform #define PATCH_SWITCH_FAST_RADIATIONALBLUR fast_radiationalblur #define PATCH_SWITCH_FAST_FLASH fast_flash #endif // define PATCH_SWITCH_CL #endif //define PATCH_SWITCH_FAST #else // ifdef PATCH_INTERNAL #define PATCH_VERSION_STR "r43 beta1" #define PATCH_SWITCH_EXCEPTION_LOG #define PATCH_SWITCH_SYSINFO_MODIFY #define PATCH_SWITCH_ACCESS_KEY access_key #define PATCH_SWITCH_COLORPALETTE_CACHE colorpalette_cache #define PATCH_SWITCH_TRA_AVIUTL_FILTER tra_aviutl_filter #define PATCH_SWITCH_TRA_CHANGE_DRAWFILTER tra_change_drawfilter #define PATCH_SWITCH_TRA_SPECIFIED_SPEED tra_specified_speed #define PATCH_SWITCH_AUP_SCENE_SETTING aup_scene_setting #define PATCH_SWITCH_AUP_LAYER_SETTING aup_layer_setting #define PATCH_SWITCH_EXO_AVIUTL_FILTER exo_aviutl_filter #define PATCH_SWITCH_EXO_TRACK_MINUSVAL exo_track_minusval #define PATCH_SWITCH_EXO_SCENEIDX exo_sceneidx #define PATCH_SWITCH_EXO_TRACKPARAM exo_trackparam #define PATCH_SWITCH_EXO_MIDPT_AND_TRA exo_midpt_tra #define PATCH_SWITCH_EXO_SPECIALCOLORCONV exo_specialcolorconv #define PATCH_SWITCH_EXO_FOLD_GUI exo_fold_gui #define PATCH_SWITCH_TEXT_OP_SIZE text_op_size #define PATCH_SWITCH_IGNORE_MEDIA_PARAM_RESET ignore_media_param_reset #define PATCH_SWITCH_THEME_CC theme_cc #define PATCH_SWITCH_EXEDITWINDOW_SIZING exeditwindow_sizing #define PATCH_SWITCH_SETTINGDIALOG_MOVE settingdialog_move #define PATCH_SWITCH_SETTINGDIALOG_EXCOLORCONFIG settingdialog_excolorconfig #define PATCH_SWITCH_CANCEL_BOOST_CONFLICT #define PATCH_SWITCH_WARNING_OLD_LSW #define PATCH_SWITCH_FAILED_SJIS_MSGBOX failed_sjis #define PATCH_SWITCH_FAILED_LONGER_PATH failed_longpath #define PATCH_SWITCH_FAILED_FILE_DROP failed_filedrop #define PATCH_SWITCH_OBJ_COLORCORRECTION obj_colorcorrection #define PATCH_SWITCH_OBJ_GLOW obj_glow #define PATCH_SWITCH_OBJ_LENSBLUR obj_lensblur #define PATCH_SWITCH_OBJ_NOISE obj_noise #define PATCH_SWITCH_OBJ_SPECIALCOLORCONV obj_specialcolorconv #define PATCH_SWITCH_RCLICKMENU_SPLIT rclickmenu_split #define PATCH_SWITCH_RCLICKMENU_DELETE rclickmenu_delete #define PATCH_SWITCH_BLEND blend #define PATCH_SWITCH_ADD_EXTENSION add_extension #define PATCH_SWITCH_DIALOG_NEW_FILE dlg_newfile #define PATCH_SWITCH_PLAYBACK_SPEED pb_speed #define PATCH_SWITCH_SETTING_NEW_PROJECT setting_newproject #define PATCH_SWITCH_UNDO undo #ifdef PATCH_SWITCH_UNDO #define PATCH_SWITCH_UNDO_REDO undo_redo #ifdef PATCH_SWITCH_UNDO_REDO #define PATCH_SWITCH_UNDO_REDO_SHIFT undo_redo_shift #endif #endif #define PATCH_SWITCH_CONSOLE console #ifdef PATCH_SWITCH_CONSOLE #define PATCH_SWITCH_DEBUGSTRING console_debug_string #endif // ifdef PATCH_SWITCH_CONSOLE #define PATCH_SWITCH_LUA lua #ifdef PATCH_SWITCH_LUA #define PATCH_SWITCH_LUA_ENV lua_env #define PATCH_SWITCH_LUA_GETVALUE lua_getvalue #define PATCH_SWITCH_LUA_RAND lua_rand #define PATCH_SWITCH_LUA_RANDEX lua_randex #define PATCH_SWITCH_LUA_PATH lua_path //#define PATCH_SWITCH_LUA_COPYBUFFER_SMEM lua_copybuffer_smem #endif // ifdef PATCH_SWITCH_LUA #define PATCH_SWITCH_FAST fast #ifdef PATCH_SWITCH_FAST #define PATCH_SWITCH_FAST_SETTINGDIALOG fast_settingdialog #define PATCH_SWITCH_FAST_EXEDITWINDOW fast_exeditwindow #define PATCH_SWITCH_FAST_TEXT fast_text #define PATCH_SWITCH_FAST_CREATE_FIGURE fast_create_figure #define PATCH_SWITCH_FAST_BORDER fast_border #define PATCH_SWITCH_FAST_GLOW fast_glow #define PATCH_SWITCH_CL cl #ifdef PATCH_SWITCH_CL #define PATCH_SWITCH_FAST_POLORTRANSFORM fast_polortransform #define PATCH_SWITCH_FAST_DISPLACEMENTMAP fast_displacementmap #define PATCH_SWITCH_FAST_RADIATIONALBLUR fast_radiationalblur #define PATCH_SWITCH_FAST_FLASH fast_flash #define PATCH_SWITCH_FAST_DIRECTIONALBLUR fast_directionalblur #define PATCH_SWITCH_FAST_LENSBLUR fast_lensblur #endif // define PATCH_SWITCH_CL #endif //define PATCH_SWITCH_FAST #endif // ifdef PATCH_INTERNAL #define PATCH_SWITCHER_DEFINE_STRING(s) #s #define PATCH_SWITCHER_DEFINE_STRINGX(s) PATCH_SWITCHER_DEFINE_STRING(s) #define PATCH_SWITCHER_DEFINE_VALUE(s) s #define PATCH_SWITCHER_KEY_JOINNER(a, b) a ## b #define PATCH_SWITCHER_KEY_JOINNERX(a, b) PATCH_SWITCHER_KEY_JOINNER(a, b) #define PATCH_SWITCHER_DEFINE(name, def) bool name = def; inline static constexpr const char PATCH_SWITCHER_KEY_JOINNER(key_, name)[] = PATCH_SWITCHER_DEFINE_STRING(name); #define PATCH_SWITCHER_DEFINE_EX(name, def, key) bool name = def; inline static constexpr const char PATCH_SWITCHER_KEY_JOINNER(key_, name)[] = PATCH_SWITCHER_DEFINE_STRING(key); #define PATCH_SWITCHER_IF(name) if (load_variable(elm, PATCH_SWITCHER_KEY_JOINNER(key_, name), name)) continue; #define PATCH_SWITCHER_STORE(name) tj(PATCH_SWITCHER_KEY_JOINNER(key_, name), name); #define PATCH_SWITCHER_MEMBER(name) GLOBAL::config.switcher.name ================================================ FILE: patch/moduledata.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include "hash.hpp" struct ModulesDataEntry { uintptr_t begin; uintptr_t end; std::string name; std::optional hash; }; inline static std::pair, std::string_view> getModulesData() { std::vector ret; auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, NULL); if (snapshot != INVALID_HANDLE_VALUE) { MODULEENTRY32 entry{ .dwSize = sizeof(MODULEENTRY32) }; if (Module32First(snapshot, &entry)) { do { ret.emplace_back( reinterpret_cast(entry.modBaseAddr), reinterpret_cast(entry.modBaseAddr) + static_cast(entry.modBaseSize), entry.szModule, SHA256::make_opt(entry.szExePath) ); } while (Module32Next(snapshot, &entry)); CloseHandle(snapshot); } else { auto err = GetLastError(); CloseHandle(snapshot); return { ret,"LastError:{}"_fmt(err) }; } } else { auto err = GetLastError(); CloseHandle(snapshot); return { ret,"LastError:{}"_fmt(err) }; } std::sort(ret.begin(), ret.end(), [](auto a, auto b) { return a.begin < b.begin; }); return { ret, "" }; } inline std::weak_ordering operator<=>(const ModulesDataEntry& a, const ModulesDataEntry& b) { return a.begin <=> b.begin; } class ModulesData { inline static std::vector modules_data_cache; inline static std::set modules_data_cache_name; public: inline static std::mutex mtx; static void update() { auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, NULL); if (snapshot != INVALID_HANDLE_VALUE) { MODULEENTRY32 entry{ .dwSize = sizeof(MODULEENTRY32) }; if (Module32First(snapshot, &entry)) { do { if (!modules_data_cache_name.contains(entry.szModule)) { modules_data_cache_name.insert(entry.szModule); modules_data_cache.emplace_back( reinterpret_cast(entry.modBaseAddr), reinterpret_cast(entry.modBaseAddr) + static_cast(entry.modBaseSize), entry.szModule, SHA256::make_opt(entry.szExePath) ); } } while (Module32Next(snapshot, &entry)); CloseHandle(snapshot); } else { auto err = GetLastError(); CloseHandle(snapshot); } } else { auto err = GetLastError(); CloseHandle(snapshot); } } static const auto& get() { if (!std::is_sorted(modules_data_cache.cbegin(), modules_data_cache.cend(), [](auto a, auto b) { return a.begin < b.begin; })) { std::sort(modules_data_cache.begin(), modules_data_cache.end(), [](auto a, auto b) { return a.begin < b.begin; }); } return modules_data_cache; } }; ================================================ FILE: patch/multi_threading.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include #include #include #include inline class { inline static std::once_flag init_flag; inline static size_t thread_num; static void init() { SYSTEM_INFO info; GetSystemInfo(&info); thread_num = info.dwNumberOfProcessors; } public: template, std::nullptr_t> = nullptr> inline void operator()(T func) const { std::call_once(init_flag, init); std::vector threads; for (size_t i = 0; i < thread_num; i++) threads.emplace_back(func, i, thread_num); for (auto&& t : threads) t.join(); } auto get_thread_num() const { std::call_once(init_flag, init); return thread_num; } } multi_threading; ================================================ FILE: patch/mylua.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "global.hpp" /* patch内でluaを使うとき用のコード群 */ using lua_State = struct lua_State; using lua_Number = double; using lua_Integer = ptrdiff_t; using lua_CFunction = int(__cdecl*)(lua_State* L); using lua_Reader = const char* (__cdecl*)(lua_State* L, void* data, size_t* size); using lua_Writer = int(__cdecl*)(lua_State* L, const void* data, size_t sz, void* ud); constexpr const int LUA_REGISTRYINDEX = -10000; constexpr const int LUA_ENVIRONINDEX = -10001; constexpr const int LUA_GLOBALSINDEX = -10002; constexpr auto lua_upvalueindex(int i) { return LUA_GLOBALSINDEX - i; } enum { LUA_TNONE = -1, LUA_TNIL = 0, LUA_TBOOLEAN = 1, LUA_TLIGHTUSERDATA = 2, LUA_TNUMBER = 3, LUA_TSTRING = 4, LUA_TTABLE = 5, LUA_TFUNCTION = 6, LUA_TUISERDATA = 7, LUA_TTHREAD = 8, }; enum { LUA_YIELD = 1, LUA_ERRRUN = 2, LUA_ERRSYNTAX = 3, LUA_ERRMEM = 4, LUA_ERRERR = 5, }; struct luaL_Reg { const char* name; lua_CFunction* func; }; #define defluafunc(offset, ret, ...) (*reinterpret_cast(GLOBAL::exedit_base + offset)) #define lua_close defluafunc(0x1b24ac, void, lua_State*) #define lua_createtable defluafunc(0x1b2b30, void, lua_State*, int, int) #define lua_getfield defluafunc(0x1bacc8, void, lua_State*, int, const char*) #define lua_gettable defluafunc(0x1bab68, void, lua_State*, int) #define lua_gettop defluafunc(0x1b23ac, int, lua_State*) #define lua_isnumber defluafunc(0x1b2b38, int, lua_State*, int) #define lua_isuserdata defluafunc(0x1b24a4, int, lua_State*, int) #define lua_newuserdata defluafunc(0x1b248c, void*, lua_State*, size_t) #define lua_pcall defluafunc(0x1bac8c, int, lua_State*, int, int, int) #define lua_pushboolean defluafunc(0x1b2b44, void*, lua_State*, int) #define lua_pushinteger defluafunc(0x1bab78, void*, lua_State*, int) #define lua_pushlightuserdata defluafunc(0x1b2b00, void, lua_State*, void*) #define lua_pushnil defluafunc(0x1b23c0, void, lua_State*) #define lua_pushnumber defluafunc(0x1b28d8, void, lua_State*, lua_Number) #define lua_pushstring defluafunc(0x1b28e0, void, lua_State*, const char*) #define lua_setfield defluafunc(0x1bab5c, void, lua_State*, int, const char*) #define lua_sethook defluafunc(0x1b23b4, int, lua_State*, lua_Hook, int, int) #define lua_settable defluafunc(0x1b2320, void, lua_State*, int) #define lua_settop defluafunc(0x1b23c4, void, lua_State*, int) #define lua_toboolean defluafunc(0x1b2b14, int, lua_State*, int) #define lua_tointeger defluafunc(0x1b29f0, lua_Integer, lua_State*, int) #define lua_tolstring defluafunc(0x1b21ec, const char*, lua_State*, int, size_t*) #define lua_tonumber defluafunc(0x1b21e8, lua_Number, lua_State*, int) #define lua_touserdata defluafunc(0x1b2490, void*, lua_State*, int) #define lua_type defluafunc(0x1bab70, int, lua_State*, int) #define luaL_checkinteger defluafunc(0x1b2b48, lua_Integer, lua_State*, int) #define luaL_checklstring defluafunc(0x1bacb4, const char*, lua_State*, int, size_t*) #define luaL_checknumber defluafunc(0x1b220c, lua_Number, lua_State*, int) #define luaL_error defluafunc(0x1b2488, int, lua_State*, const char*, ...) #define luaL_loadstring defluafunc(0x1b2b1c, int, lua_State*, const char*) #define luaL_newstate defluafunc(0x1b2208, lua_State*, void) #define luaL_openlibs defluafunc(0x1b28e4, void, lua_State*) #define luaL_register defluafunc(0x1b2b24, void, lua_State*, const char*, luaL_Reg*) inline int(__cdecl* lua_isstring)(lua_State* L, int idx); inline void(__cdecl* lua_pushcclosure)(lua_State* L, lua_CFunction fn, int n); inline void(__cdecl* lua_remove)(lua_State* L, int index); inline void(__cdecl* lua_setmetatable)(lua_State* L, int index); inline int(__cdecl* luaL_newmetatable)(lua_State* L, const char* tname); inline void(__cdecl* lua_pushvalue)(lua_State* L, int index); inline bool lua_isfunction(lua_State* L, int index) { return lua_type(L, index) == LUA_TFUNCTION; } inline bool lua_istable(lua_State* L, int index) { return lua_type(L, index) == LUA_TTABLE; } inline bool lua_islightuserdata(lua_State* L, int index) { return lua_type(L, index) == LUA_TLIGHTUSERDATA; } inline bool lua_isnil(lua_State* L, int index) { return lua_type(L, index) == LUA_TNIL; } inline bool lua_isboolean(lua_State* L, int index) { return lua_type(L, index) == LUA_TBOOLEAN; } inline bool lua_isthread(lua_State* L, int index) { return lua_type(L, index) == LUA_TTHREAD; } inline bool lua_isnone(lua_State* L, int index) { return lua_type(L, index) == LUA_TNONE; } inline bool lua_isnoneornil(lua_State* L, int index) { return lua_type(L, index) <= 0; } //template inline auto lua_pushliteral(lua_State* L, const char(&s)[N]) { return lua_pushlstring(L, s, N); } inline auto lua_tostring(lua_State* L, int i) { return lua_tolstring(L, i, nullptr); } inline auto luaL_checkstring(lua_State* L, int i) { return luaL_checklstring(L, i, nullptr); } inline auto lua_pushcfunction(lua_State* L, lua_CFunction f) { return lua_pushcclosure(L, f, 0); } inline auto lua_pop(lua_State* L, int n) { return lua_settop(L, -n - 1); } inline auto lua_setglobal(lua_State* L, const char* s) { return lua_setfield(L, LUA_GLOBALSINDEX, s); } inline auto lua_getglobal(lua_State* L, const char* s) { return lua_getfield(L, LUA_GLOBALSINDEX, s); } inline auto lua_newtable(lua_State* L) { return lua_createtable(L, 0, 0); } inline auto luaL_getmetatable(lua_State* L, const char* tname) { return lua_getfield(L, LUA_REGISTRYINDEX, tname); } ================================================ FILE: patch/mywindow.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "util_resource.hpp" #include "patch_exo_trackminusval.hpp" // playground inline class mywindow_t { HMENU hmenu; HWND hwnd; inline static LRESULT CALLBACK wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { if (message != WM_COMMAND) return DefWindowProc(hwnd, message, wparam, lparam); switch (LOWORD(wparam)) { case 10000: { patch::exo_trackminusval.switching(false); return FALSE; } case 10001: { patch::exo_trackminusval.switching(true); return FALSE; } } return DefWindowProc(hwnd, message, wparam, lparam); } public: #if _DEBUG ~mywindow_t() { DestroyWindow(hwnd); DestroyMenu(hmenu); } void init() { hmenu = CreateMenu(); InsertMenuA(hmenu, -1, MF_BYPOSITION | MF_STRING, 10000, "switch"); InsertMenuA(hmenu, -1, MF_BYPOSITION | MF_STRING, 10001, "switch2"); hwnd = CreateWindowA("STATIC", "patchhhhhhhh", 0, 0, 0, 1000, 500, NULL, hmenu, GLOBAL::patchaul_hinst, NULL); SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)&wndproc); ShowWindow(hwnd, SW_SHOWNORMAL); } #else void init() {} #endif }mywindow; ================================================ FILE: patch/offset_address.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "util_int.hpp" namespace OFS { namespace AviUtl { constexpr i32 InitAuf = 0x02c930; constexpr i32 VersionString = 0x07425c; constexpr i32 default_resource_hmod = 0x2c525c; constexpr i32 getsys_versionstr_arg = 0x022187; constexpr i32 current_resource_hmod = 0x2d910c; constexpr i32 edit_handle_ptr = 0x08717c; constexpr i32 saveProjectFile = 0x024160; constexpr i32 str_dot_avi = 0x0745fc; // ".avi" constexpr i32 filter_clipping_and_resize_ptr = 0x07ad58; } namespace ExEdit { constexpr i32 exedit_fp = 0x14d4b4; constexpr i32 aviutl_hwnd = 0x135c6c; constexpr i32 exedit_hwnd = 0x177a44; constexpr i32 settingdialog_hwnd = 0x1539c8; constexpr i32 blend_yca_normal_func = 0x007df0; constexpr i32 blend_yc_normal_func = 0x007f20; constexpr i32 ConvertFilter2Exo_TrackScaleJudge_RangeBegin = 0x028a8d; constexpr i32 ConvertFilter2Exo_TrackScaleJudge_Overwrite1 = 0x028a84; constexpr i32 ConvertFilter2Exo_TrackScaleJudge_Overwrite2 = 0x0289cb; constexpr i32 ConvertFilter2Exo_TrackScaleJudge_Overwrite3 = 0x028a00; constexpr i32 efSceneAudio_exdatause_idx_type = 0x0aeb5c; constexpr i32 efSceneAudio_exdatause_idx_name = 0x0aeb60; constexpr i32 efScene_exdatause_idx_name = 0x0ae9b0; constexpr i32 exo_readtrack = 0x029090; constexpr i32 str2int2 = 0x0918ab; constexpr i32 exo_trackparam_overwrite = 0x0299d1; constexpr i32 efpip_g = 0x1b2b20; constexpr i32 getpixeldata = 0x09a65c; constexpr i32 rgb2yc = 0x06fed0; constexpr i32 exedit_max_h_add8 = 0x135c64; constexpr i32 exedit_buffer_line = 0x135c68; constexpr i32 exedit_YC_vram_w = 0x149840; constexpr i32 exedit_YC_vram_h = 0x14ca4c; constexpr i32 exedit_max_w = 0x196748; constexpr i32 exedit_max_h = 0x1920e0; constexpr i32 memory_ptr = 0x01a5328; constexpr i32 CreateFigure_var_ptr = 0x1e4798; constexpr i32 CreateFigure_circle_func_call = 0x073882; constexpr i32 CreateFigure_circle_func_mt_call = 0x0738ac; constexpr i32 CreateFigure_polygons_func_call = 0x073949; constexpr i32 CreateFigure_polygons_func_mt_call = 0x07395b; constexpr i32 efBorder_func_proc_var_ptr = 0x0a5d28; constexpr i32 efBorder_func_proc_ptr = 0x0515d0; constexpr i32 efBorder_var_ptr = 0x1b1e30; constexpr i32 efGlow_var_ptr = 0x1b2010; constexpr i32 efPolorTransform_func_proc = 0x0748a0; constexpr i32 efPolorTransform_func_proc_ptr = 0x0add30; constexpr i32 efPolorTransform_mt_func_call = 0x074a62; constexpr i32 efPolorTransform_var_ptr = 0x1e48c0; constexpr i32 efDisplacementMap_mt_func_call = 0x01f154; constexpr i32 efDisplacementMap_var_ptr = 0x11effc; constexpr i32 efRadiationalBlur_func_proc = 0x00b310; constexpr i32 efRadiationalBlur_func_proc_ptr = 0x09fdb0; constexpr i32 efRadiationalBlur_var_ptr = 0x0d75a8; constexpr i32 efFlash_func_proc = 0x04e560; constexpr i32 efFlash_var_ptr = 0x1a6b7c; constexpr i32 efFlash_func_proc_ptr = 0x0a5a28; constexpr i32 efDirectionalBlur_func_proc_ptr = 0x0a00a0; constexpr i32 efDirectionalBlur_var_ptr = 0x0d75cc; constexpr i32 efDirectionalBlur_Filter_mt_func_call = 0x00cae6; constexpr i32 efLensBlur_Media_mt_func_call = 0x012761; constexpr i32 efLensBlur_Filter_mt_func_call = 0x012786; constexpr i32 efLensBlur_var_ptr = 0x11ec5c; constexpr i32 ScriptProcessingFilter = 0x1b2b10; constexpr i32 ini_extension_buf = 0x14cb58; constexpr i32 str_DOUGAFILE = 0x09df6c; // "動画ファイル" constexpr i32 str_ONSEIFILE = 0x0ba698; // "音声ファイル" constexpr i32 exedit_edit_open = 0x03ac30; constexpr i32 exfunc_10 = 0x04abe0; constexpr i32 exfunc_08 = 0x04ab40; constexpr i32 func_0x047ad0 = 0x047ad0; constexpr i32 exfunc_64 = 0x04d040; constexpr i32 scenechange_progress_times4096 = 0x230c60; constexpr i32 exfunc_1c = 0x04ade0; constexpr i32 GetCurrentProcessing = 0x047ba0; constexpr i32 LoadedFilterTable = 0x187c98; constexpr i32 splitted_object_new_group_belong = 0x034f90; constexpr i32 DrawTimelineMask = 0x0392f0; constexpr i32 disp_settingdialog = 0x039550; constexpr i32 filter_sendmessage = 0x04a1a0; constexpr i32 get_near_object_idx = 0x0445a0; constexpr i32 TraScript_ProcessingObjectIndex = 0x1b2b04; constexpr i32 TraScript_ProcessingTrackBarIndex = 0x1b21f4; constexpr i32 TraScript_Time = 0x1b28c8; constexpr i32 LoadLua = 0x0646e0; constexpr i32 hmodule_lua = 0x1bac9c; constexpr i32 luaL_Reg_global_table = 0x09a680; constexpr i32 luaL_Reg_obj_table = 0x09a5c0; constexpr i32 exeditdir = 0x1b2b18; constexpr i32 sScriptFolderName = 0x1b2b4c; constexpr i32 l_effect = 0x05d0a0; constexpr i32 l_load = 0x05ef50; constexpr i32 l_draw = 0x05e250; constexpr i32 l_drawpoly = 0x05e680; constexpr i32 l_setanchor = 0x0625e0; constexpr i32 GetOrCreateLuaState = 0x064660; constexpr i32 LuaUnload = 0x064e90; constexpr i32 SetLuaPathAndCpath = 0x064550; constexpr i32 DoScriptInit = 0x0641a0; constexpr i32 DoScriptExit = 0x064250; constexpr i32 luastateidx = 0x1baccc; constexpr i32 lua_pop_nop = 0x064d15; constexpr i32 lua_set_nop = 0x06442a; constexpr i32 lua_tonumber_arg = 0x064d64; constexpr i32 lua_tostring_calling1 = 0x064d44; constexpr i32 lua_tostring_calling2 = 0x06448b; constexpr i32 lua_tostring_calling3 = 0x064449; constexpr i32 OutputDebugString_calling_err1 = 0x064453; constexpr i32 OutputDebugString_calling_err2 = 0x064495; constexpr i32 OutputDebugString_calling_err3 = 0x064d4e; constexpr i32 OutputDebugString_calling_dbg = 0x05d099; constexpr i32 ignore_media_param_reset_mov = 0x00674d; constexpr i32 ignore_media_param_reset_aud = 0x090116; constexpr i32 ExtendedFilter_wndcls = 0x02e872; constexpr i32 loaded_spi_array = 0x2321f0; constexpr i32 MyFindFirstFile = 0x04e220; constexpr i32 MyFindNextFile = 0x04e270; constexpr i32 LoadSpi = 0x08a210; constexpr i32 text_op_logfont_size = 0x050716; constexpr i32 specialcolorconv_status2 = 0x0a14f4; constexpr i32 ObjectArrayPointer = 0x1e0fa4; constexpr i32 NextObjectIdxArray = 0x1592d8; constexpr i32 ScaleColorBackGround = 0x0a4048; constexpr i32 ScaleColorForeGround = 0x0a404c; constexpr i32 LayerNameRectWidth = 0x037d1a; constexpr i32 layer_height_array = 0x0a3e08; //constexpr i32 LayerLockBorder = 0x037d78; // push char されているので安直には無理 constexpr i32 LayerLockBorder_mod = 0x037d71; constexpr i32 LayerLockCenter = 0x037d81; constexpr i32 LayerClippingBorder = 0x037e96; constexpr i32 LayerClippingCenter = 0x037ea2; constexpr i32 LayerLinkBorder = 0x037dfd; constexpr i32 LayerLinkCenter = 0x037e09; constexpr i32 LayerHideAlpha = 0x09a570; constexpr i32 ObjectColorMedia = 0x0a40e0; constexpr i32 ObjectColorMFilter = 0x0a4104; constexpr i32 ObjectColorSound = 0x0a4128; constexpr i32 ObjectColorSFilter = 0x0a414c; constexpr i32 ObjectColorControl = 0x0a4170; constexpr i32 ObjectColorUnknown = 0x0a4194; constexpr i32 ObjectColorInactive = 0x0a41b8; constexpr i32 ObjectNameColor = 0x0a4040; constexpr i32 ObjectNameColorShow = 0x0a4040; constexpr i32 ObjectNameColorHide = 0x0a4044; constexpr i32 MidPointSize = 0x0a3e14; constexpr i32 ObjectClippingColorB = 0x0375d7; constexpr i32 ObjectClippingColorG = 0x0375d9; constexpr i32 ObjectClippingColorR = 0x0375db; constexpr i32 ObjectClippingHeight = 0x0375e2; constexpr i32 BPMGridColorBeat = 0x0a4050; constexpr i32 BPMGridColorMeasure = 0x0a4054; } } ================================================ FILE: patch/overwrite_resource.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "overwrite_resource.hpp" #include "patch_access_key.hpp" //template inline std::invoke_result resource_func_wrap_helper(Func func) {} HRSRC WINAPI overwrite_resource_t::FindResourceA_Wrap(HMODULE hModule, LPCSTR lpName, LPCSTR lpType) { if (hModule != GLOBAL::patchaul_hinst) return (*FindResourceA_org)(hModule, lpName, lpType); auto ret = (*FindResourceA_org)(hModule, lpName, lpType); if (ret) return ret; return (*FindResourceA_org)(default_default_resource_hmod, lpName, lpType); } HCURSOR WINAPI overwrite_resource_t::LoadCursorA_Wrap(HINSTANCE hInstance, LPCSTR lpCursorName) { if (hInstance != GLOBAL::patchaul_hinst) return (*LoadCursorA_org)(hInstance, lpCursorName); if ((*FindResourceA_org)(hInstance, lpCursorName, RT_CURSOR)) { return (*LoadCursorA_org)(hInstance, lpCursorName); } return (*LoadCursorA_org)(default_default_resource_hmod, lpCursorName); } HICON WINAPI overwrite_resource_t::LoadIconA_Wrap(HINSTANCE hInstance, LPCSTR lpIconName) { if (hInstance != GLOBAL::patchaul_hinst) return (*LoadIconA_org)(hInstance, lpIconName); if ((*FindResourceA_org)(hInstance, lpIconName, RT_ICON)) { return (*LoadIconA_org)(hInstance, lpIconName); } return (*LoadIconA_org)(default_default_resource_hmod, lpIconName); } HANDLE WINAPI overwrite_resource_t::LoadImageA_Wrap(HINSTANCE hInst, LPCSTR name, UINT type, int cx, int cy, UINT fuLoad) { if (hInst != GLOBAL::patchaul_hinst) return (*LoadImageA_org)(hInst, name, type, cx, cy, fuLoad); auto ret = (*LoadImageA_org)(hInst, name, type, cx, cy, fuLoad); if (ret) return ret; return (*LoadImageA_org)(default_default_resource_hmod, name, type, cx, cy, fuLoad); } HMENU WINAPI overwrite_resource_t::LoadMenuA_Wrap(HINSTANCE hInstance, LPCSTR lpMenuName) { HMENU ret; do { if (hInstance != GLOBAL::patchaul_hinst) { ret = (*LoadMenuA_org)(hInstance, lpMenuName); break; } if ((*FindResourceA_org)(hInstance, lpMenuName, RT_MENU)) { ret = (*LoadMenuA_org)(hInstance, lpMenuName); break; } ret = (*LoadMenuA_org)(default_default_resource_hmod, lpMenuName); break; } while (0); #ifdef PATCH_SWITCH_ACCESS_KEY return patch::access_key.modify(lpMenuName, ret); #else return ret; #endif } int WINAPI overwrite_resource_t::LoadStringA_Wrap(HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, int cchBufferMax) { if (hInstance != GLOBAL::patchaul_hinst) return (*LoadStringA_org)(hInstance, uID, lpBuffer, cchBufferMax); auto ret = (*LoadStringA_org)(hInstance, uID, lpBuffer, cchBufferMax); if (ret) return ret; return (*LoadStringA_org)(default_default_resource_hmod, uID, lpBuffer, cchBufferMax); } INT_PTR WINAPI overwrite_resource_t::DialogBoxParamA_Wrap(HINSTANCE hInstance, LPCSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam) { if (hInstance != GLOBAL::patchaul_hinst) return (*DialogBoxParamA_org)(hInstance, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam); if ((*FindResourceA_org)(hInstance, lpTemplateName, RT_DIALOG)) { return (*DialogBoxParamA_org)(hInstance, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam); } return (*DialogBoxParamA_org)(default_default_resource_hmod, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam); } HWND WINAPI overwrite_resource_t::CreateDialogParamA_Wrap(HINSTANCE hInstance, LPCSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam) { if (hInstance != GLOBAL::patchaul_hinst) return (*CreateDialogParamA_org)(hInstance, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam); if ((*FindResourceA_org)(hInstance, lpTemplateName, RT_DIALOG)) { return (*CreateDialogParamA_org)(hInstance, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam);; } return (*CreateDialogParamA_org)(default_default_resource_hmod, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam); } BOOL APIENTRY overwrite_resource_t::GetSaveFileNameA_Wrap(LPOPENFILENAMEA ofnap) { if (ofnap->hInstance != GLOBAL::patchaul_hinst || ofnap->lpTemplateName == NULL) return (*GetSaveFileNameA_org)(ofnap); auto fr_ret = (*FindResourceA_org)(GLOBAL::patchaul_hinst, ofnap->lpTemplateName, RT_DIALOG); if (fr_ret) return (*GetSaveFileNameA_org)(ofnap); ofnap->hInstance = default_default_resource_hmod; auto ret = (*GetSaveFileNameA_org)(ofnap); ofnap->hInstance = GLOBAL::patchaul_hinst; return ret; } BOOL APIENTRY overwrite_resource_t::GetOpenFileNameA_Wrap(LPOPENFILENAMEA ofnap) { if (ofnap->hInstance != GLOBAL::patchaul_hinst || ofnap->lpTemplateName == NULL) return (*GetOpenFileNameA_org)(ofnap); auto fr_ret = (*FindResourceA_org)(GLOBAL::patchaul_hinst, ofnap->lpTemplateName, RT_DIALOG); if (fr_ret) return (*GetOpenFileNameA_org)(ofnap); ofnap->hInstance = default_default_resource_hmod; auto ret = (*GetOpenFileNameA_org)(ofnap); ofnap->hInstance = GLOBAL::patchaul_hinst; return ret; } ================================================ FILE: patch/overwrite_resource.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "util.hpp" #include "util_pe.hpp" #include "util_resource.hpp" #include "offset_address.hpp" #define overwrite_resource_t_func_org_def(name) inline static std::add_pointer_t name##_org #define overwrite_resource_t_func_ptr_def(name) inline const static auto name##_ptr = &name inline class overwrite_resource_t { public: static HRSRC WINAPI FindResourceA_Wrap(HMODULE hModule, LPCSTR lpName, LPCSTR lpType); static BOOL APIENTRY GetSaveFileNameA_Wrap(LPOPENFILENAMEA ofnap); static BOOL APIENTRY GetOpenFileNameA_Wrap(LPOPENFILENAMEA ofnap); static HCURSOR WINAPI LoadCursorA_Wrap(HINSTANCE hInstance, LPCSTR lpCursorName); static HICON WINAPI LoadIconA_Wrap(HINSTANCE hInstance, LPCSTR lpIconName); static HANDLE WINAPI LoadImageA_Wrap(HINSTANCE hInst, LPCSTR name, UINT type, int cx, int cy, UINT fuLoad); static HMENU WINAPI LoadMenuA_Wrap(HINSTANCE hInstance, LPCSTR lpMenuName); static int WINAPI LoadStringA_Wrap(HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, int cchBufferMax); static INT_PTR WINAPI DialogBoxParamA_Wrap(HINSTANCE hInstance, LPCSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam); static HWND WINAPI CreateDialogParamA_Wrap(HINSTANCE hInstance, LPCSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam); private: inline static HMODULE default_default_resource_hmod; overwrite_resource_t_func_ptr_def(FindResourceA_Wrap); overwrite_resource_t_func_ptr_def(GetSaveFileNameA_Wrap); overwrite_resource_t_func_ptr_def(GetOpenFileNameA_Wrap); overwrite_resource_t_func_ptr_def(LoadCursorA_Wrap); overwrite_resource_t_func_ptr_def(LoadIconA_Wrap); overwrite_resource_t_func_ptr_def(LoadImageA_Wrap); overwrite_resource_t_func_ptr_def(LoadMenuA_Wrap); overwrite_resource_t_func_ptr_def(LoadStringA_Wrap); overwrite_resource_t_func_ptr_def(DialogBoxParamA_Wrap); overwrite_resource_t_func_ptr_def(CreateDialogParamA_Wrap); overwrite_resource_t_func_org_def(FindResourceA); overwrite_resource_t_func_org_def(GetSaveFileNameA); overwrite_resource_t_func_org_def(GetOpenFileNameA); overwrite_resource_t_func_org_def(LoadCursorA); overwrite_resource_t_func_org_def(LoadIconA); overwrite_resource_t_func_org_def(LoadImageA); overwrite_resource_t_func_org_def(LoadMenuA); overwrite_resource_t_func_org_def(LoadStringA); overwrite_resource_t_func_org_def(DialogBoxParamA); overwrite_resource_t_func_org_def(CreateDialogParamA); static void InitAtResourceLoaded() { for (auto& s : patch_resource_message_stack) { s->fire(); } patch_resource_message_stack.clear(); } inline static auto InitAtResourceLoaded_ptr = &InitAtResourceLoaded; public: void operator()() { /* ・LoadLibrary直後のEnumResourceLanguagesAを消し飛ばす  ・patch.aulのリソースを別に登録させない  ・patch.aulは正しい言語拡張リソースではなかったということにする   ・これで必ず毎回読まれるようになる ・AviUtlのデフォルトのリソースのHMODULEをこれにする  ・メニューを読んであとから編集~はしない ・SaveDialogとOpenDIalogのTEMPLETEどうしよう...  ・これも乗っ取っちまえ */ // reinterpret_cast(search_import((HMODULE)GLOBAL::aviutl_base, "COMDLG32.DLL", "GetOpenFileNameA")), auto reloc_list = search_reloc((HMODULE)GLOBAL::aviutl_base, { 0x06f07c, // GetOpenFileNameA 0x06f074, // GetSaveFileNameA 0x06f0dc, // FindResourceA 0x06f400, // LoadCursorA 0x06f394, // LoadIconA 0x06f3a0, // LoadImageA 0x06f3b8, // LoadMenuA 0x06f3b4, // LoadStringA 0x06f3b0, // DialogBoxParamA 0x06f3ac, // CreateDialogParamA }); for (auto v : reloc_list[0x06f07c]) OverWriteOnProtectHelper(reinterpret_cast(v), 4).store_i32(0, &GetOpenFileNameA_Wrap_ptr); for (auto v : reloc_list[0x06f074]) OverWriteOnProtectHelper(reinterpret_cast(v), 4).store_i32(0, &GetSaveFileNameA_Wrap_ptr); for (auto v : reloc_list[0x06f0dc]) OverWriteOnProtectHelper(reinterpret_cast(v), 4).store_i32(0, &FindResourceA_Wrap_ptr); for (auto v : reloc_list[0x06f400]) OverWriteOnProtectHelper(reinterpret_cast(v), 4).store_i32(0, &LoadCursorA_Wrap_ptr); for (auto v : reloc_list[0x06f394]) OverWriteOnProtectHelper(reinterpret_cast(v), 4).store_i32(0, &LoadIconA_Wrap_ptr); for (auto v : reloc_list[0x06f3a0]) OverWriteOnProtectHelper(reinterpret_cast(v), 4).store_i32(0, &LoadImageA_Wrap_ptr); for (auto v : reloc_list[0x06f3b8]) OverWriteOnProtectHelper(reinterpret_cast(v), 4).store_i32(0, &LoadMenuA_Wrap_ptr); for (auto v : reloc_list[0x06f3b4]) OverWriteOnProtectHelper(reinterpret_cast(v), 4).store_i32(0, &LoadStringA_Wrap_ptr); for (auto v : reloc_list[0x06f3b0]) OverWriteOnProtectHelper(reinterpret_cast(v), 4).store_i32(0, &DialogBoxParamA_Wrap_ptr); for (auto v : reloc_list[0x06f3ac]) OverWriteOnProtectHelper(reinterpret_cast(v), 4).store_i32(0, &CreateDialogParamA_Wrap_ptr); #define def(name, ofs) name = reinterpret_cast(GLOBAL::aviutl_base + ofs) def(GetOpenFileNameA_org , 0x06f07c); def(GetSaveFileNameA_org , 0x06f074); def(FindResourceA_org , 0x06f0dc); def(LoadCursorA_org , 0x06f400); def(LoadIconA_org , 0x06f394); def(LoadImageA_org , 0x06f3a0); def(LoadMenuA_org , 0x06f3b8); def(LoadStringA_org , 0x06f3b4); def(DialogBoxParamA_org , 0x06f3b0); def(CreateDialogParamA_org, 0x06f3ac); #undef def /* OverWriteOnProtectHelper(GLOBAL::aviutl_base + 0x06f07c, 4).store_i32(0, GetOpenFileNameA_Wrap); OverWriteOnProtectHelper(GLOBAL::aviutl_base + 0x06f074, 4).store_i32(0, GetSaveFileNameA_Wrap); OverWriteOnProtectHelper(GLOBAL::aviutl_base + 0x06f0dc, 4).store_i32(0, FindResourceA_Wrap); OverWriteOnProtectHelper(GLOBAL::aviutl_base + 0x06f400, 4).store_i32(0, LoadCursorA_Wrap); OverWriteOnProtectHelper(GLOBAL::aviutl_base + 0x06f394, 4).store_i32(0, LoadIconA_Wrap); OverWriteOnProtectHelper(GLOBAL::aviutl_base + 0x06f3a0, 4).store_i32(0, LoadImageA_Wrap); OverWriteOnProtectHelper(GLOBAL::aviutl_base + 0x06f3b8, 4).store_i32(0, LoadMenuA_Wrap); OverWriteOnProtectHelper(GLOBAL::aviutl_base + 0x06f3b4, 4).store_i32(0, LoadStringA_Wrap); OverWriteOnProtectHelper(GLOBAL::aviutl_base + 0x06f3b0, 4).store_i32(0, DialogBoxParamA_Wrap); OverWriteOnProtectHelper(GLOBAL::aviutl_base + 0x06f3ac, 4).store_i32(0, CreateDialogParamA_Wrap); */ // default_resource_hmod auto default_resource_hmod_ptr = (HMODULE*)(GLOBAL::aviutl_base + OFS::AviUtl::default_resource_hmod); default_default_resource_hmod = std::exchange(*default_resource_hmod_ptr, GLOBAL::patchaul_hinst); const char code[] = "\x50" // push eax "\xff\x15xxxx" // call [i32] "\x58" // pop eax "\xc3"; // ret OverWriteOnProtectHelper h(GLOBAL::aviutl_base + 0x0548e0, sizeof(code) - 1); memcpy((void*)(GLOBAL::aviutl_base + 0x0548e0), code, sizeof(code) - 1); h.store_i32(3, &InitAtResourceLoaded_ptr); } } overwrite_resource; ================================================ FILE: patch/packages.config ================================================  ================================================ FILE: patch/patch.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "macro.h" #include "init.hpp" #include "add_dll_ref.hpp" #include "config.hpp" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) { static bool loading_self = false; switch (fdwReason) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hinstDLL); if (add_dll_ref.dllmain_if_break())break; GLOBAL::init_minimum(hinstDLL); init.InitAtDllMain(); break; case DLL_PROCESS_DETACH: //GLOBAL::config.store(GLOBAL::patchaul_config_path); config2.store(GLOBAL::patchaul_config_path); #ifdef PATCH_SWITCH_CONSOLE patch::console.exit(); #endif break; } return TRUE; } ================================================ FILE: patch/patch.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "patch_access_key.hpp" #include "patch_exo_sceneidx.hpp" #include "patch_exo_trackparam.hpp" #include "patch_exo_trackminusval.hpp" #include "patch_tra_aviutlfilter.hpp" #include "patch_exo_aviutlfilter.hpp" #include "patch_exo_specialcolorconv.hpp" #include "patch_lua.hpp" #include "patch_console.hpp" #include "patch_exception_log.hpp" #include "patch_aviutl_wndproc_override.hpp" #include "patch_sysinfo_write.hpp" #include "patch_splash.hpp" #include "patch_scroll_objdlg.hpp" #include "patch_text_op_size.hpp" #include "patch_ignore_media_param_reset.hpp" #include "patch_susie_load.hpp" #include "patch_alpha_bg.hpp" #include "patch_theme_cc.hpp" #include "patch_helpful_msgbox.hpp" #include "patch_fast_setting_dialog.hpp" #include "patch_fast_exeditwindow.hpp" #include "patch_exeditwindow_sizing.hpp" #include "patch_setting_dialog_wndproc_override.hpp" #include "patch_undo.hpp" #include "patch_fast_getputpixeldata.hpp" #include "patch_fast_polortransform.hpp" #include "patch_fast_displacementmap.hpp" #include "patch_fast_radiationalblur.hpp" #include "patch_fast_flash.hpp" #include "patch_fast_lensblur.hpp" #include "patch_font_dialog.hpp" #include "patch_setting_dialog_move.hpp" #include "patch_redo.hpp" #include "patch_fast.hpp" #include "patch_fast_cl.hpp" #include "patch_lua_getvalueex.hpp" #include "patch_lua_rand.hpp" #include "patch_lua_randex.hpp" #include "patch_fast_text.hpp" #include "patch_fast_create_figure.hpp" #include "patch_obj_lensblur.hpp" #include "patch_obj_noise.hpp" #include "patch_setting_dialog_excolorconfig.hpp" #include "patch_fast_border.hpp" #include "patch_fast_directionalblur.hpp" #include "patch_rclickmenu_split.hpp" #include "patch_rclickmenu_delete.hpp" #include "patch_tra_change_drawfilter.hpp" #include "patch_tra_specified_speed.hpp" #include "patch_blend.hpp" #include "patch_failed_sjis_msgbox.hpp" #include "patch_obj_colorcorrection.hpp" #include "patch_aup_scene_setting.hpp" #include "patch_exo_fold_gui.hpp" #include "patch_colorpalette_cache.hpp" #include "patch_add_extension.hpp" #include "patch_obj_specialcolorconv.hpp" #include "patch_dialog_new_file.hpp" #include "patch_exo_midpt_and_tra.hpp" #include "patch_fileinfo.hpp" #include "patch_playback_speed.hpp" #include "patch_fast_glow.hpp" #include "patch_obj_glow.hpp" #include "patch_setting_new_project.hpp" #include "patch_aup_layer_setting.hpp" #include "patch_failed_file_drop.hpp" #include "patch_failed_longer_path.hpp" ================================================ FILE: patch/patch.rc ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include #include "resource.h" #include "macro.h" STRINGTABLE LANGUAGE LANG_JAPANESE,SUBLANG_DEFAULT { 0, "日本語 (patched)" 1, "patch.aul by ePi" 10, "デフォルト" 11, "自動" 12, "なし" 13, "秒" 14, "分" 15, "時間" 16, "インターレース解除" 17, "奇数" 18, "偶数" 19, "二重化" 21, "自動" 22, "自動24fps" 23, "標準" 24, "反転" 25, "周期" 26, "不明" 27, "出力中" 28, "計測中" 29, "検索中" 30, "残り時間" 31, "再圧縮不可" 32, "未圧縮" 33, "fps変換無し" 34, "画像サイズ" 35, "記録時間" 36, "フレームレート" 37, "フレーム数" 38, "ビデオ圧縮" 39, "サンプリングレート" 40, "チャンネル数" 41, "オーディオ形式" 42, "強さ" 43, "範囲" 44, "しきい値" 45, "下限値" 46, "上限値" 49, "上" 50, "下" 51, "左" 52, "右" 53, "明るさ" 54, "コントラスト" 55, "輝度" 56, "ガンマ" 57, "色の濃さ" 58, "色合い" 59, "レベル" 60, "音量の最大化" 61, "ぼかしフィルタ" 62, "クリッピング&リサイズ" 63, "元の縦横比に合わせる" 64, "元のサイズに拡大" 66, "色調補正" 67, "拡張色調補正" 68, "TV -> PC スケール補正" 69, "RGBの同期" 73, "ヒストグラム" 74, "インターレースの解除" 75, "自動24fps解除" 76, "ドット単位解除" 77, "イメージ表示" 78, "自動解除" 79, "動き重視" 80, "横縞部分を二重化" 81, "奇数偶数解除" 82, "位置補間" 83, "適合補間" 84, "インターリーブ" 85, "0.5秒" 86, "1秒" 87, "2秒" 88, "1フレーム" 89, "2フレーム" 90, "5フレーム" 91, "10フレーム" 92, "指定フレーム数" 93, "ナビゲートウィンドウ" 94, "ノイズ除去フィルタ" 95, "ノイズ除去(時間軸)フィルタ" 96, "再生ウィンドウ" 97, "フレームレートの変更" 98, "フレームレートの設定" 99, "24fps<-30fpsの間引きには自動24fpsの処理を使う" 100, "サイズの変更" 101, "指定サイズ" 102, "シャープフィルタ" 105, "連番BmpFile (*.bmp)|*.bmp" 106, "ツールウィンドウ" 107, "の設定" 108, "の表示" 109 "フィールドオーダー" 110 "ボトムフィールド -> トップフィールド" 111 "トップフィールド -> ボトムフィールド" 112 "ファイル制御" 113 "ビデオ展開形式" 114 "音量の調整" 115 "音声の位置調整" 116 "位置" 122 "縁塗りつぶし" 123 "黒で塗る" 124 "縁の色で塗る" 125 "PC -> TV スケール補正" 128 "中央に配置" 129 "何もしない" 130 "ウィンドウズをシャットダウン" 131 "ウィンドウズを休止" 132 "ウィンドウズをサスペンド" 133 "AviUtlを終了" 134 "バッチ出力リスト" 135 "[出力ファイル名が指定されていません]" 136 "色変換の設定" 137 "[ 入力 ]" 138 "[ 出力 ]" 139 "追加読み込み" 140 "音声読み込み" 141 "プロジェクトを開く" 142 "プロジェクトを保存" 143 "AVI出力" 144 "WAV出力" 145 "AviUtlを終了&ウィンドウズを休止" 146 "AviUtlを終了&ウィンドウズをサスペンド" 1000, "ファイルの読み込みに失敗しました。" 1001, "ファイルの書き込みに失敗しました。\n\nディスクの空き容量が足りないか\n作成できるファイルサイズの上限を超えた可能性があります。" 1002, "ファイルの作成に失敗しました。" 1003, "このファイルには対応していません。" 1004, "使用されていたファイルが見つからないか変更されています。\n別のファイルを指定しますか?" 1005, "同時に読み込めるファイルは%d個までです。" 1006, "%dx%dを超える画像サイズのファイルは編集できません。\n\n最大画像サイズはシステムの設定で変更出来ます。" 1007, "%dx%dより小さい画像サイズのファイルは編集できません。" 1008, "編集できる最大フレーム数は%dフレームまでです。\n\n最大フレーム数はシステムの設定で変更出来ます。" 1009, "再圧縮するフレームがありますがよろしいですか?\n\n※フレーム%d%s。" 1010, "バッチ登録は最大%d個までです。" 1011, "の画像フォーマットが違う" 1012, "の画像サイズが違う" 1013, "がキーフレームから続いていない" 1014, "が60fps化モードで読み込まれている" 1015, "編集しているファイルへの上書きは出来ません。" 1016, "ビデオ圧縮の初期化に失敗しました。\n\n画像サイズを特定の倍数にしないと\n使用出来ないコーデックの可能性があります。" 1017, "オーディオ圧縮の初期化に失敗しました。\n\n使用出来ないコーデックの可能性があります。" 1018, "出力を中断しますか?" 1019, "検索を中断しますか?" 1020, "ありません。" 1021, "使用されていません。" 1022, "プロファイル名に以下の文字は使えません。\n\n%s" 1023, "入力ファイルへの上書きは出来ません。" 1024, "連結できるファイルは最大%d個までです。" 1025, "再圧縮しないと正常なファイルが作成されない可能性がありますがよろしいですか?" 1026, "出力プラグインが見つかりません。" 1028, "ファイルの情報" 1029, "プラグインフィルタ情報" 1030, "入力プラグイン情報" 1031, "出力プラグイン情報" 1032, "オーバーレイ情報" 1033, "バージョン情報" 1034, "言語拡張リソース情報" 1035, "メモリの確保に失敗しました。\n\nキャッシュサイズを調整して再試行しますか?" 1036, "バッチ出力に失敗したファイルがあります。" 1037, "すべて削除しますがよろしいですか?" 1038, "ファイルの読み込みに失敗しました。\n\nこのファイル形式には対応していないか\n対応するコーデックやプラグインが\n登録されていない可能性があります。" 1039, "ファイルの出力に失敗しました。" 1040, "[開始]ボタンを押すとバッチ出力を開始します" 1041, "すべて正常に終了しました" 1042, "\x22%s\x22を出力中です" 1043, "他のプロセスでの出力終了を待っています" 1044, "色変換プラグイン情報" 1045, "複数の操作が同じショートカットキーに割り当てられています\n\n%s\n%s\n" 1046, "現在の編集データは破棄されますがよろしいですか?" 1047, "メモリをアドレスに割り当てることができません。" PATCH_RS_PATCH_FAILED_TO_SAVE_SETTING, "設定ファイルの保存に失敗" PATCH_RS_PATCH_FAILED_TO_LOAD_SETTING, "設定ファイルの読込に失敗" PATCH_RS_PATCH_FAILED_TO_INIT_CONSOLE, "コンソールの初期化に失敗" PATCH_RS_PATCH_CONSOLE_IS_DIABLED, "コンソール機能は無効になっています。\n有効にするには、switch.console を true にしてください。" PATCH_RS_PATCH_INVALID_SETTING_JSON, "設定ファイルは不正なjsonです。文法を確認してください。\n設定は読込/保存されません。" PATCH_RS_PATCH_CONFLICT_PLUGIN, "以下プラグインの機能はpatch.aulが既に持っているため、除去してください。\nプラグインファイルを削除しますか?\n\n{}" PATCH_RS_PATCH_OLD_LSW, "古いバージョンのL-SMASH Worksを使用しようとしています。このバージョンの使用は推奨されません。\n新しいバージョンへとアクセスしますか?" PATCH_RS_PATCH_FAILED_TO_CREATE_EXCEPTION_DIALOG, "patch.aulは例外ダイアログの生成に失敗しました。({})\n例外の詳細情報は log/{} に保存されています。\n情報\n{}" PATCH_RS_PATCH_WEB_CONFIRM, "次の外部Webサイトを開きますか?" PATCH_RS_PATCH_WEB_CONFIRM_BUTTON_OPEN, "開く" PATCH_RS_PATCH_WEB_CONFIRM_BUTTON_COPY, "URLをコピー" PATCH_RS_PATCH_WEB_CONFIRM_BUTTON_CANCEL, "キャンセル" #ifdef PATCH_SWITCH_CL PATCH_RS_PATCH_CANT_USE_CL, "OpenCL Effectは使用できません" #endif #ifdef PATCH_SWITCH_TRANSRATE #endif } AVIUTL MENU { POPUP "ファイル" { MENUITEM "開く", 5097 MENUITEM "閉じる", 5157 MENUITEM "追加読み込み", 5100 MENUITEM "音声読み込み", 5168 MENUITEM SEPARATOR MENUITEM "編集プロジェクトを開く", 5118 MENUITEM "編集プロジェクトの保存", 1023 MENUITEM "編集プロジェクトの上書き", 1024 MENUITEM SEPARATOR MENUITEM "AVI出力", 1003 MENUITEM "WAV出力", 1062 POPUP "プラグイン出力" { MENUITEM "", 5395 } MENUITEM "バッチ出力", 1025 MENUITEM "出力の中断", 1009 MENUITEM SEPARATOR POPUP "インポート" { MENUITEM "キーフレームリスト", 5167 MENUITEM "", 14000 } POPUP "エクスポート" { MENUITEM "キーフレームリスト", 1054 MENUITEM "", 15000 } POPUP "AVIファイル操作" { MENUITEM "AVIファイルの連結", 1057 MENUITEM "AVIファイルの合成", 1058 } POPUP "最近使ったファイル" { MENUITEM "なし", 5596 MENUITEM SEPARATOR MENUITEM "最近使ったファイルの履歴を消去", 1073 } MENUITEM SEPARATOR POPUP "環境設定" { POPUP "優先度" { MENUITEM "Highest", 1041 MENUITEM "High", 1040 MENUITEM "Normal", 1039 MENUITEM "Low", 1038 MENUITEM "Lowest", 1037 MENUITEM SEPARATOR MENUITEM "Realtime", 1042 } MENUITEM SEPARATOR MENUITEM "システムの設定", 108 MENUITEM "コーデックの設定", 109 POPUP "入力プラグインの設定" { MENUITEM "", 5595 } MENUITEM "入力プラグイン優先度の設定", 1086 MENUITEM "ショートカットキーの設定", 102 MENUITEM "言語の設定 (Language)", 106 MENUITEM SEPARATOR MENUITEM "ウィンドウの位置を初期化", 111 } MENUITEM SEPARATOR MENUITEM "終了", 1002 } POPUP "フィルタ" { MENUITEM "", 10000 MENUITEM SEPARATOR MENUITEM "", 10999 MENUITEM SEPARATOR MENUITEM "すべてのフィルタをOFFにする", 5183 } POPUP "設定" { MENUITEM "", 11000 MENUITEM SEPARATOR MENUITEM "", 11999 MENUITEM SEPARATOR MENUITEM "", 11998 MENUITEM SEPARATOR POPUP "圧縮の設定" { MENUITEM "ビデオ圧縮の設定", 5127 MENUITEM "オーディオ圧縮の設定", 5128 MENUITEM SEPARATOR MENUITEM "プラグイン出力の設定", 5399 } POPUP "フィルタ順序の設定" { MENUITEM "ビデオフィルタ順序の設定", 5139 MENUITEM "オーディオフィルタ順序の設定", 5181 } } POPUP "編集" { MENUITEM "現在のフレームの画像をコピー", 1020 MENUITEM "現在のフレームに画像を貼り付け", 5117 MENUITEM "現在のフレームをクリップボードにコピー", 1026 MENUITEM "現在のフレームにクリップボードから貼り付け", 5123 MENUITEM "現在のフレームの出力イメージをクリップボードにコピー", 1070 MENUITEM "指定のフレームに移動", 5131 MENUITEM "選択範囲の指定", 5115 MENUITEM "選択範囲のフレームに画像を貼り付け", 5184 MENUITEM "選択範囲のフレーム切り出し", 5143 MENUITEM "選択範囲のフレーム削除", 5101 MENUITEM SEPARATOR MENUITEM "元に戻す", 5147 MENUITEM "すべてのフレームを選択", 5112 MENUITEM SEPARATOR MENUITEM "選択範囲を新しいプロファイルにする", 5109 MENUITEM "選択範囲を新しい圧縮の設定にする", 5126 MENUITEM "選択範囲のインターレース解除を指定", 5125 POPUP "現在のフレームのインターレース解除" { MENUITEM "標準", 5196 MENUITEM "反転", 5197 MENUITEM "奇数", 5198 MENUITEM "偶数", 5199 MENUITEM "二重化", 5200 MENUITEM "自動", 5201 } POPUP "現在のフレームのプロファイル" { MENUITEM "標準プロファイル", 5206 MENUITEM "プロファイル[1]", 5207 MENUITEM "プロファイル[2]", 5208 MENUITEM "プロファイル[3]", 5209 MENUITEM "プロファイル[4]", 5210 MENUITEM "プロファイル[5]", 5211 MENUITEM "プロファイル[6]", 5212 MENUITEM "プロファイル[7]", 5213 MENUITEM "プロファイル[8]", 5214 MENUITEM "プロファイル[9]", 5215 } MENUITEM SEPARATOR MENUITEM "現在のフレームをキーフレームにする", 5129 MENUITEM "現在のフレームを優先間引きフレームにする", 5132 MENUITEM "現在のフレームをマークする", 5130 MENUITEM "現在のフレームをコピーフレームにする", 5156 MENUITEM SEPARATOR MENUITEM "再生速度の情報を変更", 5398 MENUITEM SEPARATOR POPUP "基本機能" { MENUITEM "次のフレームに移動 (→)", 9002 MENUITEM "前のフレームに移動 (←)", 9001 MENUITEM "削除フレームを飛ばして次のフレームに移動 (↓)", 5142 MENUITEM "削除フレームを飛ばして前のフレームに移動 (↑)", 5141 MENUITEM "先頭のフレームに移動(Home)", 5396 MENUITEM "最後のフレームに移動(End)", 5397 MENUITEM "現在のフレームを選択開始フレームにする ([)", 5110 MENUITEM "現在のフレームを選択終了フレームにする (])", 5111 MENUITEM "選択開始フレームに移動", 5103 MENUITEM "選択終了フレームに移動", 5104 MENUITEM "次のキーフレームに移動", 5174 MENUITEM "前のキーフレームに移動", 5175 MENUITEM "次のマークフレームに移動", 5178 MENUITEM "前のマークフレームに移動", 5179 MENUITEM "次のプロファイルの変更フレームに移動", 5176 MENUITEM "前のプロファイルの変更フレームに移動", 5177 MENUITEM "次のフレーム不連続点に移動", 5170 MENUITEM "前のフレーム不連続点に移動", 5171 MENUITEM "任意フレーム数次移動A (PageDown)", 5187 MENUITEM "任意フレーム数前移動A (PageUp)", 5188 MENUITEM "任意フレーム数次移動B", 5189 MENUITEM "任意フレーム数前移動B", 5190 MENUITEM "任意フレーム数次移動C", 5191 MENUITEM "任意フレーム数前移動C", 5192 MENUITEM "任意フレーム数次移動D", 5193 MENUITEM "任意フレーム数前移動D", 5194 MENUITEM "現在のフレームから再生ウィンドウで再生/停止", 1099 MENUITEM "現在のフレーム番号をクリップボードにコピー", 1090 } } POPUP "プロファイル" { MENUITEM "", 8005 MENUITEM SEPARATOR POPUP "プロファイルの編集" { MENUITEM "新しいプロファイルを作る", 8001 MENUITEM "現在のプロファイルを削除する", 8002 MENUITEM "現在のプロファイルを初期値に戻す", 8000 } } POPUP "表示" { POPUP "拡大表示" { MENUITEM "25%", 9200 MENUITEM "50%", 9201 MENUITEM "100%", 9202 MENUITEM "200%", 9203 MENUITEM "300%", 9204 MENUITEM "400%", 9205 MENUITEM "WindowSize", 9206 MENUITEM SEPARATOR MENUITEM "ズームイン", 9107 MENUITEM "ズームアウト", 9108 MENUITEM SEPARATOR MENUITEM "ウィンドウサイズを自動変更", 9116 } MENUITEM "オーディオ波形の表示", 9104 MENUITEM "時間の表示", 9114 MENUITEM "セーブ中もプレビュー表示", 9105 MENUITEM "セーブ中にデータレートを表示", 9115 MENUITEM "間引き予定フレームの表示", 9106 MENUITEM "再圧縮が必要なフレームの表示", 9110 MENUITEM "ソースファイルのキーフレーム表示", 9109 MENUITEM SEPARATOR MENUITEM "", 10998 MENUITEM SEPARATOR #ifdef PATCH_SWITCH_CONSOLE MENUITEM "コンソールの表示", PATCH_MENU_CONSOLE MENUITEM SEPARATOR #endif MENUITEM "常に手前に表示", 9113 MENUITEM "オーバーレイ表示", 9111 MENUITEM "セーブ中のみフィルタリングして表示", 5144 } POPUP "その他" { MENUITEM "ファイルの情報", 1006 MENUITEM "オーバーレイ情報", 104 MENUITEM "プラグインフィルタ情報", 101 MENUITEM "入力プラグイン情報", 103 MENUITEM "出力プラグイン情報", 105 MENUITEM "色変換プラグイン情報", 110 MENUITEM "言語拡張リソース情報", 107 MENUITEM SEPARATOR MENUITEM "バージョン情報", 100 MENUITEM "patch.aul", PATCH_MENU_INFO } } PATCH_DIALOG_EXCEPTION DIALOGEX 0, 0, 286, 166 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_NOFAILCREATE CAPTION "AviUtl : Application Exception" FONT 8, "MS Shell Dlg", 400, 0, 0x1 { DEFPUSHBUTTON "OK", PATCH_ID_EXCEPTION_OK, 18, 108, 120, 14 PUSHBUTTON "詳細",PATCH_ID_EXCEPTION_DETAIL_BUTTON, 150, 108, 120, 14 PUSHBUTTON "編集プロジェクトの保存",PATCH_ID_EXCEPTION_SAVE_PROJECT, 18, 148, 252, 14 LTEXT "例外が発生しました。\n詳細情報は以下のファイルに出力されました。", PATCH_ID_EXCEPTION_LABEL1, 10, 6, 264, 18 LTEXT "この画面から、現在の編集プロジェクトの保存が出来ます\n(元のファイルと同じ名前は使用しないでください)。", PATCH_ID_EXCEPTION_LABEL2, 10, 128, 264, 18 CONTROL "dummy syslink", PATCH_ID_EXCEPTION_LINK, "SysLink", WS_GROUP | WS_TABSTOP, 10, 25, 264, 12 EDITTEXT PATCH_ID_EXCEPTION_DETAIL_TEXT, 10, 38, 266, 54, ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_READONLY | ES_MULTILINE CONTROL "しばらく同種のメッセージの表示を停止する", PATCH_ID_EXCEPTION_STOPMES, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 11, 94, 258, 12 /* COMBOBOX PATCH_ID_EXCEPTION_THREADID_COMBO, 227, 7, 51, 12,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "thread id", PATCH_ID_EXCEPTION_LABEL3, 184, 9, 42, 8 */ } #ifdef PATCH_SWITCH_SPLASH SPLASH RCDATA "splash.png" #endif ================================================ FILE: patch/patch.vcxproj ================================================  Debug Win32 Release_PDB Win32 Release Win32 16.0 Win32Proj {20c4ed31-b17f-445a-90fe-77f8119f831b} patch 10.0 DynamicLibrary true v143 MultiByte DynamicLibrary false v143 true MultiByte DynamicLibrary false v143 true MultiByte true .aul false .aul false .aul Level3 true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpplatest aviutl_exedit_sdk;winwrap;%CUDA_PATH%\include;%(AdditionalIncludeDirectories) /source-charset:utf-8 /execution-charset:shift_jis %(AdditionalOptions) true Console true OpenCL.DLL %CUDA_PATH%\lib\Win32 xcopy /Y "$(TargetPath)" "$(SolutionDir)test\" xcopy /Y "$(TargetPath)" "$(SolutionDir)pack\" xcopy /Y "$(SolutionDir)patch.aul.txt" "$(SolutionDir)pack\" xcopy /Y "$(SolutionDir)credits.md" "$(SolutionDir)pack\" xcopy /Y "$(SolutionDir)LICENSE" "$(SolutionDir)pack\" xcopy /Y "$(SolutionDir)COPYING" "$(SolutionDir)pack\" xcopy /Y "$(SolutionDir)COPYING.LESSER" "$(SolutionDir)pack\" /c 65001 %(AdditionalOptions) Level3 true true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpplatest aviutl_exedit_sdk;winwrap;%CUDA_PATH%\include;%(AdditionalIncludeDirectories) /source-charset:utf-8 /execution-charset:shift_jis %(AdditionalOptions) true Console true true false OpenCL.DLL %CUDA_PATH%\lib\Win32 copy /Y "$(TargetPath)" "$(SolutionDir)test\$(TargetFileName)" copy /Y "$(TargetPath)" "$(SolutionDir)pack\$(TargetFileName)" copy /Y "$(SolutionDir)patch.aul.txt" "$(SolutionDir)pack\patch.aul.txt" copy /Y "$(SolutionDir)credits.md" "$(SolutionDir)pack\credits.md" copy /Y "$(SolutionDir)LICENSE" "$(SolutionDir)pack\LICENSE" copy /Y "$(SolutionDir)COPYING" "$(SolutionDir)pack\COPYING" copy /Y "$(SolutionDir)COPYING.LESSER" "$(SolutionDir)pack\COPYING.LESSER" /c 65001 %(AdditionalOptions) Level3 true true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpplatest aviutl_exedit_sdk;winwrap;%CUDA_PATH%\include;%(AdditionalIncludeDirectories) /source-charset:utf-8 %(AdditionalOptions) true Console true true true OpenCL.DLL %CUDA_PATH%\lib\Win32 copy /Y "$(TargetPath)" "$(SolutionDir)test\$(TargetFileName)" copy /Y "$(TargetPath)" "$(SolutionDir)pack\$(TargetFileName)" copy /Y "$(SolutionDir)patch.aul.txt" "$(SolutionDir)pack\patch.aul.txt" copy /Y "$(SolutionDir)credits.md" "$(SolutionDir)pack\credits.md" copy /Y "$(SolutionDir)LICENSE" "$(SolutionDir)pack\LICENSE" copy /Y "$(SolutionDir)COPYING" "$(SolutionDir)pack\COPYING" copy /Y "$(SolutionDir)COPYING.LESSER" "$(SolutionDir)pack\COPYING.LESSER" /c 65001 %(AdditionalOptions) このプロジェクトは、このコンピューター上にない NuGet パッケージを参照しています。それらのパッケージをダウンロードするには、[NuGet パッケージの復元] を使用します。詳細については、http://go.microsoft.com/fwlink/?LinkID=322105 を参照してください。見つからないファイルは {0} です。 ================================================ FILE: patch/patch.vcxproj.filters ================================================  {f2c356a4-9aa7-4917-b27b-4b37a59cc03e} {0921e89c-9ee4-4242-9edf-9f1278a8fd04} {42fd95df-c430-425e-839f-50891f36ebff} feature feature feature feature feature feature feature feature feature feature feature feature feature feature feature feature feature feature feature feature feature feature feature feature feature feature feature feature feature\fast feature\fast feature\fast feature\fast feature\fast util util util util util util feature feature feature feature feature\fast feature\fast feature\fast feature feature\fast feature feature\fast feature\fast feature\fast feature feature feature feature feature feature feature feature feature\fast feature\fast feature feature feature feature feature feature feature feature feature feature feature feature feature feature\fast feature\fast feature\fast feature\fast feature\fast util feature feature feature feature\fast feature\fast feature feature\fast feature\fast feature\fast feature feature feature feature feature feature feature\fast feature\fast feature ================================================ FILE: patch/patch_access_key.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_ACCESS_KEY #include "global.hpp" #include "config_rw.hpp" namespace patch { // LoadMenuA 時にmodifyを噛ませる // メニューにアクセスキーの追加をする inline class access_key_t { struct Menu { enum { File, Filter, Setting, Edit, Profile, View, Other, Count }; }; char map_key[Menu::Count] = { 'F', 'L', 'S', 'E', 'P', 'V', 'O', }; // どのメニューがあるかでどのフォルダかを調べる UINT mark_map[Menu::Count] = { 5097, 5183, 5127, 1020, 8001, 9200, 1006 }; inline static bool find_menu(HMENU hMenu, UINT id) { auto menu_n = GetMenuItemCount(hMenu); for (int i = 0; i < menu_n; i++) { MENUITEMINFOW mii{ .cbSize = sizeof(mii), .fMask = MIIM_ID | MIIM_SUBMENU, }; GetMenuItemInfoW(hMenu, i, TRUE, &mii); if (mii.hSubMenu != NULL) { auto ret = find_menu(mii.hSubMenu, id); if (ret)return true; } if (mii.wID == id) return true; } return false; } bool enabled = false; bool enabled_i; inline static const char key[] = "access_key"; public: void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void init() { enabled_i = enabled; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } HMENU modify(LPCSTR key, HMENU hMenu) { if (!enabled_i) return hMenu; if (lstrcmpiA(key, "AVIUTL") != 0)return hMenu; auto find_submenu = [](HMENU hMenu, int idx, UINT id) { auto sub = GetSubMenu(hMenu, idx); auto menu_n = GetMenuItemCount(sub); for (int i = 0; i < menu_n; i++) { MENUITEMINFOW mii{ .cbSize = sizeof(mii), .fMask = MIIM_ID, }; GetMenuItemInfoW(sub, i, TRUE, &mii); if (mii.wID == id) return true; } return false; }; for (int i = 0; i < Menu::Count; i++) { auto menu_n = GetMenuItemCount(hMenu); for (int j = 0; j < menu_n; j++) { MENUITEMINFOW mii{ .cbSize = sizeof(mii), .fMask = MIIM_STRING | MIIM_ID, .dwTypeData = NULL }; GetMenuItemInfoW(hMenu, j, TRUE, &mii); if (find_menu(GetSubMenu(hMenu, j), mark_map[i])) { std::wstring buf; buf.resize(mii.cch); mii.fMask = MIIM_STRING; mii.dwTypeData = buf.data(); mii.cch = buf.size() + 1; GetMenuItemInfoW(hMenu, j, TRUE, &mii); buf.append(L"(&"); buf.push_back(map_key[i]); buf.push_back(L')'); mii.fMask = MIIM_STRING; mii.dwTypeData = buf.data(); mii.cch = buf.size() + 1; SetMenuItemInfoW(hMenu, j, TRUE, &mii); } } } return hMenu; } } access_key; } // namespace patch #endif // ifdef PATCH_SWITCH_ACCESS_KEY ================================================ FILE: patch/patch_add_extension.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_add_extension.hpp" #ifdef PATCH_SWITCH_ADD_EXTENSION namespace patch { int __cdecl add_extension_t::wsprintfA_wrap2701a(void* ebp, LPSTR dst, LPCSTR src) { int* flag = (int*)((int)ebp - 1308); // 1:VideoFile 2:AudioFile int* new_ext_num = (int*)((int)ebp - 1288); // new_ext_bufに追加された拡張子の数(最初の時点では0) char* new_ext_buf = (char*)((int)ebp - 1284); // ".mp4\0.acb\0.xyz\0"のように'\0'区切りで書いていく .aviのみ別枠として確定で追加されるのでここには追加しないこと *new_ext_num = 0; char* str_movie_audio_file; if (*flag == 1) { str_movie_audio_file = (char*)(GLOBAL::exedit_base + OFS::ExEdit::str_DOUGAFILE); // "動画ファイル" } else { // *flag == 2 str_movie_audio_file = (char*)(GLOBAL::exedit_base + OFS::ExEdit::str_ONSEIFILE); // "音声ファイル" } char* ptr = (char*)(GLOBAL::exedit_base + OFS::ExEdit::ini_extension_buf); unsigned int endptr = (unsigned int)ptr + 2047; // 読み込み時に字数カウントしていればその条件にする while ((unsigned int)ptr < endptr) { if (*ptr == '.') { int cnt = 1; while (ptr[cnt] != '\0') { // 次の区切り文字までの字数カウントついでに拡張子の大文字は小文字にしてしまう if ((unsigned int)ptr + cnt >= endptr) { return wsprintfA(dst, src); } if ('A' <= ptr[cnt] && ptr[cnt] <= 'Z') { ptr[cnt] += 'a' - 'A'; } cnt++; } cnt++; if (lstrcmpiA(&ptr[cnt], str_movie_audio_file) == 0) { if (lstrcmpiA(ptr, (LPCSTR)(GLOBAL::aviutl_base + OFS::AviUtl::str_dot_avi)) != 0) { // ".avi" lstrcpyA(new_ext_buf, ptr); new_ext_buf += cnt; (*new_ext_num)++; } } ptr += cnt; } while (*ptr != '\0') { ptr++; } ptr++; } return wsprintfA(dst, src); } } // namespace patch #endif // ifdef PATCH_ADD_EXTENSION ================================================ FILE: patch/patch_add_extension.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_ADD_EXTENSION #include #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "restorable_patch.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // 動画、音声ファイル参照の時の拡張子にexedit.iniにあるものを追加する機能 inline class add_extension_t { static int __cdecl wsprintfA_wrap2701a(void* ebp, LPSTR dst, LPCSTR src); bool enabled = true; bool enabled_i; inline static const char key[] = "add_extension"; public: void init() { enabled_i = enabled; if (!enabled_i)return; { /* 0042701a ff1584f34600 call dword ptr [USER32.wsprintfA] 00427020 83c408 add esp,+08 ↓ 0042701a 55 push ebp 0042701b e8XxXxXxXx call wsprintfA_wrap2701a(void* ebp, LPSTR dst, LPCSTR src) 00427020 83c40c add esp,+0c 00427034 899df8faffff mov dword ptr [ebp+fffffaf8],ebx ↓ 00427034 eb04 jmp skip,+04 */ OverWriteOnProtectHelper h(GLOBAL::aviutl_base + 0x02701a, 28); h.store_i16(0, '\x55\xe8'); h.replaceNearJmp(2, &wsprintfA_wrap2701a); h.store_i8(8, '\x0c'); h.store_i16(26, '\xeb\x04'); } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } add_extension; } // namespace patch #endif // ifdef PATCH_SWITCH_ADD_EXTENSION ================================================ FILE: patch/patch_alpha_bg.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_ALPHA_BG #include #include namespace patch { // アルファチャンネル部分に背景を表示する // 凍結: 普段からアルファチャンネル付きでのレンダリングをしなきゃならない 容易に操作できるスイッチを用意しなければならない inline class alpha_bg_t { bool enabled = true; bool enabled_i; inline static const char key[] = "alpha_bg"; public: static BOOL func_proc(AviUtl::FilterPlugin* fp, AviUtl::FilterProcInfo* fpip) { const auto rect_size = 16; const auto pattern_size = rect_size * 2; if (!fp->exfunc->is_saving(fpip->editp)) { const auto w = fpip->w; const auto h = fpip->h; const auto ox = pattern_size - (w / 2) % pattern_size; const auto oy = pattern_size - (h / 2) % pattern_size; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { auto& p = *reinterpret_cast(reinterpret_cast(fpip->ycp_edit) + x * fpip->yc_size + y * fpip->line_size); if (( ((x + ox) % pattern_size < rect_size) ^ ((y + oy) % pattern_size < rect_size) ) == 1) { p = { 3584,0,0 }; } else { p = { 4096,0,0 }; } } } } return TRUE; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } bool init() { enabled_i = enabled; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } alpha_bg; } // namespace patch #endif // ifdef PATCH_SWITCH_ALPHA_BG ================================================ FILE: patch/patch_aup_layer_setting.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_AUP_LAYER_SETTING #include "global.hpp" #include "util.hpp" #include "restorable_patch.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // プロジェクトの保存時、レイヤー情報を保存する基準を変える // 従来:オブジェクトが存在するレイヤーのみ保存する(レイヤー情報が初期値であってもわざわざ保存する) // 変更:レイヤー情報が初期値以外のみ保存する // 保存時のみのパッチで互換性あり // パッチ有りで保存→パッチなしで読み込み:全てのレイヤー情報が読み込める inline class aup_layer_setting_t { bool enabled = true; bool enabled_i; inline static const char key[] = "aup_layer_setting"; public: void init() { enabled_i = enabled; if (!enabled_i)return; /* 100326b8 3bcb cmp ecx,ebx ; ecx=ObjectCount, ebx=i(0~ObjectCount) 100326ba 895c2410 mov dword ptr [esp+10],ebx ; 0 100326be 895c2414 mov dword ptr [esp+14],ebx ; 0 100326c2 7e3c jng 10032700 100326c4 8b0c85a88f1610 mov ecx,dword ptr [eax*4+10168fa8] ; ecx=SortedObjectTable[idx] 100326cb 40 inc eax ; idx++ 100326cc 8b91c4050000 mov edx,dword ptr [ecx+000005c4] 100326d2 c6041601 mov byte ptr [esi+edx],01 100326d6 8b0c85a48f1610 mov ecx,dword ptr [eax*4+10168fa4] 100326dd 8b91c4050000 mov edx,dword ptr [ecx+000005c4] 100326e3 8b89c0050000 mov ecx,dword ptr [ecx+000005c0] 100326e9 8d1492 lea edx,dword ptr [edx+edx*4] 100326ec 8d1492 lea edx,dword ptr [edx+edx*4] 100326ef 8d1491 lea edx,dword ptr [ecx+edx*4] 100326f2 c6042a01 mov byte ptr [edx+ebp],01 100326f6 8b0d50621410 mov ecx,dword ptr [10146250] 100326fc 3bc1 cmp eax,ecx 100326fe 7cc4 jl 100326c4 for(int i=0;iscene_set] = 1; layer_save_flag[obj->scene_set * 100 + obj->layer_set] = 1; } ↓ 100326b8 3bcb cmp ecx,ebx 100326ba 895c2410 mov dword ptr [esp+10],ebx 100326be 895c2414 mov dword ptr [esp+14],ebx 100326c2 7e1c jng 100326e0 100326c4 8b0c85a88f1610 mov ecx,dword ptr [eax*4+10168fa8] 100326cb 40 inc eax 100326cc 8b91c4050000 mov edx,dword ptr [ecx+000005c4] 100326d2 c6041601 mov byte ptr [esi+edx],01 100326d6 8b0d506214Xx mov ecx,dword ptr [10146250] 100326dc 3bc1 cmp eax,ecx 100326de 7ce4 jl 100326c4 100326e0 b810270000 mov eax,0x2710 ; 10000 100326e5 48 dec eax 100326e6 8b0c85988418Xx mov ecx,dword ptr [eax*4 + exedit+188498] ; scene_setting 100326ed 85c9 test ecx,ecx 100326ef 7409 jz skip,9 ; 100326fa 100326f1 8bd0 mov edx,eax 100326f3 c1ea01 shr edx,1 100326f6 c6042a01 mov byte ptr [edx+ebp],01 100326fa 85c0 test eax,eax 100326fc 75e7 jnz back,19 ; 100326e5 100326fe 90 nop 100326ff 90 nop for(int i=0;iscene_set] = 1; } for (int i = 0; i < 5000; i++) { if (layersetting[i].flag != 0 || layersetting[i].name != 0) { layer_save_flag[i] = 1; } } */ { } { /* for (int i = 0; i < 5000; i++) { if (layersetting[i].flag != 0 || layersetting[i].name != 0) { layer_save[i] = 1; } } */ char code_put[] = { /*\x8b*/"\x0d\x50\x62\x14\x00" // mov ecx,dword ptr [exedit+146250] "\x3b\xc1" // cmp eax,ecx "\x7c\xe4" // jl 100326c4 "\xb8\x10\x27\x00\x00" // mov eax,0x2710 ; 10000 "\x48" // dec eax "\x8b\x0c\x85\x98\x84\x18\x00"// mov ecx,dword ptr [eax*4+ exedit+188498] "\x85\xc9" // test ecx,ecx "\x74\x09" // jz skip,9 ; 100326fa "\x8b\xd0" // mov edx,eax "\xc1\xea\x01" // shr edx,1 "\xc6\x04\x2a\x01" // mov byte ptr [edx+ebp],01 "\x85\xc0" // test eax,eax "\x75\xe7" // jnz back,19 ; 100326e5 "\x90" // nop "\x90" // nop }; *(int*)(&code_put[1]) = GLOBAL::exedit_base + 0x146250; *(int*)(&code_put[18]) = GLOBAL::exedit_base + 0x188498; OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x0326c3, 61); h.store_i8(0, 0x1c); memcpy(reinterpret_cast(h.address()+20), code_put, sizeof(code_put) - 1); } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } aup_layer_setting; } // namespace patch #endif // ifdef PATCH_SWITCH_AUP_LAYER_SETTING ================================================ FILE: patch/patch_aup_scene_setting.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_AUP_SCENE_SETTING #include "global.hpp" #include "util.hpp" #include "restorable_patch.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // プロジェクトの保存/読み込み時にシーン設定の一部情報(グリッド設定など)が欠けるのを修正 inline class aup_scene_setting_t { bool enabled = true; bool enabled_i; inline static const char key[] = "aup_scene_setting"; public: void init() { enabled_i = enabled; if (!enabled_i)return; { char save_scene_setting_all[] = { "\x8d\x7e\x48" // lea edi,dword ptr [esi+48] ; dst "\x56" // push esi "\x8d\x75\x04" // lea esi,dword ptr [ebp+04] ; src "\xb9\x16\x00\x00\x00" // mov ecx,00000016 ; scenesetting.widthから22項目 "\xf3\xa5" // rep movsd "\x5e" // pop esi "\xeb\x2e" // jmp skip,2e (10032781) }; OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x032742, sizeof(save_scene_setting_all) - 1); memcpy(reinterpret_cast(h.address()), save_scene_setting_all, sizeof(save_scene_setting_all) - 1); } { /* 10031b48 8b4648 mov eax,dword ptr [esi+48] 10031b4b c1e205 shl edx,05 10031b4e 8982587a1710 mov dword ptr [edx+10177a58],eax 10031b54 ... ↓ 10031b48 8bc7 mov eax,edi 10031b4a 90 nop 10031b4b c1e205 shl edx,05 10031b4e 8dbaXxXxXxXx lea edi,dword ptr [edx+exedit+177a58] ; Xの部分は書きかえなければ良い 10031b54 ... load_scene_setting_all */ char load_scene_setting_all[] = { "\x83\xc6\x48" // add esi,+48 "\xb9\x15\x00\x00\x00" // mov ecx,00000015 ; こっちは21(22項目目はこの後に別の判定がある) "\xf3\xa5" // rep movsd "\x8b\xf8" // mov edi,eax "\x81\xee\x9c\x00\x00\x00" // sub esi,0000009c ; 21*4 + 0x48 "\x81\xfb\x2b\x23\x00\x00" // cmp ebx,0000232b "\xeb\x74" // jmp skip,74 (10031be2) }; OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x031b49, 25); h.store_i16(0, '\xc7\x90'); h.store_i16(5, '\x8d\xba'); memcpy(reinterpret_cast(h.address() + 11), load_scene_setting_all, sizeof(load_scene_setting_all) - 1); } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } aup_scene_setting; } // namespace patch #endif // ifdef PATCH_SWITCH_AUP_SCENE_SETTING ================================================ FILE: patch/patch_aviutl_wndproc_override.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_aviutl_wndproc_override.hpp" namespace patch { LRESULT CALLBACK aviutl_wndproc_override_t::wrap(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { auto org = [=]() { return aviutl_wndproc_orig(hwnd, message, wparam, lparam); }; switch (message) { case WM_MENUSELECT: #ifdef PATCH_SWITCH_CONSOLE if ((HMENU)lparam == aviutl_hmenu && HIWORD(wparam) & MF_POPUP) { console.update_visible_state(aviutl_hmwnu_disp); } #endif return org(); case WM_ACTIVATE: { static bool first_activate_gate = false; auto ret = org(); if (!first_activate_gate) { #ifdef PATCH_SWITCH_CONSOLE console.update_showwindow(); #endif first_activate_gate = true; } return ret; } case WM_COMMAND: { auto menuid = LOWORD(wparam); if (20000 <= menuid && menuid < 30000) { switch (menuid) { case PATCH_MENU_INFO: { MessageBoxA(hwnd, patchaul_info.get(), "patch.aul info", 0); return 0; } #ifdef PATCH_SWITCH_CONSOLE case PATCH_MENU_CONSOLE: { console.menu_console(aviutl_hmwnu_disp); return 0; } #endif } } break; } case WM_SYSCOMMAND: #ifdef PATCH_SWITCH_CONSOLE switch (wparam) { case SC_RESTORE: { auto ret = org(); if (console.visible) { console.showWindow(SW_RESTORE); } return ret; } case SC_MINIMIZE: { auto ret = org(); if (console.visible) { console.showWindow(SW_MINIMIZE); } return ret; } } #endif break; } return org(); } } // namespace patch ================================================ FILE: patch/patch_aviutl_wndproc_override.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include "macro.h" #include "cryptostring.hpp" #include "global.hpp" #include "offset_address.hpp" #include "version.hpp" #include "util.hpp" #include "patch_console.hpp" namespace patch { // init before filter plugin load // AviUtl のメインウィンドウのWndProcのフック inline class aviutl_wndproc_override_t { inline static HMENU aviutl_hmenu; // menu parent inline static HMENU aviutl_hmwnu_disp; // menu 表示 inline static WNDPROC aviutl_wndproc_orig; friend class console_t; static LRESULT CALLBACK wrap(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); public: inline void go() { auto hwnd = load_i32(GLOBAL::aviutl_base + OFS::AviUtl::edit_handle_ptr)->aviutl_window_info.main_window; aviutl_wndproc_orig = reinterpret_cast(SetWindowLongA(hwnd, GWL_WNDPROC, reinterpret_cast(wrap))); #ifdef PATCH_SWITCH_CONSOLE if (!patch::console.visible) console.showWindow(SW_MINIMIZE); #endif aviutl_hmenu = GetMenu(hwnd); aviutl_hmwnu_disp = GetSubMenu(aviutl_hmenu, 5); } } aviutl_wndproc_override; } // namespace patch ================================================ FILE: patch/patch_base.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once namespace patch { class patch_base1 { protected: bool enabled; public: void switch_true_to_false() {} void switch_false_to_true() {} void switch_enabled(bool flag) { if (flag) { if (!enabled) switch_false_to_true(); } else { if (enabled) switch_true_to_false(); } } }; class patch_base2 : public patch_base1 { protected: bool enabled_i; public: void switch_enabled(bool flag) { enabled = flag; } void init(bool flag) { enabled = enabled_i = flag; } }; } ================================================ FILE: patch/patch_blend.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_blend.hpp" #ifdef PATCH_SWITCH_BLEND namespace patch { void __cdecl blend_t::blend_yca_add(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a) { src_y += (dst->y * dst->a) >> 12; src_cb += (dst->cb * dst->a) >> 12; src_cr += (dst->cr * dst->a) >> 12; if (0x2000 < src_y) { if (src_y < 0x3000) { src_cb = ((0x3000 - src_y) * src_cb) >> 12; src_cr = ((0x3000 - src_y) * src_cr) >> 12; } else { src_cb = src_cr = 0; } src_y = 0x2000; } blend_yca_normal(dst, src_y, src_cb, src_cr, src_a); } void __cdecl blend_t::blend_yca_sub(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a) { src_y = ((dst->y * dst->a) >> 12) - src_y; src_cb = ((dst->cb * dst->a) >> 12) - src_cb; src_cr = ((dst->cr * dst->a) >> 12) - src_cr; if (src_y < 0) { if (src_y <= -0x400) { src_cb = src_cr = 0; } else { src_cb = ((src_y + 0x400) * src_cb) >> 10; src_cr = ((src_y + 0x400) * src_cr) >> 10; } src_y = 0; } blend_yca_normal(dst, src_y, src_cb, src_cr, src_a); } void __cdecl blend_t::blend_yca_mul(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a) { int fix_y = (dst->y * dst->a) >> 12; int fix_cb = (dst->cb * dst->a) >> 12; int fix_cr = (dst->cr * dst->a) >> 12; int src_t = (std::max)(0, ((src_cr * 0x59ba) >> 14) + src_y); int dst_t = (std::max)(0, ((fix_cr * 0x59ba) >> 14) + fix_y); int r = (std::min)((src_t * dst_t) >> 12, 0x2000); src_t = (std::max)(0, ((src_cb * -0x1604 + src_cr * -0x2db2) >> 14) + src_y); dst_t = (std::max)(0, ((fix_cb * -0x1604 + fix_cr * -0x2db2) >> 14) + fix_y); int g = (std::min)((src_t * dst_t) >> 12, 0x2000); src_t = (std::max)(0, ((src_cb * 0x7168) >> 14) + src_y); dst_t = (std::max)(0, ((fix_cb * 0x7168) >> 14) + fix_y); int b = (std::min)((src_t * dst_t) >> 12, 0x2000); src_y = (r * 0x1322 + g * 0x2591 + b * 0x74b ) >> 14; src_cb = (r * -0xad0 + g * -0x152f + b * 0x2000) >> 14; src_cr = (r * 0x2000 + g * -0x1ad0 + b * -0x52f) >> 14; blend_yca_normal(dst, src_y, src_cb, src_cr, src_a); } void __cdecl blend_t::blend_yca_screen(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a) { int fix_y = (dst->y * dst->a) >> 12; int fix_cb = (dst->cb * dst->a) >> 12; int fix_cr = (dst->cr * dst->a) >> 12; int src_t = (std::max)(0, ((src_cr * 0x59ba) >> 14) + src_y); int dst_t = (std::max)(0, ((fix_cr * 0x59ba) >> 14) + fix_y); int r = dst_t - ((dst_t * src_t) >> 12) + src_t; src_t = (std::max)(0, ((src_cb * -0x1604 + src_cr * -0x2db2) >> 14) + src_y); dst_t = (std::max)(0, ((fix_cb * -0x1604 + fix_cr * -0x2db2) >> 14) + fix_y); int g = dst_t - ((dst_t * src_t) >> 12) + src_t; src_t = (std::max)(0, ((src_cb * 0x7168) >> 14) + src_y); dst_t = (std::max)(0, ((fix_cb * 0x7168) >> 14) + fix_y); int b = dst_t - ((dst_t * src_t) >> 12) + src_t; src_y = (r * 0x1322 + g * 0x2591 + b * 0x74b ) >> 14; src_cb = (r * -0xad0 + g * -0x152f + b * 0x2000) >> 14; src_cr = (r * 0x2000 + g * -0x1ad0 + b * -0x52f) >> 14; blend_yca_normal(dst, src_y, src_cb, src_cr, src_a); } void __cdecl blend_t::blend_yca_overlay(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a) { int fix_y = (dst->y * dst->a) >> 12; int fix_cb = (dst->cb * dst->a) >> 12; int fix_cr = (dst->cr * dst->a) >> 12; int src_t = (std::max)(0, ((src_cr * 0x59ba) >> 14) + src_y); int dst_t = (std::max)(0, ((fix_cr * 0x59ba) >> 14) + fix_y); int r = (dst_t * src_t) >> 11; if (0x800 <= dst_t) { r = (dst_t + src_t) * 2 - 0x1000 - r; } src_t = (std::max)(0, ((src_cb * -0x1604 + src_cr * -0x2db2) >> 14) + src_y); dst_t = (std::max)(0, ((fix_cb * -0x1604 + fix_cr * -0x2db2) >> 14) + fix_y); int g = (dst_t * src_t) >> 11; if (0x800 <= dst_t) { g = (dst_t + src_t) * 2 - 0x1000 - g; } src_t = (std::max)(0, ((src_cb * 0x7168) >> 14) + src_y); dst_t = (std::max)(0, ((fix_cb * 0x7168) >> 14) + fix_y); int b = (dst_t * src_t) >> 11; if (0x800 <= dst_t) { b = (dst_t + src_t) * 2 - 0x1000 - b; } src_y = (r * 0x1322 + g * 0x2591 + b * 0x74b ) >> 14; src_cb = (r * -0xad0 + g * -0x152f + b * 0x2000) >> 14; src_cr = (r * 0x2000 + g * -0x1ad0 + b * -0x52f) >> 14; blend_yca_normal(dst, src_y, src_cb, src_cr, src_a); } void __cdecl blend_t::blend_yca_cmpmax(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a) { int fix_y = (dst->y * dst->a) >> 12; int fix_cb = (dst->cb * dst->a) >> 12; int fix_cr = (dst->cr * dst->a) >> 12; int r = (std::max)(((src_cr * 0x59ba) >> 14) + src_y, ((fix_cr * 0x59ba) >> 14) + fix_y); int g = (std::max)(((src_cb * -0x1604 + src_cr * -0x2db2) >> 14) + src_y, ((fix_cb * -0x1604 + fix_cr * -0x2db2) >> 14) + fix_y); int b = (std::max)(((src_cb * 0x7168) >> 14) + src_y, ((fix_cb * 0x7168) >> 14) + fix_y); src_y = (r * 0x1322 + g * 0x2591 + b * 0x74b ) >> 14; src_cb = (r * -0xad0 + g * -0x152f + b * 0x2000) >> 14; src_cr = (r * 0x2000 + g * -0x1ad0 + b * -0x52f) >> 14; blend_yca_normal(dst, src_y, src_cb, src_cr, src_a); } void __cdecl blend_t::blend_yca_cmpmin(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a) { int fix_y = (dst->y * dst->a) >> 12; int fix_cb = (dst->cb * dst->a) >> 12; int fix_cr = (dst->cr * dst->a) >> 12; int r = (std::min)(((src_cr * 0x59ba) >> 14) + src_y, ((fix_cr * 0x59ba) >> 14) + fix_y); int g = (std::min)(((src_cb * -0x1604 + src_cr * -0x2db2) >> 14) + src_y, ((fix_cb * -0x1604 + fix_cr * -0x2db2) >> 14) + fix_y); int b = (std::min)(((src_cb * 0x7168) >> 14) + src_y, ((fix_cb * 0x7168) >> 14) + fix_y); src_y = (r * 0x1322 + g * 0x2591 + b * 0x74b ) >> 14; src_cb = (r * -0xad0 + g * -0x152f + b * 0x2000) >> 14; src_cr = (r * 0x2000 + g * -0x1ad0 + b * -0x52f) >> 14; blend_yca_normal(dst, src_y, src_cb, src_cr, src_a); } void __cdecl blend_t::blend_yca_luminance(ExEdit::PixelYCA* dst, short src_y, short src_cb, short src_cr, short src_a) { if (0x1000 <= src_a) { dst->y = src_y; dst->cb = (dst->cb * dst->a) >> 12; dst->cr = (dst->cr * dst->a) >> 12; dst->a = 0x1000; } else if (0x1000 <= dst->a) { dst->y += ((src_y - dst->y) * src_a) >> 12; dst->a = 0x1000; } else if (dst->a <= 0) { dst->y = src_y; dst->cb = 0; dst->cr = 0; dst->a = src_a; } else { short new_a = (0x1000800 - (0x1000 - dst->a) * (0x1000 - src_a)) >> 12; dst->y = (((dst->y * dst->a) >> 12) * (0x1000 - src_a) + src_y * src_a) / new_a; dst->cb = dst->cb * dst->a / new_a; dst->cr = dst->cr * dst->a / new_a; dst->a = new_a; } } void __cdecl blend_t::blend_yca_colordiff(ExEdit::PixelYCA* dst, short src_y, short src_cb, short src_cr, short src_a) { if (0x1000 <= src_a) { dst->y = (dst->y * dst->a) >> 12; dst->cb = src_cb; dst->cr = src_cr; dst->a = 0x1000; } else if (0x1000 <= dst->a) { dst->cb += ((src_cb - dst->cb) * src_a) >> 12; dst->cr += ((src_cr - dst->cr) * src_a) >> 12; dst->a = 0x1000; } else if (dst->a <= 0) { dst->y = 0; dst->cb = src_cb; dst->cr = src_cr; dst->a = src_a; } else { int new_a = (0x1000800 - (0x1000 - dst->a) * (0x1000 - src_a)) >> 12; int new_dst_a = (0x1000 - src_a) * dst->a / new_a; int new_src_a = (src_a << 12) / new_a; dst->y = dst->y * dst->a / new_a; dst->cb = (dst->cb * new_dst_a + src_cb * new_src_a) >> 12; dst->cr = (dst->cr * new_dst_a + src_cr * new_src_a) >> 12; dst->a = new_a; } } void __cdecl blend_t::blend_yca_shadow(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a) { int fix_y = (dst->y * dst->a) >> 12; int fix_cb = (dst->cb * dst->a) >> 12; int fix_cr = (dst->cr * dst->a) >> 12; int src_t = (std::max)(0, ((src_cr * 0x59ba) >> 14) + src_y); int dst_t = (std::max)(0, ((fix_cr * 0x59ba) >> 14) + fix_y); int r = (std::max)(0, dst_t + src_t - 0x1000); src_t = (std::max)(0, ((src_cb * -0x1604 + src_cr * -0x2db2) >> 14) + src_y); dst_t = (std::max)(0, ((fix_cb * -0x1604 + fix_cr * -0x2db2) >> 14) + fix_y); int g = (std::max)(0, dst_t + src_t - 0x1000); src_t = (std::max)(0, ((src_cb * 0x7168) >> 14) + src_y); dst_t = (std::max)(0, ((fix_cb * 0x7168) >> 14) + fix_y); int b = (std::max)(0, dst_t + src_t - 0x1000); src_y = (r * 0x1322 + g * 0x2591 + b * 0x74b ) >> 14; src_cb = (r * -0xad0 + g * -0x152f + b * 0x2000) >> 14; src_cr = (r * 0x2000 + g * -0x1ad0 + b * -0x52f) >> 14; blend_yca_normal(dst, src_y, src_cb, src_cr, src_a); } void __cdecl blend_t::blend_yca_lightdark(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a) { int fix_y = (dst->y * dst->a) >> 12; int fix_cb = (dst->cb * dst->a) >> 12; int fix_cr = (dst->cr * dst->a) >> 12; int src_t = ((src_cr * 0x59ba) >> 14) + src_y; int dst_t = ((fix_cr * 0x59ba) >> 14) + fix_y; int r = std::clamp(dst_t + src_t * 2 - 0x1000, 0, 0x2000); src_t = ((src_cb * -0x1604 + src_cr * -0x2db2) >> 14) + src_y; dst_t = ((fix_cb * -0x1604 + fix_cr * -0x2db2) >> 14) + fix_y; int g = std::clamp(dst_t + src_t * 2 - 0x1000, 0, 0x2000); src_t = ((src_cb * 0x7168) >> 14) + src_y; dst_t = ((fix_cb * 0x7168) >> 14) + fix_y; int b = std::clamp(dst_t + src_t * 2 - 0x1000, 0, 0x2000); src_y = (r * 0x1322 + g * 0x2591 + b * 0x74b ) >> 14; src_cb = (r * -0xad0 + g * -0x152f + b * 0x2000) >> 14; src_cr = (r * 0x2000 + g * -0x1ad0 + b * -0x52f) >> 14; blend_yca_normal(dst, src_y, src_cb, src_cr, src_a); } void __cdecl blend_t::blend_yca_difference(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a) { int sub_y = src_y - ((dst->y * dst->a) >> 12); int sub_cb = src_cb - ((dst->cb * dst->a) >> 12); int sub_cr = src_cr - ((dst->cr * dst->a) >> 12); int r = abs(((sub_cr * 0x59ba) >> 14) + sub_y); int g = abs(((sub_cb * -0x1604 + sub_cr * -0x2db2) >> 14) + sub_y); int b = abs(((sub_cb * 0x7168) >> 14) + sub_y); src_y = (r * 0x1322 + g * 0x2591 + b * 0x74b ) >> 14; src_cb = (r * -0xad0 + g * -0x152f + b * 0x2000) >> 14; src_cr = (r * 0x2000 + g * -0x1ad0 + b * -0x52f) >> 14; blend_yca_normal(dst, src_y, src_cb, src_cr, src_a); } } // namespace patch #endif // ifdef PATCH_SWITCH_BLEND ================================================ FILE: patch/patch_blend.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_BLEND #include #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "restorable_patch.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // 合成モード関数の修正(主にアルファチャンネル有りシーンオブジェクト) inline class blend_t { static void __cdecl blend_yca_add(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a); static void __cdecl blend_yca_sub(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a); static void __cdecl blend_yca_mul(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a); static void __cdecl blend_yca_screen(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a); static void __cdecl blend_yca_overlay(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a); static void __cdecl blend_yca_cmpmax(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a); static void __cdecl blend_yca_cmpmin(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a); static void __cdecl blend_yca_luminance(ExEdit::PixelYCA* dst, short src_y, short src_cb, short src_cr, short src_a); static void __cdecl blend_yca_colordiff(ExEdit::PixelYCA* dst, short src_y, short src_cb, short src_cr, short src_a); static void __cdecl blend_yca_shadow(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a); static void __cdecl blend_yca_lightdark(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a); static void __cdecl blend_yca_difference(ExEdit::PixelYCA* dst, int src_y, int src_cb, int src_cr, int src_a); bool enabled = true; bool enabled_i; inline static const char key[] = "blend"; public: inline static void(__cdecl* blend_yca_normal)(void* dst, int src_y, int src_cb, int src_cr, int src_a); void init() { enabled_i = enabled; if (!enabled_i)return; blend_yca_normal = reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::blend_yca_normal_func); { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x9fbb4, 48); h.store_i32(0, &blend_yca_add); h.store_i32(4, &blend_yca_sub); h.store_i32(8, &blend_yca_mul); h.store_i32(12, &blend_yca_screen); h.store_i32(16, &blend_yca_overlay); h.store_i32(20, &blend_yca_cmpmax); h.store_i32(24, &blend_yca_cmpmin); h.store_i32(28, &blend_yca_luminance); h.store_i32(32, &blend_yca_colordiff); h.store_i32(36, &blend_yca_shadow); h.store_i32(40, &blend_yca_lightdark); h.store_i32(44, &blend_yca_difference); } char blend_yca_normal_bin[] = { "\x8b\x4c\x24\x04" // mov ecx,dword ptr [esp+04] "\x8b\x54\x24\x14" // mov edx,dword ptr [esp+14] "\xb8\x00\x10\x00\x00" // mov eax,00001000 "\x3b\xd0" // cmp edx,eax "\x7c\x1f" // jl 10007e20 "\x66\x89\x41\x06" // mov [ecx+06],ax "\x66\x8b\x44\x24\x08" // mov ax,[esp+08] "\x66\x8b\x54\x24\x0c" // mov dx,[esp+0c] "\x66\x89\x01" // mov [ecx],ax "\x66\x8b\x44\x24\x10" // mov ax,[esp+10] "\x66\x89\x51\x02" // mov [ecx+02],dx "\x66\x89\x41\x04" // mov [ecx+04],ax "\xc3" // ret "\x56" // push esi "\x0f\xbf\x71\x06" // movsx esi,dword ptr [ecx+06] "\x3b\xf0" // cmp esi,eax "\x7c\x40" // jl 10007e69 "\x66\x89\x41\x06" // mov [ecx+06],ax "\x0f\xbf\x31" // movsx esi,dword ptr [ecx] "\x8b\x44\x24\x0c" // mov eax,dword ptr [esp+0c] "\x2b\xc6" // sub eax,esi "\x0f\xaf\xc2" // imul eax,edx "\xc1\xf8\x0c" // sar eax,0c "\x66\x01\x01" // add [ecx],ax "\x0f\xbf\x71\x02" // movsx esi,dword ptr [ecx+02] "\x8b\x44\x24\x10" // mov eax,dword ptr [esp+10] "\x2b\xc6" // sub eax,esi "\x0f\xaf\xc2" // imul eax,edx "\xc1\xf8\x0c" // sar eax,0c "\x66\x01\x41\x02" // add [ecx+02],ax "\x0f\xbf\x71\x04" // movsx esi,dword ptr [ecx+04] "\x8b\x44\x24\x14" // mov eax,dword ptr [esp+14] "\x2b\xc6" // sub eax,esi "\x0f\xaf\xc2" // imul eax,edx "\xc1\xf8\x0c" // sar eax,0c "\x66\x01\x41\x04" // add [ecx+04],ax "\x5e" // pop esi "\xc3" // ret "\x85\xf6" // test esi,esi "\x7f\x20" // jg 10007e90 "\x66\x89\x51\x06" // mov [ecx+06],dx "\x66\x8b\x44\x24\x0c" // mov ax,[esp+0c] "\x66\x8b\x54\x24\x10" // mov dx,[esp+10] "\x66\x89\x01" // mov [ecx],ax "\x66\x8b\x44\x24\x14" // mov ax,[esp+14] "\x66\x89\x51\x02" // mov [ecx+02],dx "\x66\x89\x41\x04" // mov [ecx+04],ax "\x5e" // pop esi "\xc3" // ret "\x53" // push ebx "\x8b\xd8" // mov ebx,eax "\x2b\xde" // sub ebx,esi "\x2b\xc2" // sub eax,edx "\x0f\xaf\xd8" // imul ebx,eax "\x0f\xaf\xc6" // imul eax,esi "\xbe\x00\x08\x00\x01" // mov esi,01000800 "\x2b\xf3" // sub esi,ebx "\xc1\xfe\x0c" // sar esi,0c "\x66\x89\x71\x06" // mov [ecx+06],si "\x99" // cdq "\xf7\xfe" // idiv esi "\x8b\xd8" // mov ebx,eax "\x8b\x44\x24\x1c" // mov eax,dword ptr [esp+1c] "\xc1\xe0\x0c" // shl eax,0c "\x99" // cdq "\xf7\xfe" // idiv esi "\x0f\xbf\x11" // movsx edx,dword ptr [ecx] "\x0f\xaf\xd3" // imul edx,ebx "\x8b\x74\x24\x10" // mov esi,dword ptr [esp+10] "\x0f\xaf\xf0" // imul esi,eax "\x03\xd6" // add edx,esi "\xc1\xfa\x0c" // sar edx,0c "\x66\x89\x11" // mov [ecx],dx "\x0f\xbf\x51\x02" // movsx edx,dword ptr [ecx+02] "\x0f\xaf\xd3" // imul edx,ebx "\x8b\x74\x24\x14" // mov esi,dword ptr [esp+14] "\x0f\xaf\xf0" // imul esi,eax "\x03\xd6" // add edx,esi "\xc1\xfa\x0c" // sar edx,0c "\x66\x89\x51\x02" // mov [ecx+02],dx "\x0f\xbf\x51\x04" // movsx edx,dword ptr [ecx+04] "\x0f\xaf\xd3" // imul edx,ebx "\x8b\x74\x24\x18" // mov esi,dword ptr [esp+18] "\x0f\xaf\xf0" // imul esi,eax "\x03\xd6" // add edx,esi "\xc1\xfa\x0c" // sar edx,0c "\x66\x89\x51\x04" // mov [ecx+04],dx "\x5b" // pop ebx "\x5e" // pop esi "\xc3" // ret }; { OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::blend_yca_normal_func, sizeof(blend_yca_normal_bin) - 1); memcpy(reinterpret_cast(h.address()), blend_yca_normal_bin, sizeof(blend_yca_normal_bin) - 1); } { char blend_yc_normal_bin[] = { "\x8b\x4c\x24\x04" // mov ecx,dword ptr [esp+04] "\x8b\x54\x24\x14" // mov edx,dword ptr [esp+14] "\x81\xfa\x00\x10\x00\x00" // cmp edx,00001000 "\x7c\x1b" // jl 10007f4b "\x66\x8b\x44\x24\x08" // mov ax,[esp+08] "\x66\x8b\x54\x24\x0c" // mov dx,[esp+0c] "\x66\x89\x01" // mov [ecx],ax "\x66\x8b\x44\x24\x10" // mov ax,[esp+10] "\x66\x89\x51\x02" // mov [ecx+02],dx "\x66\x89\x41\x04" // mov [ecx+04],ax "\xc3" // ret "\x56" // push esi }; OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::blend_yc_normal_func, 104); memcpy(reinterpret_cast(h.address()), blend_yc_normal_bin, sizeof(blend_yc_normal_bin) - 1); memcpy(reinterpret_cast(h.address() + sizeof(blend_yc_normal_bin) - 1), &blend_yca_normal_bin[61], 60); } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } blend; } // namespace patch #endif // ifdef PATCH_SWITCH_BLEND ================================================ FILE: patch/patch_colorpalette_cache.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_COLORPALETTE_CACHE #include "global.hpp" #include "config_rw.hpp" #include "util.hpp" namespace patch { // bmpのキャッシュをとる際に、カラーパレット分のデータ容量を取り忘れているのを修正 inline class colorpalette_cache_t { inline static int __cdecl fix_size_2a6a(uintptr_t avi_file_handle) { int video_decode_w = *(int*)(avi_file_handle + 20); int video_decode_h = *(int*)(avi_file_handle + 24); short video_decode_bit = *(short*)(avi_file_handle + 30); int size = (video_decode_bit * video_decode_w + 7) >> 3; size = (size + 3 & 0xfffffffc) * video_decode_h; switch (video_decode_bit) { case 32:case 24:case 16: size += 16; break; case 8: size += 1040; break; case 4: size += 80; break; default: size += 24; } return size; } bool enabled = true; bool enabled_i; inline static const char key[] = "colorpalette_cache"; public: void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void init() { enabled_i = enabled; if (!enabled_i)return; { /* 00402a68 89442418 mov dword ptr [esp+18],eax 00402a6c 8d0c8510000000 lea ecx,dword ptr [eax*4+00000010] 00402a73 51 push ecx ↓ 00402a68 56 push esi ; avi_file_handle 00402a69 e8xxxxxxxx call fix_size_2a6a() 00402a6e 5e pop esi 00402a6f 89442418 mov dword ptr [esp+18],eax 00402a73 50 push eax 00402a88 c1e102 shl ecx,02 ↓ 00402a88 83e910 sub ecx,10 */ OverWriteOnProtectHelper h(GLOBAL::aviutl_base + 0x2a68, 35); h.store_i16(0, '\x56\xe8'); h.replaceNearJmp(2, &fix_size_2a6a); h.store_i32(6, '\x5e\x89\x44\x24'); h.store_i16(10, '\x18\x50'); h.store_i16(32, '\x83\xe9'); h.store_i8(34, '\x10'); } } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } colorpalette_cache; } // namespace patch #endif // ifdef PATCH_SWITCH_COLORPALETTE_CACHE ================================================ FILE: patch/patch_console.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_console.hpp" #ifdef PATCH_SWITCH_DEBUGSTRING #include #include #include "patch_console.hpp" namespace patch { void __stdcall console_t::debug_print_override(LPCSTR lpOutputString) { if (!lpOutputString)return; console.setConsoleTextAttribute(FOREGROUND_BLUE | FOREGROUND_INTENSITY); if (console.debug_string_time) console.writeConsole("[{}]\t"_fmt(get_local_time_string())); console.writeConsole(lpOutputString); console.setConsoleTextAttribute(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); console.writeConsole("\n"); } void __stdcall console_t::exedit_lua_error_override(LPCSTR lpOutputString) { if (!lpOutputString)return; console.setConsoleTextAttribute(FOREGROUND_RED | FOREGROUND_INTENSITY); if (console.debug_string_time) console.writeConsole("[{}]\t"_fmt(get_local_time_string())); console.writeConsole(lpOutputString); console.setConsoleTextAttribute(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); console.writeConsole("\n"); } } // namespace patch #endif // ifdef PATCH_SWITCH_DEBUGSTRING ================================================ FILE: patch/patch_console.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_CONSOLE #include #include #include #include #include "global.hpp" #include "util.hpp" #include "config_rw.hpp" namespace patch { // init at dllload // コンソール関連 inline class console_t { HANDLE h_stdout; HWND console_hwnd; bool valid; bool enabled = true; bool enabled_i; inline static const char key[] = "console"; inline static const char key_escape[] = "console.escape"; inline static const char key_input[] = "console.input"; inline static const char key_debug_string[] = "console.debug_string"; inline static const char key_debug_string_time[] = "console.debug_string.time"; bool escape = true; bool input = false; bool debug_string = true; bool debug_string_time = true; inline static const char key_visible[] = "visible"; inline static const char key_rect[] = "rect"; bool visible = false; std::optional rect; static void __stdcall debug_print_override(LPCSTR lpOutputString); static void __stdcall exedit_lua_error_override(LPCSTR lpOutputString); inline static constexpr auto* debug_print_override_ptr = &debug_print_override; inline static constexpr auto* exedit_lua_error_override_ptr = &exedit_lua_error_override; public: friend class aviutl_wndproc_override_t; void exit() { writeConsole("bye"); FreeConsole(); } void init() { enabled_i = enabled; if (!enabled_i)return; if (AllocConsole() != TRUE) { patch_resource_message_w(PATCH_RS_PATCH_FAILED_TO_INIT_CONSOLE, MB_TASKMODAL | MB_ICONERROR); valid = false; return; } console_hwnd = GetConsoleWindow(); if (rect) { SetWindowPos(console_hwnd, NULL, rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top, SWP_NOZORDER | SWP_NOACTIVATE); } update_showwindow(); SetConsoleTitleA("Console Window"); h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); if (escape) { DWORD consoleMode; GetConsoleMode(h_stdout, &consoleMode); SetConsoleMode(h_stdout, consoleMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); } FILE* fp; if (input) { freopen_s(&fp, "CONIN$", "r", stdin); } freopen_s(&fp, "CONOUT$", "w", stderr); freopen_s(&fp, "CONOUT$", "w", stdout); setConsoleTextAttribute(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY); writeConsole("patch.aul\n"); setConsoleTextAttribute(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); valid = true; } void init_at_exedit_init() { #ifdef PATCH_SWITCH_DEBUGSTRING if (debug_string) { OverWriteOnProtectHelper(GLOBAL::exedit_base + OFS::ExEdit::OutputDebugString_calling_err1, 4).store_i32(0, &exedit_lua_error_override_ptr); OverWriteOnProtectHelper(GLOBAL::exedit_base + OFS::ExEdit::OutputDebugString_calling_err2, 4).store_i32(0, &exedit_lua_error_override_ptr); OverWriteOnProtectHelper(GLOBAL::exedit_base + OFS::ExEdit::OutputDebugString_calling_err3, 4).store_i32(0, &exedit_lua_error_override_ptr); OverWriteOnProtectHelper(GLOBAL::exedit_base + OFS::ExEdit::OutputDebugString_calling_dbg, 4).store_i32(0, &debug_print_override_ptr); } #endif } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void config_load(ConfigReader& cr) { cr.regist(key_visible, [this](json_value_s* value) { ConfigReader::load_variable(value, visible); }); cr.regist(key_rect, [this](json_value_s* value) { ConfigReader::load_variable(value, rect); }); } void config_store(ConfigWriter& cw) { cw.append(key_visible, visible); if (!IsIconic(console_hwnd)) { RECT rect; if (GetWindowRect(console_hwnd, &rect) == TRUE) { cw.append(key_rect, rect); } } } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); cr.regist(key_escape, [this](json_value_s* value) { ConfigReader::load_variable(value, escape); }); cr.regist(key_input, [this](json_value_s* value) { ConfigReader::load_variable(value, input); }); cr.regist(key_debug_string, [this](json_value_s* value) { ConfigReader::load_variable(value, debug_string); }); cr.regist(key_debug_string_time, [this](json_value_s* value) { ConfigReader::load_variable(value, debug_string_time); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); cw.append(key_escape, escape); cw.append(key_input, input); cw.append(key_debug_string, debug_string); cw.append(key_debug_string_time, debug_string_time); } bool is_valid() const { return valid; } // コンソールの表示 メニューが押されたときに呼ばれる関数 void menu_console(HMENU aviutl_hmwnu_disp) { if (!enabled_i) { patch_resource_message_w(PATCH_RS_PATCH_CONSOLE_IS_DIABLED, MB_TOPMOST | MB_ICONINFORMATION); return; } bool& console_flag = visible; if (GetKeyState(VK_LCONTROL) & 0x8000 | GetKeyState(VK_RCONTROL) & 0x8000) { console_flag = true; } else { console_flag = !console_flag; } modify_menuitem_check(aviutl_hmwnu_disp, 20002, FALSE, [console_flag](bool state) { return console_flag; }); update_showwindow(); } DWORD writeConsole(std::string_view str) { DWORD written; WriteConsoleA(h_stdout, str.data(), str.length(), &written, NULL); return written; } void setConsoleTextAttribute(WORD wAttributes) { SetConsoleTextAttribute(h_stdout, wAttributes); } void showWindow(int nCmdShow) { ShowWindow(console_hwnd, nCmdShow); } // コンソールウィンドウを前面に移動させる void front() const { SetWindowPos(console_hwnd, HWND_NOTOPMOST, NULL, NULL, NULL, NULL, SWP_NOSIZE | SWP_NOMOVE); } void update_visible_state(HMENU aviutl_hmwnu_disp) { modify_menuitem_check(aviutl_hmwnu_disp, 20002, FALSE, [this](bool state) -> bool { if (input) { visible = !IsIconic(console_hwnd); } return visible; }); } void console_get_setting_rect(std::optional& rect) const { if (!IsIconic(console_hwnd)) { rect = RECT{}; if (GetWindowRect(console_hwnd, &rect.value()) == FALSE) rect = std::nullopt; } } void update_showwindow() { bool& console_flag = visible; if (input) { if (console_flag) { showWindow(SW_RESTORE); } else { console_get_setting_rect(rect); showWindow(SW_MINIMIZE); } } else { if (console_flag) { showWindow(SW_RESTORE); showWindow(SW_SHOW); } else { showWindow(SW_HIDE); } } } } console; } // namespace patch #endif // ifdef PATCH_SWITCH_CONSOLE ================================================ FILE: patch/patch_copybuffer_smem.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_LUA_COPYBUFFER_SMEM #include #include #include #include #include #include #include #include #include #include #include #include "mylua.hpp" namespace patch { using namespace std::literals::string_literals; // init at exedit load // obj.copybufferによるキャッシュを共有メモリに確保する inline struct copybuffer_smem_t { private: struct YCABuffer { int w, h; ExEdit::PixelYCA buf[]; }; inline static std::unordered_map> smem; struct BufferBasic{}; struct BufferNamed : public BufferBasic { std::string name; }; struct BufferObj : public BufferBasic {}; struct BufferFrm : public BufferBasic {}; struct BufferTmp : public BufferBasic {}; struct BufferCache : public BufferNamed {}; struct BufferImage : public BufferNamed {}; using Buffer = std::variant; enum class BufferId { Obj, Tmp, Frm, Cache, Image, Invalid = -1 }; inline static Buffer getBufferIdAll(std::string_view name) { if (auto cmp = ::strnicmp(name.data(), "image:", 6) <=> 0; cmp < 0) { if (auto cmp = ::stricmp(name.data(), "frm") <=> 0; cmp < 0) { if (auto cmp = ::strnicmp(name.data(), "cache:", 6) <=> 0; cmp != 0) return std::monostate{}; return BufferCache{ BufferNamed{ .name = { name.begin() + 6, name.end() } } }; } else if(cmp == 0){ // frm return BufferFrm{}; } } else if(cmp == 0) { // image: return BufferImage{ BufferNamed{ .name = { name.begin() + 6, name.end() } } }; } else { if (auto cmp = ::stricmp(name.data(), "obj") <=> 0; cmp == 0) { // obj return BufferObj{}; } else { // tmp if (auto cmp = ::stricmp(name.data(), "tmp") <=> 0; cmp != 0) return std::monostate{}; return BufferTmp{}; } } return std::monostate{}; } inline static Buffer getBufferIdDst(std::string_view name) { if (auto cmp = ::stricmp(name.data(), "obj") <=> 0; cmp < 0) { // cache: if (auto cmp = ::strnicmp(name.data(), "cache:", 6) <=> 0; cmp != 0) return std::monostate{}; return BufferCache{ BufferNamed{ .name = { name.begin() + 6, name.end() } } }; } else if(cmp == 0) { // obj: return BufferObj{}; } else { // tmp if (auto cmp = ::stricmp(name.data(), "tmp") <=> 0; cmp != 0) return std::monostate{}; return BufferTmp{}; } return std::monostate{}; } static Buffer getBufferIdFromReadonly(std::string_view name) { if (auto cmp = ::stricmp(name.data(), "obj") <=> 0; cmp == 0) { // obj: return BufferObj{}; } else { // tmp if (auto cmp = ::stricmp(name.data(), "tmp") <=> 0; cmp != 0) return std::monostate{}; return BufferTmp{}; } return std::monostate{}; } struct VisitorSrc { std::string_view dst_name; bool operator()(std::monostate) { return false; } bool operator()(BufferObj) { auto dst = getBufferIdDst(dst_name); if(std::holds_alternative(dst)) return false; if(std::holds_alternative(dst)) return true; return true; } bool operator()(BufferTmp) { auto dst = getBufferIdDst(dst_name); if(std::holds_alternative(dst)) return false; if(std::holds_alternative(dst)) return true; return true; } bool operator()(BufferFrm) { auto dst = getBufferIdFromReadonly(dst_name); if(std::holds_alternative(dst)) return false; return true; } bool operator()(BufferCache src) { if(src.name.empty()) return false; auto dst = getBufferIdDst(dst_name); if(std::holds_alternative(dst)) return false; if(std::holds_alternative(dst)) { return std::get(dst).name == src.name; } return true; } bool operator()(BufferImage src) { if(src.name.empty()) return false; auto dst = getBufferIdFromReadonly(dst_name); if(std::holds_alternative(dst)) return false; return true; } }; static int copybuffer_override(lua_State* L) { auto src = getBufferIdAll(lua_tostring(L, 2)); lua_pushboolean(L, std::visit(VisitorSrc{lua_tostring(L, 1)}, src)); return 1; } public: void operator()() { } } copybuffer_smem; } // namespace patch #endif // ifdef PATCH_SWITCH_LUA_COPYBUFFER_SMEM ================================================ FILE: patch/patch_dialog_new_file.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_DIALOG_NEW_FILE #include #include "global.hpp" #include "util.hpp" namespace patch { // init at exedit load // 新規プロジェクト作成ダイアログの画像サイズ入力欄の幅を上げる inline class dlg_newfile_t { bool enabled = true; bool enabled_i; inline static const char key[] = "new_project_editbox"; public: void init() { enabled_i = enabled; if (!enabled_i)return; { DLGITEMTEMPLATE* width_edit= (DLGITEMTEMPLATE*)(GLOBAL::exedit_base + 0x252d88); OverWriteOnProtectHelper h((int)width_edit, sizeof(DLGITEMTEMPLATE)); width_edit->x = 51; // original = 60 width_edit->cx = 27; // original = 20 } { DLGITEMTEMPLATE* times_static = (DLGITEMTEMPLATE*)(GLOBAL::exedit_base + 0x252da4); OverWriteOnProtectHelper h((int)times_static, sizeof(DLGITEMTEMPLATE)); times_static->x = 78; // original = 81 } { DLGITEMTEMPLATE* height_edit = (DLGITEMTEMPLATE*)(GLOBAL::exedit_base + 0x252dc0); OverWriteOnProtectHelper h((int)height_edit, sizeof(DLGITEMTEMPLATE)); height_edit->x = 85; // original = 89 height_edit->cx = 27; // original = 20 } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } dialog_new_file; } // namespace patch #endif // ifdef PATCH_SWITCH_DIALOG_NEW_FILE ================================================ FILE: patch/patch_exception_history.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include #include #include namespace patch { // ExceptionHistory の要素型 // オフセットアドレスと例外コード struct ExceptionHistoryEntry { uint32_t address; uint32_t code; struct Hash { using result_type = uint32_t; result_type operator()(const ExceptionHistoryEntry& history) const { return history.address ^ history.code; } }; bool operator==(const ExceptionHistoryEntry& x) const { return this->address == x.address && this->code == x.code; } }; // しばらく同種のメッセージの表示を停止する のためのもの // 過去に出た例外のコードとオフセットアドレスを連想配列に記憶する inline struct ExceptionHistory { std::mutex mtx; std::unordered_map map; // 過去10分以内に出たことのある例外ならtrueを返す [[nodiscard]] bool check(const ExceptionHistoryEntry& key) { using namespace std::chrono_literals; std::lock_guard lock(mtx); if (auto itr = map.find(key); itr != map.end()) { if (std::chrono::system_clock::now() - itr->second < std::chrono::system_clock::duration(10min)) { return true; } map.erase(itr); } return false; } } exception_history; } // namespace patch ================================================ FILE: patch/patch_exception_log.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_exception_log.hpp" #include "patch_exception_history.hpp" #include "moduledata.hpp" #include "util_resource.hpp" #ifdef PATCH_SWITCH_EXCEPTION_LOG namespace patch { BOOL __stdcall exception_log_t::override_exception_catch(EXCEPTION_POINTERS* pExp, const char* plugin_name, const char* func_name) { // [esp - 128, esp + 256) uint32_t stack[96]; { OverWriteOnProtectHelper h(pExp->ContextRecord->Esp - 128, 384); for (int i = 0; i < 96; i++) { stack[95 - i] = load_i32(pExp->ContextRecord->Esp - i * 4 + 252); } } auto [log_name_a, log_name_w] = get_log_name(); std::unique_lock lock(ModulesData::mtx); ModulesData::update(); auto& modulesdata = ModulesData::get(); lock.unlock(); auto detail = format_detail(pExp, plugin_name, func_name, modulesdata); write_logfile(log_name_w, detail, pExp, modulesdata, stack); try { window_gate.wait(); if (exception_history.check({ .address = reinterpret_cast(pExp->ExceptionRecord->ExceptionAddress), .code = static_cast(pExp->ExceptionRecord->ExceptionCode) })) return TRUE; exception_log_dialog_window_t::Param param = { .link = L"log/{}"_fmt(log_name_w), .info_dir = log_dir, .info_path = log_name_w, .detail = detail, .pExp = pExp }; exception_log_dialog_window_t window(¶m); window_gate.open(); } catch (const std::runtime_error& e) { patch_resource_message_a( PATCH_RS_PATCH_FAILED_TO_CREATE_EXCEPTION_DIALOG, MB_ICONERROR | MB_TASKMODAL, e.what(), log_name_a, detail ); } return TRUE; } } // namespace patch #endif // ifdef PATCH_SWITCH_EXCEPTION_LOG ================================================ FILE: patch/patch_exception_log.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_EXCEPTION_LOG #include #include #include #include #include #include #include #include #include #pragma comment(lib, "shlwapi.lib") #include #include #include "global.hpp" #include "util.hpp" #include "resource.h" #include "hash.hpp" #include "moduledata.hpp" #include "gate.hpp" #include "patch_exception_log_dialog.hpp" namespace patch { // init at dllload inline class exception_log_t { #define exception_code_name_macro(name) { name, #name } // 例外コードを文字列にするための連想配列 static inline const std::unordered_map exception_code_name{ exception_code_name_macro(STILL_ACTIVE), exception_code_name_macro(EXCEPTION_GUARD_PAGE), exception_code_name_macro(EXCEPTION_DATATYPE_MISALIGNMENT), exception_code_name_macro(EXCEPTION_BREAKPOINT), exception_code_name_macro(EXCEPTION_SINGLE_STEP), exception_code_name_macro(EXCEPTION_ACCESS_VIOLATION), exception_code_name_macro(EXCEPTION_IN_PAGE_ERROR), exception_code_name_macro(EXCEPTION_INVALID_HANDLE), exception_code_name_macro(EXCEPTION_ILLEGAL_INSTRUCTION), exception_code_name_macro(EXCEPTION_NONCONTINUABLE_EXCEPTION), exception_code_name_macro(EXCEPTION_INVALID_DISPOSITION), exception_code_name_macro(EXCEPTION_ARRAY_BOUNDS_EXCEEDED), exception_code_name_macro(EXCEPTION_FLT_DENORMAL_OPERAND), exception_code_name_macro(EXCEPTION_FLT_DIVIDE_BY_ZERO), exception_code_name_macro(EXCEPTION_FLT_INEXACT_RESULT), exception_code_name_macro(EXCEPTION_FLT_INVALID_OPERATION), exception_code_name_macro(EXCEPTION_FLT_OVERFLOW), exception_code_name_macro(EXCEPTION_FLT_STACK_CHECK), exception_code_name_macro(EXCEPTION_FLT_UNDERFLOW), exception_code_name_macro(EXCEPTION_INT_DIVIDE_BY_ZERO), exception_code_name_macro(EXCEPTION_INT_OVERFLOW), exception_code_name_macro(EXCEPTION_PRIV_INSTRUCTION), exception_code_name_macro(EXCEPTION_STACK_OVERFLOW), exception_code_name_macro(CONTROL_C_EXIT), { 0xe0434352L, "* .Net exception" }, { 0xc06d007eL, "* DLL delay load failed" }, { 0xe06d7363L, "* C++ exception" }, { 0x80000100L, "* Unimplemented function" }, }; #undef exception_code_name_macro // 例外コードごとに何か特別なフォーマットをしたいとき用の関数を置く連想配列 static inline const std::unordered_map exception_format{ { EXCEPTION_ACCESS_VIOLATION, [](PEXCEPTION_RECORD erp){ return "read/write : {}\r\naccessed address : 0x{:08x}\r\n"_fmt( erp->ExceptionInformation[0], erp->ExceptionInformation[1] ); }}, { EXCEPTION_IN_PAGE_ERROR, [](PEXCEPTION_RECORD erp) { return "read/write : {}\r\naccessed address : 0x{:08x}\r\nNTSTATUS : {:08x}\r\n"_fmt( erp->ExceptionInformation[0], erp->ExceptionInformation[1], erp->ExceptionInformation[2] ); }}, { 0xe06d7363L, [](PEXCEPTION_RECORD erp) { uint32_t d1 = load_i32(erp->ExceptionInformation[2] + 12); uint32_t d2 = load_i32(d1 + 4); uint32_t d3 = load_i32(d2 + 4); auto class_name = reinterpret_cast(d3 + 8); auto exception = erp->ExceptionInformation[1]; return "Information[0] : {:08x}\r\nclass_name : {}\r\nexception ptr : {:08x}\r\n"_fmt( erp->ExceptionInformation[0], class_name, exception ); }}, }; // デフォルトの例外コードフォーマット static std::string exception_format_default(PEXCEPTION_RECORD erp) { std::ostringstream ss; for(DWORD i = 0; i < erp->NumberParameters; i++){ format_to_os(ss, "[{}] : {:08x}\r\n", i, erp->ExceptionInformation[i]); } return ss.str(); } static std::string format_eflags(DWORD eflags) { std::ostringstream ss; ss << "("; int c = 0; #define def(shift, name) if (eflags & (1 << shift)) { if(c++) ss << "|"; ss << #name; } def(0, CF); def(2, PF); def(4, AF); def(6, ZF); def(7, SF); def(8, TF); def(9, IF); def(10, DF); def(11, OF); #undef def if(c++) ss << "|"; ss << "IOPL" << ((eflags >> 12) & 0b11); #define def(shift, name) if (eflags & (1 << shift)) { ss << "|" << #name; } def(14, NT); def(16, RF); def(17, VM); def(18, AC); def(19, VIF); def(20, VIP); def(21, ID); #undef def ss << ")"; return ss.str(); } static std::string format_registers(PCONTEXT cp) { std::ostringstream ss; ss << "registers\r\n"; format_to_os(ss, "{} : {:08x}\r\n", "eax", cp->Eax); format_to_os(ss, "{} : {:08x}\r\n", "ecx", cp->Ecx); format_to_os(ss, "{} : {:08x}\r\n", "edx", cp->Edx); format_to_os(ss, "{} : {:08x}\r\n", "ebx", cp->Ebx); format_to_os(ss, "{} : {:08x}\r\n", "esi", cp->Esi); format_to_os(ss, "{} : {:08x}\r\n", "edi", cp->Edi); format_to_os(ss, "{} : {:08x}\r\n", "ebp", cp->Ebp); format_to_os(ss, "{} : {:08x}\r\n", "esp", cp->Esp); format_to_os(ss, "{} : {:08x}\r\n", "eip", cp->Eip); format_to_os(ss, "{} : {:08x} {}\r\n", "flag", cp->EFlags, format_eflags(cp->EFlags)); format_to_os(ss, "{} : {:08x}\r\n", "cs", cp->SegCs); format_to_os(ss, "{} : {:08x}\r\n", "ds", cp->SegDs); format_to_os(ss, "{} : {:08x}\r\n", "ss", cp->SegSs); format_to_os(ss, "{} : {:08x}\r\n", "es", cp->SegEs); format_to_os(ss, "{} : {:08x}\r\n", "fs", cp->SegFs); format_to_os(ss, "{} : {:08x}\r\n", "gs", cp->SegGs); ss << "extend : "; for(size_t i = 0; i < sizeof(cp->ExtendedRegisters); i++){ format_to_os(ss, "{:08x}", cp->ExtendedRegisters[i]); } ss << '\n' << '\n'; return ss.str(); } static std::tuple get_module_address(void* address, const std::vector& data) { auto addr = reinterpret_cast(address); ModulesDataEntry d{0u,addr,""}; auto itr = std::lower_bound(data.begin(),data.end(),d,[](auto a, auto b){ return a.end < b.end; }); if(itr!=data.end()){ if(itr->begin <= addr && addr < itr->end) { return { itr->name, addr - itr->begin }; } } return { "", 0 }; } static inline std::wstring log_dir; static auto get_log_name() { auto tid = GetCurrentThreadId(); SYSTEMTIME st; GetLocalTime(&st); return std::make_tuple( "{:04}-{:02}-{:02}_{:02}-{:02}-{:02}-{}_{}.txt"_fmt( st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, tid ), L"{:04}-{:02}-{:02}_{:02}-{:02}-{:02}-{}_{}.txt"_fmt( st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, tid ) ); } inline static std::string format_detail(EXCEPTION_POINTERS* pExp, const char* plugin_name, const char* func_name, const std::vector& data) { const auto code = pExp->ExceptionRecord->ExceptionCode; std::ostringstream ss; ss << "code : "; if(auto itr = exception_code_name.find(code); itr != exception_code_name.end()) { format_to_os(ss, "{} (0x{:08x})\r\n", itr->second, code); }else{ format_to_os(ss, "unknown (0x{:08x})\r\n", code); } format_to_os(ss, "address : 0x{:08x}", reinterpret_cast(pExp->ExceptionRecord->ExceptionAddress)); if (data.size()) { auto [modname, offset] = get_module_address(pExp->ExceptionRecord->ExceptionAddress, data); if(modname.size()) format_to_os(ss, " ({} + 0x{:08x})", modname, offset); } ss << "\r\n"; format_to_os(ss, "plugin_name : {}\r\n", plugin_name); format_to_os(ss, "func_name : {}\r\n", func_name); if (auto itr = exception_format.find(code); itr != exception_format.end()) { ss << itr->second(pExp->ExceptionRecord); } else { ss << exception_format_default(pExp->ExceptionRecord); } return ss.str(); } inline static std::string format_stack(uint32_t start, uint8_t* stack, uint32_t length) { auto esp_mod16 = start & 0xf; std::ostringstream ss; ss << "stack\r\n"; auto esp = start & ~0xf; if (esp_mod16) { format_to_os(ss, "{:08x} ", esp); for (uint32_t i = 0; i < esp_mod16 * 2; i++) ss << ' '; for (uint32_t i = 0; i < 16 - esp_mod16; i++) { format_to_os(ss, "{:02x}", stack[i]); } ss << "\r\n"; esp += 16; } for (uint32_t i = 0; i < (length - esp_mod16) / 16; i++) { format_to_os(ss, "{:08x} ", esp); for (int j = 0; j < 16; j++) format_to_os(ss, "{:02x}", stack[i * 16 + j + esp_mod16]); ss << "\r\n"; esp += 16; } if (esp_mod16) { format_to_os(ss, "{:08x} ", esp); for (uint32_t i = length - esp_mod16; i < length; i++) { format_to_os(ss, "{:02x}", stack[i]); } } ss << "\r\n"; return ss.str(); } template static bool write_logfile(std::wstring& filename, std::string_view detail, EXCEPTION_POINTERS* pExp, const std::vector& data, const uint32_t (&stack)[N]) { if(!PathFileExistsW(log_dir.c_str())) { if(!CreateDirectoryW(log_dir.c_str(), NULL)){ return false; } } auto filepath = log_dir + filename; auto hfile = CreateFileW(filepath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL); if(hfile == INVALID_HANDLE_VALUE) { return false; } const auto code = pExp->ExceptionRecord->ExceptionCode; std::ostringstream ss; ss << "patch.aul (" PATCH_VERSION_STR ") debug info file\r\n\r\n"; ss << detail; ss << "\r\n"; ss << "modules\r\n"; if (data.size()) { for(const auto& d : data) { if (d.hash.has_value()) { format_to_os(ss, "{:08x}-{:08x}:{} ({})\r\n", d.begin, d.end, d.name, d.hash->tostring()); } else { format_to_os(ss, "{:08x}-{:08x}:{}\r\n", d.begin, d.end, d.name); } } } else { ss << "(Failed to get modules info)\r\n"; } ss << "\r\n"; ss << format_registers(pExp->ContextRecord); ss << "\r\n"; ss << format_stack(pExp->ContextRecord->Esp - 128, (uint8_t*)&stack, N * 4); ss << "\r\n"; auto str = ss.str(); DWORD written; WriteFile(hfile, str.c_str(), str.size(), &written, NULL); CloseHandle(hfile); return true; // todo: ヒープ情報の出力 } inline static Gate window_gate{ true }; static BOOL __stdcall override_exception_catch(EXCEPTION_POINTERS* pExp, const char* plugin_name, const char* func_name); inline static const auto exception_catch_ptr = &override_exception_catch; inline static bool dialog_init = false; public: void operator()() { log_dir = WinWrap::Module{}.getFileNameW(); log_dir.resize(log_dir.find_last_of(L"/\\") + 1); log_dir += L"log\\"; OverWriteOnProtectHelper h(GLOBAL::aviutl_base + 0x5b8b0, 13); h.store_i32(0, '\xff\x74\x24\x04'); // push [esp+4] h.store_i32(4, '\x52\x51\xff\x15'); // push edx ; push ecx ; call [(i32)] h.store_i32(8, &exception_catch_ptr); h.store_i8(12, '\xc3'); // ret dialog_init = exception_log_dialog_window_t::init(); //if (!dialog_init)return; } } exception_log; } // namespace patch #endif // ifdef PATCH_SWITCH_EXCEPTION_LOG ================================================ FILE: patch/patch_exception_log_dialog.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #define ISOLATION_AWARE_ENABLED 1 #include #include "patch_exception_log_dialog.hpp" #ifdef PATCH_SWITCH_EXCEPTION_LOG #include #include #include #pragma comment(lib, "shlwapi.lib") #include "offset_address.hpp" #include "patch_exception_history.hpp" #include "util_others.hpp" namespace patch { exception_log_dialog_window_t::exception_log_dialog_window_t(const Param* param) { this->param = param; INT_PTR ret; std::thread th([this, &ret] { MessageBeep(MB_ICONEXCLAMATION); auto current_hmod = load_i32(GLOBAL::aviutl_base + OFS::AviUtl::current_resource_hmod); const auto RT_DIALOG_W = (LPWSTR)(RT_DIALOG); if (FindResourceW(current_hmod, L"PATCH_DIALOG_EXCEPTION", RT_DIALOG_W)) ret = IsolationAwareDialogBoxParamW(current_hmod, L"PATCH_DIALOG_EXCEPTION", NULL, dialog_proc, (LPARAM)this); else ret = IsolationAwareDialogBoxParamW(GLOBAL::patchaul_hinst, L"PATCH_DIALOG_EXCEPTION", NULL, dialog_proc, (LPARAM)this); }); if (th.joinable()) { th.join(); } else { throw std::runtime_error("Failed to start a thread."); } if (ret == 0 || ret == -1) throw std::runtime_error("Failed to create a dialog."); } // 48 144 2 130 INT_PTR CALLBACK exception_log_dialog_window_t::dialog_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { auto this_ = reinterpret_cast(GetWindowLong(hwnd, GWL_USERDATA)); switch (message) { case WM_INITDIALOG: { SetWindowLong(hwnd, GWL_USERDATA, lparam); this_ = reinterpret_cast(lparam); this_->hwnd_detail_text = GetDlgItem(hwnd, PATCH_ID_EXCEPTION_DETAIL_TEXT); this_->hwnd_link = GetDlgItem(hwnd, PATCH_ID_EXCEPTION_LINK); this_->hwnd_button_ok = GetDlgItem(hwnd, PATCH_ID_EXCEPTION_OK); this_->hwnd_button_detail = GetDlgItem(hwnd, PATCH_ID_EXCEPTION_DETAIL_BUTTON); this_->hwnd_check_stopmes = GetDlgItem(hwnd, PATCH_ID_EXCEPTION_STOPMES); this_->hwnd_button_save_project = GetDlgItem(hwnd, PATCH_ID_EXCEPTION_SAVE_PROJECT); this_->hwnd_save_text = GetDlgItem(hwnd, PATCH_ID_EXCEPTION_LABEL2); RECT rect_detail_text; GetWindowRect(this_->hwnd_detail_text, &rect_detail_text); RECT rect_check_stopmes; GetWindowRect(this_->hwnd_check_stopmes, &rect_check_stopmes); this_->resize_ofs = rect_check_stopmes.top - rect_detail_text.top; SetWindowTextW(this_->hwnd_link, this_->param->link.c_str()); if (!this_->detail_showed) { ShowWindow(this_->hwnd_detail_text, SW_HIDE); this_->update_window_detail(hwnd, false); } SetWindowTextA(this_->hwnd_detail_text, this_->param->detail.c_str()); ShowWindow(hwnd, SW_SHOW); SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); return TRUE; } case WM_CLOSE: EndDialog(hwnd, 1); return TRUE; case WM_COMMAND: switch(LOWORD(wparam)){ case PATCH_ID_EXCEPTION_OK: if(SendMessageA(this_->hwnd_check_stopmes, BM_GETCHECK, 0, 0) == BST_CHECKED) { auto record = this_->param->pExp->ExceptionRecord; exception_history.map.insert_or_assign(ExceptionHistoryEntry{ .address = reinterpret_cast(record->ExceptionAddress), .code = static_cast(record->ExceptionCode) }, std::chrono::system_clock::now()); } EndDialog(hwnd, 1); return TRUE; case PATCH_ID_EXCEPTION_DETAIL_BUTTON: if(this_->detail_showed){ this_->update_window_detail(hwnd, false); this_->detail_showed = false; }else{ this_->update_window_detail(hwnd, true); this_->detail_showed = true; } return TRUE; case PATCH_ID_EXCEPTION_SAVE_PROJECT: { save_project(hwnd); } return TRUE; }break; case WM_NOTIFY: switch(const auto& nmhdr = *reinterpret_cast(lparam); nmhdr.code) { case NM_CLICK: case NM_RETURN: switch(nmhdr.idFrom){ case PATCH_ID_EXCEPTION_LINK:{ STARTUPINFOW si={.cb=sizeof(STARTUPINFOW)}; PROCESS_INFORMATION pi; auto commandline = L"explorer.exe /select,{}{}"_fmt(this_->param->info_dir, this_->param->info_path); auto ret = CreateProcessW(NULL, commandline.data(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); if(ret){ CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } return TRUE; } } break; }break; } return FALSE; } } // namespace patch #endif // ifdef PATCH_SWITCH_EXCEPTION_LOG ================================================ FILE: patch/patch_exception_log_dialog.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_EXCEPTION_LOG #include #include #include #include #include #pragma comment(linker,"/manifestdependency:\"type='win32' \ name='Microsoft.Windows.Common-Controls' \ version='6.0.0.0' \ processorArchitecture='x86' \ publicKeyToken='6595b64144ccf1df' \ language='*'\"") #pragma comment(lib, "comctl32.lib") #include #include "resource.h" #include "global.hpp" namespace patch { class exception_log_dialog_window_t { public: struct Param { std::wstring link; // SysLink用のコード文字列 std::wstring info_dir; // 表示する文字列 std::wstring info_path; // 飛ばすパス std::string detail; // 例外の詳細 EXCEPTION_POINTERS* pExp; Param& operator=(const Param& x) { this->link = x.link; this->info_dir = x.info_dir; this->info_path = x.info_path; this->detail = x.detail; this->pExp = x.pExp; return *this; } }; // ウィンドウを生成する exception_log_dialog_window_t(const Param* param); // コモンコントロール初期化など static bool init() { INITCOMMONCONTROLSEX icc{ .dwSize = sizeof(INITCOMMONCONTROLSEX), .dwICC = ICC_LINK_CLASS }; return InitCommonControlsEx(&icc); } private: HWND hwnd; bool detail_showed; HWND hwnd_detail_text; HWND hwnd_save_text; HWND hwnd_link; HWND hwnd_button_ok; HWND hwnd_button_detail; HWND hwnd_check_stopmes; HWND hwnd_button_save_project; DWORD resize_ofs; const Param* param; void update_window_detail(HWND hwnd, bool flag) { ShowWindow(hwnd_detail_text, flag ? SW_SHOW : SW_HIDE); int ofs = flag ? static_cast(resize_ofs) : -static_cast(resize_ofs); RECT rect; POINT point; GetWindowRect(hwnd, &rect); SetWindowPos(hwnd, NULL, 0, 0, rect.right - rect.left, rect.bottom - rect.top + ofs, SWP_NOMOVE | SWP_NOZORDER); GetWindowRect(hwnd_button_ok, &rect); point = { rect.left, static_cast(rect.top + ofs) }; ScreenToClient(hwnd, &point); SetWindowPos(hwnd_button_ok, NULL, point.x, point.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); GetWindowRect(hwnd_button_detail, &rect); point = { rect.left, static_cast(rect.top + ofs) }; ScreenToClient(hwnd, &point); SetWindowPos(hwnd_button_detail, NULL, point.x, point.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); GetWindowRect(hwnd_check_stopmes, &rect); point = { rect.left, static_cast(rect.top + ofs) }; ScreenToClient(hwnd, &point); SetWindowPos(hwnd_check_stopmes, NULL, point.x, point.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); GetWindowRect(hwnd_button_save_project, &rect); point = { rect.left, static_cast(rect.top + ofs) }; ScreenToClient(hwnd, &point); SetWindowPos(hwnd_button_save_project, NULL, point.x, point.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); GetWindowRect(hwnd_save_text, &rect); point = { rect.left, static_cast(rect.top + ofs) }; ScreenToClient(hwnd, &point); SetWindowPos(hwnd_save_text, NULL, point.x, point.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); }; private: constexpr static UINT UPDATE_PARAM = WM_APP + 1; static INT_PTR CALLBACK dialog_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); }; } // namespace patch #endif // ifdef PATCH_SWITCH_EXCEPTION_LOG ================================================ FILE: patch/patch_exeditwindow_sizing.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_EXEDITWINDOW_SIZING #include #include "global.hpp" #include "util_magic.hpp" #include "config_rw.hpp" namespace patch { // call at v_func_WncProc WM_SIZING // 拡張編集ウィンドウの上部を正常にドラッグできるようにする inline class exeditwindow_sizing_t { bool enabled = true; inline static const char key[] = "exeditwindow_sizing"; public: BOOL wndproc(WPARAM wparam, LPARAM lparam) { if (!enabled) return -1; auto LayerHeightState = load_i32(GLOBAL::exedit_base + 0x0a3e20); auto DAT_101a530c = load_i32(GLOBAL::exedit_base + 0x1a530c); auto rect = (RECT*)lparam; if (rect->right < rect->left + 128) rect->right = rect->left + 128; auto top = rect->top; auto layer_count = (rect->bottom - rect->top - DAT_101a530c + LayerHeightState / 2) / LayerHeightState; bool is_top; switch (wparam) { case WMSZ_TOP: case WMSZ_TOPLEFT: case WMSZ_TOPRIGHT: is_top = true; break; default: is_top = false; } if (layer_count < 1) layer_count = 1; else if (100 < layer_count) layer_count = 100; if (is_top) { rect->top = rect->bottom - (DAT_101a530c + LayerHeightState * layer_count); } else { rect->bottom = rect->top + DAT_101a530c + LayerHeightState * layer_count; } return 0; } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } exeditwindow_sizing; } // namespace patch #endif // ifdef PATCH_SWITCH_EXEDITWINDOW_SIZING ================================================ FILE: patch/patch_exo_aviutlfilter.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_EXO_AVIUTL_FILTER #include #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "restorable_patch.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // 拡張編集以外のフィルタを使ったフィルタオブジェクトを正常にオブジェクトファイルに出力できない inline class exo_aviutlfilter_t { bool enabled = true; inline static const char key[] = "exo_aviutlfilter"; std::optional rp1; std::optional rp2; std::optional rp3; public: void init() { if (!enabled)return; auto& cursor = GLOBAL::executable_memory_cursor; OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::ConvertFilter2Exo_TrackScaleJudge_RangeBegin, 30); /* 10028a84 MOV EAX, DWORD PTR [ESI + CCH] ; filter_param_ptr->track_scale ↓ 10028a84 NOP 10028a85 CALL func func MOV AL, BYTE PTR [ESI + 3H] TEST AL, 04H JNZ SKIP, 03H XOR EAX, EAX RET MOV EAX, DWORD PTR [ESI + CCH] ; filter_param_ptr->track_scale RET */ static const char code_put[] = "\x8a\x46\x03" // MOV AL, BYTE PTR [ESI + 3H] "\xa8\x04" // TEST AL, 04H "\x75\x03" // JNZ SKIP, 03H "\x33\xc0" // XOR EAX, EAX "\xc3" // RET "\x8b\x86\xcc\x00\x00\x00" // MOV EAX, DWORD PTR [ESI + CCH] ; filter_param_ptr->track_scale "\xc3" // RET ; memcpy(cursor, code_put, sizeof(code_put) - 1); auto apply = [&cursor](uint32_t ofs, std::optional& rp) { char injection[6]; injection[0] = '\x90'; // nop injection[1] = '\xe8'; // call rel32 store_i32(&injection[2], CalcNearJmp(ofs + 2, reinterpret_cast(cursor))); rp.emplace(ofs, injection, sizeof(injection)); }; apply(GLOBAL::exedit_base + OFS::ExEdit::ConvertFilter2Exo_TrackScaleJudge_Overwrite1, rp1); apply(GLOBAL::exedit_base + OFS::ExEdit::ConvertFilter2Exo_TrackScaleJudge_Overwrite2, rp2); apply(GLOBAL::exedit_base + OFS::ExEdit::ConvertFilter2Exo_TrackScaleJudge_Overwrite3, rp3); cursor += sizeof(code_put) - 1; rp1->switching(enabled); rp2->switching(enabled); rp3->switching(enabled); } void switching(bool flag) { enabled = flag; rp1->switching(enabled); rp2->switching(enabled); rp3->switching(enabled); } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } exo_aviutlfilter; } // namespace patch #endif // ifdef PATCH_SWITCH_EXO_AVIUTL_FILTER ================================================ FILE: patch/patch_exo_fold_gui.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_EXO_FOLD_GUI #include #include #include "global.hpp" #include "util.hpp" namespace patch { // init at exedit load // exa,exo生成時、設定ダイアログの▼(折り畳み)とマウスマーク(GUI表示)の情報を追加する inline class exo_fold_gui_t { bool enabled = true; bool enabled_i; inline static const char key[] = "exa_fold_gui"; inline static const char fold_gui_write[] = "_fold_gui=%d\r\n"; inline static const char fold_gui_read[] = "_fold_gui"; public: void init() { enabled_i = enabled; if (!enabled_i)return; auto& cursor = GLOBAL::executable_memory_cursor; { // exo_write OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x0288b1, 5); h.store_i8(0, '\xe9'); h.replaceNearJmp(1, cursor); /* 100288b1 2401 and al,01 100288b3 84c0 test al,al 100288b5 750f jnz 100288c6 ↓ 100288b1 e9XxXxXxXx jmp executable_memory_cursor */ static const char code_put_write[] = "\x8b\xc8" // mov ecx,eax "\x50" // push eax "\x83\xe1\x07" // and ecx,07 "\xc1\xe9\x01" // shr ecx,01 "\x83\xf1\x02" // xor ecx,02 "\x85\xc9" // test ecx,ecx "\x74\x0e" // jz skip 0e "\x51" // push ecx "\x68XXXX" // push "_fold_gui=%d\r\n" "\x55" // push ebp "\xff\xd3" // call ebx "\x83\xc4\x0c" // add esp,0c "\x03\xe8" // add ebp,eax "\x58" // pop eax "\x24\x01" // and al,01 "\x84\xc0" // test al,al "\x0f\x84XXXX" // jz exedit + 0x288b7 "\xe9"// & XXXX // jmp exedit + 0x288c6 ; memcpy(cursor, code_put_write, sizeof(code_put_write) - 1); store_i32(cursor + 18, &fold_gui_write); cursor += sizeof(code_put_write) - 1 + 4; store_i32(cursor - 9, GLOBAL::exedit_base + 0x0288b7 - ((int)cursor - 5)); store_i32(cursor - 4, GLOBAL::exedit_base + 0x0288c6 - (int)cursor); } { // exo_read OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x029b21, 5); h.store_i8(0, '\xe9'); h.replaceNearJmp(1, cursor); /* 10029b21 8b542414 mov edx,dword ptr [esp+14] 10029b25 52 push edx ↓ 100288b1 e9XxXxXxXx jmp executable_memory_cursor */ static const char code_put_read[] = "\x8b\x54\x24\x14" // mov edx,dword ptr [esp+14] "\x52" // push edx "\x68XXXX" // push "_fold_gui" "\xff\xd6" // call esi "\x85\xc0" // test eax,eax "\x75\x1f" // jnz skip,1f "\x53" // push ebx "\xe8XXXX" // call 100918ab "\x83\xc4\x04" // add esp,04 "\x85\xc0" // test eax,eax "\x74\x12" // jz skip,12 "\x83\xe0\x03" // and eax,03 "\xc1\xe0\x01" // shl eax,01 "\x8b\x4c\x24\x48" // mov ecx,dword ptr [esp+48] "\x03\xcd" // add ecx,ebp "\x83\xc1\x72" // add ecx,+72 "\x30\x41\x72" // xor byte ptr [ecx+72],al "\x8b\x54\x24\x14" // mov edx,dword ptr [esp+14] "\x52" // push edx "\xe9"// & XXXX // jmp exedit + 0x29b26 ; memcpy(cursor, code_put_read, sizeof(code_put_read) - 1); store_i32(cursor + 6, &fold_gui_read); store_i32(cursor + 18, GLOBAL::exedit_base + 0x0918ab - ((int)cursor + 22)); cursor += sizeof(code_put_read) - 1 + 4; store_i32(cursor - 4, GLOBAL::exedit_base + 0x029b26 - (int)cursor); } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } exo_fold_gui; } // namespace patch #endif // ifdef PATCH_SWITCH_EXO_FOLD_GUI ================================================ FILE: patch/patch_exo_midpt_and_tra.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_EXO_MIDPT_AND_TRA #include #include "config_rw.hpp" namespace patch { // init at exedit load /* 中間点有りで.traスクリプト変化方式のあるオブジェクトがあると正常に読み込めないことがあるのを修正 発生条件: ・aviutl.exeを開いた後、一度も使用していない.traスクリプト変化方式が含まれること ・中間点有りオブジェクトであること */ inline class exo_midpt_and_tra_t { bool enabled = true; bool enabled_i; inline static const char key[] = "exo_midpt_and_tra"; public: void init() { enabled_i = enabled; if (!enabled_i)return; auto& cursor = GLOBAL::executable_memory_cursor; // 100345d9 e8d2030000 call exedit+349b0 OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x0345da, 4); h.replaceNearJmp(0, cursor); static const char code_put[] = "\x8b\x84\x24\x40\x01\x00\x00" // mov eax,dword ptr [esp+140] ; flag "\x85\xc0" // test eax,eax "\x0f\x84XXXX" // jz exedit+349b0 "\xc3" // ret ; memcpy(cursor, code_put, sizeof(code_put) - 1); store_i32(cursor + 11, GLOBAL::exedit_base + 0x0349b0 - (uint32_t)(cursor + 15)); cursor += sizeof(code_put) - 1; } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } exo_midpt_and_tra; } // namespace patch #endif // ifdef PATCH_SWITCH_EXO_MIDPT_AND_TRA ================================================ FILE: patch/patch_exo_sceneidx.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_EXO_SCENEIDX #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "restorable_patch.hpp" namespace patch { // init at exedit load // オブジェクトファイルにシーン・シーン(音声)のシーン番号が正しく入出力されない inline class exo_sceneidx_t { bool enabled = true; inline static const char key[] = "exo_sceneidx"; std::optional rp1; std::optional rp2; std::optional rp3; inline static const char scene_name[] = "scene"; public: void init() { rp1.emplace(GLOBAL::exedit_base + OFS::ExEdit::efSceneAudio_exdatause_idx_type, (i16)1); rp2.emplace(GLOBAL::exedit_base + OFS::ExEdit::efSceneAudio_exdatause_idx_name, &scene_name); rp3.emplace(GLOBAL::exedit_base + OFS::ExEdit::efScene_exdatause_idx_name, &scene_name); rp1->switching(enabled); rp2->switching(enabled); rp3->switching(enabled); } void switching(bool flag) { enabled = flag; rp1->switching(enabled); rp2->switching(enabled); rp3->switching(enabled); } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } exo_sceneidx; } // namespace patch #endif // ifdef PATCH_SWITCH_EXO_SCENEIDX ================================================ FILE: patch/patch_exo_specialcolorconv.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_EXO_SPECIALCOLORCONV #include "global.hpp" #include "offset_address.hpp" #include "util_magic.hpp" namespace patch { // init at exedit load // 特定色域変換の拡張データ領域にstatusが2つある問題 inline class exo_specialcolorconv_t { inline static const char status2_name[] = "status2"; bool enabled = true; inline static const char key[] = "exo_specialcolorconv"; std::optional rp; public: void init() { rp.emplace(GLOBAL::exedit_base + OFS::ExEdit::specialcolorconv_status2, &status2_name); rp->switching(enabled); } void switching(bool flag) { rp->switching(enabled = flag); } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } exo_specialcolorconv; } // namespace patch #endif // ifdef PATCH_SWITCH_EXO_SPECIALCOLORCONV ================================================ FILE: patch/patch_exo_trackminusval.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_exo_trackminusval.hpp" #ifdef PATCH_SWITCH_EXO_TRACK_MINUSVAL namespace patch { int __cdecl exo_trackminusval_t::exo_trackminusval_insteadfunc(char** strp, ExEdit::Filter* efp, int track_idx) { if (!has_flag(efp->flag, ExEdit::Filter::Flag::ExEditFilter) || efp->track_scale == nullptr || efp->track_scale[track_idx] <= 1) { auto ret = reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::str2int2)(*strp); auto itr = *strp; while (*itr != '\0' && *itr != ',') itr++; *strp = itr; return ret; } else { auto itr = *strp; bool is_neg = false; if (*itr == '-') { is_neg = true; itr++; (*strp)++; } while (*itr) { if (*itr == '.') { *itr = '\0'; itr++; break; } itr++; } auto scale = efp->track_scale[track_idx]; auto ret = reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::str2int2)(*strp) * scale; while (scale /= 10, '0' <= *itr && *itr <= '9') { ret += (*itr - '0') * scale; itr++; } if (is_neg)ret = -ret; while (*itr != '\0' && *itr != ',') itr++; *strp = itr; return ret; } } } // namespace patch #endif // ifdef PATCH_SWITCH_EXO_TRACK_MINUSVAL ================================================ FILE: patch/patch_exo_trackminusval.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_EXO_TRACK_MINUSVAL #include #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "restorable_patch.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // オブジェクトファイルからの入力で,(-1,0)の値の正負が逆転する inline class exo_trackminusval_t { static int __cdecl exo_trackminusval_insteadfunc(char** strp, ExEdit::Filter* efp, int track_idx); bool enabled = true; inline static const char key[] = "exo_track_minusval"; std::optional rpf; public: void init() { rpf.emplace(GLOBAL::exedit_base + OFS::ExEdit::exo_readtrack, exo_trackminusval_insteadfunc); rpf->switching(enabled); } void switching(bool flag) { rpf->switching(enabled = flag); } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } exo_trackminusval; } // namespace patch #endif // ifdef PATCH_SWITCH_EXO_TRACK_MINUSVAL ================================================ FILE: patch/patch_exo_trackparam.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_EXO_TRACKPARAM #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // オブジェクトファイルへの出力で,ascii文字以外が含まれたスクリプトのパラメータが0になる inline class exo_trackparam_t { std::optional rp; bool enabled = true; inline static const char key[] = "exo_trackparam"; public: void init() { rp.emplace(GLOBAL::exedit_base + OFS::ExEdit::exo_trackparam_overwrite, 0x73); rp->switching(enabled); } void switching(bool flag) { rp->switching(enabled = flag); } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } exo_trackparam; } // namespace patch #endif // #ifdef PATCH_SWITCH_EXO_TRACKPARAM ================================================ FILE: patch/patch_failed_file_drop.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FAILED_LONGER_PATH #include #include "global.hpp" #include "util.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // ドロップ処理で最終的に何も行われなかったときにメッセージを出力する inline class failed_file_drop_t { inline static const char str_failed_drop_msg[] = "拡張編集へドロップされたファイルの種類が判別できませんでした\nexedit.iniを確認してください"; bool enabled = true; bool enabled_i; inline static const char key[] = "failed_file_drop"; public: void init() { enabled_i = enabled; if (!enabled_i)return; auto& cursor = GLOBAL::executable_memory_cursor; OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x03c454, 4); h.replaceNearJmp(0, cursor); /* 1003c452 0f84f4760000 jz 10043b4c ↓ 1003c452 0f84XxXxXxXx jz executable_memory_cursor */ char code_put[] = "\x8d\x8c\x24\xd0\x00\x00\x00"// lea ecx,dword ptr [esp+000000d0] "\x51" // push ecx "\xe8XXXX" // call 1004e1d0 ; ExtractExtension "\x83\xc4\x04" // add esp,+04 "\x68\x30\x20\x04\x00" // push 0x42030 "\x50" // push eax "\x68XXXX" // push &str_failed_drop_msg "\xa1\x44\x7a\x17\x00" // mov eax,[exedit+exedit_hwnd] "\x50" // push eax "\xff\x15\x20\xa3\x09\x00" // call dword ptr [exedit+MessageBoxA] "\xe9" // jmp 10043b4c ; memcpy(cursor, code_put, sizeof(code_put) - 1); store_i32(cursor + 9, GLOBAL::exedit_base + 0x04e1d0 - (int)cursor - 13); store_i32(cursor + 23, &str_failed_drop_msg); store_i32(cursor + 28, GLOBAL::exedit_base + OFS::ExEdit::exedit_hwnd); store_i32(cursor + 35, GLOBAL::exedit_base + 0x09a320); cursor += sizeof(code_put) - 1 + 4; store_i32(cursor - 4, GLOBAL::exedit_base + 0x043b4c - (int)cursor); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } failed_file_drop; } // namespace patch #endif // ifdef PATCH_SWITCH_FAILED_FILE_DROP ================================================ FILE: patch/patch_failed_longer_path.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_failed_longer_path.hpp" #ifdef PATCH_SWITCH_FAILED_LONGER_PATH namespace patch { BOOL __cdecl failed_longer_path_t::dlg_get_load_name_wrap(AviUtl::ExFunc* a_exfunc, LPSTR name, LPSTR filter, LPSTR def) { char temp[264]; if (!a_exfunc->dlg_get_load_name(temp, filter, def))return FALSE; if (258 < lstrlenA(temp)) { HWND* settingdialog_hwnd = (HWND*)(GLOBAL::exedit_base + OFS::ExEdit::settingdialog_hwnd); MessageBoxA(*settingdialog_hwnd, str_new_longer_msg, temp, MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_TOPMOST); lstrcpyA(name, def); return FALSE; } lstrcpyA(name, temp); return TRUE; } UINT __stdcall failed_longer_path_t::DragQueryFileA_exedit_wrap(HDROP hDrop, UINT iFile, LPSTR lpszFile, UINT cch) { UINT path_len = DragQueryFileA(hDrop, iFile, lpszFile, cch); if (258 < path_len) { auto exedit_hwnd = (HWND*)(GLOBAL::exedit_base + OFS::ExEdit::exedit_hwnd); MessageBoxA(*exedit_hwnd, str_new_longer_msg, lpszFile, MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_TOPMOST); return 0; } return path_len; } UINT __stdcall failed_longer_path_t::DragQueryFileA_settingdialog_wrap(HDROP hDrop, UINT iFile, LPSTR lpszFile, UINT cch) { UINT path_len = DragQueryFileA(hDrop, iFile, lpszFile, cch); if (258 < path_len) { auto settingdialog_hwnd = (HWND*)(GLOBAL::exedit_base + OFS::ExEdit::settingdialog_hwnd); MessageBoxA(*settingdialog_hwnd, str_new_longer_msg, lpszFile, MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_TOPMOST); return 0; } return path_len; } } // namespace patch #endif // ifdef PATCH_SWITCH_FAILED_LONGER_PATH ================================================ FILE: patch/patch_failed_longer_path.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FAILED_LONGER_PATH #include #include "global.hpp" #include "util.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // 読み込もうとしたファイルパスが長くて失敗するときにメッセージを出す/エラーが発生するのを修正 // 安全性のために読み込める最大数を1バイト減らしています(260バイトを読み込ませた場合、合成モードなどと繋がってバグる) inline class failed_longer_path_t { inline static const char str_new_longer_msg[] = "ファイルパスが長いため失敗しました\nファイルやフォルダ名を短くするか、Cドライブ直下などの浅い階層に移動して下さい"; static BOOL __cdecl dlg_get_load_name_wrap(AviUtl::ExFunc* a_exfunc, LPSTR name, LPSTR filter, LPSTR def); static UINT __stdcall DragQueryFileA_exedit_wrap(HDROP hDrop, UINT iFile, LPSTR lpszFile, UINT cch); static UINT __stdcall DragQueryFileA_settingdialog_wrap(HDROP hDrop, UINT iFile, LPSTR lpszFile, UINT cch); bool enabled = true; bool enabled_i; inline static const char key[] = "failed_longer_path"; public: void init() { enabled_i = enabled; if (!enabled_i)return; { // exedit_dlg_get_load_name /* 1002093b ff9280000000 call dword ptr [edx + 0x80] ; aviutl_exfunc->dlg_get_load_name 10020941 83c40c add esp,0xc ↓ 1002093b 52 push edx 1002093c e8XxXxXxXx call new_func 10020941 83c410 add esp,0x10 */ OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x02093b, 9); h.store_i16(0, '\x52\xe8'); // push edx; call (rel32) h.replaceNearJmp(2, &dlg_get_load_name_wrap); h.store_i8(8, '\x10'); } { // ExEdit D&D /* 1003be8f ff15c8a10910 call dword ptr [DragQueryFileA] ↓ 1003be8f 90 nop 1003be90 e8XxXxXxXx call new_func */ OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x03be8f, 6); h.store_i16(0, '\x90\xe8'); // nop; call (rel32) h.replaceNearJmp(2, &DragQueryFileA_exedit_wrap); } { // SettingDialog D&D /* 1002e330 ff15c8a10910 call dword ptr [DragQueryFileA] ↓ 1002e330 90 nop 1002e331 e8XxXxXxXx call new_func */ OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x02e330, 6); h.store_i16(0, '\x90\xe8'); // nop; call (rel32) h.replaceNearJmp(2, &DragQueryFileA_settingdialog_wrap); } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } failed_longer_path; } // namespace patch #endif // ifdef PATCH_SWITCH_FAILED_LONGER_PATH ================================================ FILE: patch/patch_failed_sjis_msgbox.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_failed_sjis_msgbox.hpp" #ifdef PATCH_SWITCH_FAILED_SJIS_MSGBOX namespace patch { int __stdcall failed_sjis_msgbox_t::MessageBoxA_1(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) { auto end = lpCaption + strlen(lpCaption); // sjisに0x3fは含まれないのでこれでよい if (std::find(lpCaption, end, '?') != end) { lpText = str_new_failed_msg; } return MessageBoxA(hWnd, lpText, lpCaption, uType); } int __stdcall failed_sjis_msgbox_t::MessageBoxA_2(LPCSTR path, HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) { int ret = MessageBoxA_1(hWnd, lpText, path, uType); *(char*)path = '\0'; return ret; } } // namespace patch #endif // ifdef PATCH_SWITCH_FAILED_SJIS_MSGBOX ================================================ FILE: patch/patch_failed_sjis_msgbox.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FAILED_SJIS_MSGBOX #include #include "global.hpp" #include "util.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // ファイル名(パス)が原因で読み込み失敗のエラー表記を変更する // **ファイルの読み込みに失敗しました 対応していないフォーマットの可能性があります // ↓ // パス(ファイルもしくはフォルダ名)に使用できない文字が含まれています inline class failed_sjis_msgbox_t { inline static const char str_new_failed_msg[] = "ファイルパスに使用できない文字が含まれています\nファイル名やフォルダ名を確認してください"; static int __stdcall MessageBoxA_1(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType); static int __stdcall MessageBoxA_2(LPCSTR path, HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType); bool enabled = true; bool enabled_i; inline static const char key[] = "failed_sjis_msgbox"; public: void init() { enabled_i = enabled; if (!enabled_i)return; { // audio & movie OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x00522b, 6); h.store_i16(0, '\x90\xe8'); // nop; call (rel32) h.replaceNearJmp(2, &MessageBoxA_1); } { // image_file_wndproc OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x00e173, 11); h.store_i32(0, '\x8d\x44\x24\x24'); // lea eax,dword ptr [esp+24] h.store_i32(4, '\x50\x90\xe8\x00'); // push eax, nop, call (rel32) h.replaceNearJmp(7, &MessageBoxA_2); } { // border_wndproc OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x0521c3, 11); h.store_i32(0, '\x8d\x44\x24\x24'); // lea eax,dword ptr [esp+24] h.store_i32(4, '\x50\x90\xe8\x00'); // push eax, nop, call (rel32) h.replaceNearJmp(7, &MessageBoxA_2); } { // shadow_wndproc OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x088ef6, 11); h.store_i32(0, '\x8d\x44\x24\x24'); // lea eax,dword ptr [esp+24] h.store_i32(4, '\x50\x90\xe8\x00'); // push eax, nop, call (rel32) h.replaceNearJmp(7, &MessageBoxA_2); } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } failed_sjis_msgbox; } // namespace patch #endif // ifdef PATCH_SWITCH_FAILED_SJIS_MSGBOX ================================================ FILE: patch/patch_fast.hpp ================================================ #pragma once namespace patch::fast { inline class fast_t { bool enabled = true; bool enabled_i; inline static const char key[] = "fast"; public: void init() { enabled_i = enabled; } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } fast; } ================================================ FILE: patch/patch_fast_border.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "patch_fast_border.hpp" #ifdef PATCH_SWITCH_FAST_BORDER #include #include "global.hpp" #include "offset_address.hpp" #include "util_int.hpp" #include "debug_log.hpp" #include //#define PATCH_STOPWATCH #include "stopwatch.hpp" namespace patch::fast { // AVX2が有効かどうかを判定する関数を追加してください // AVX2が無効の場合でも縁取り関連のバグ修正は行われるようになっています BOOL enable_avx2() { auto cpucmdset = get_CPUCmdSet(); return has_flag(cpucmdset, CPUCmdSet::F_AVX2); } void efBorder_horizontal_convolution_alpha_simd(int thread_id, int thread_num, void* param1, void* param2); void efBorder_horizontal_convolution_alpha_simd2(int thread_id, int thread_num, void* param1, void* param2); void efBorder_vertical_convolution_alpha_and_put_color_simd(int thread_id, int thread_num, void* param1, void* param2); void efBorder_vertical_convolution_alpha_and_put_color_simd2(int thread_id, int thread_num, void* param1, void* param2); void efBorder_vertical_convolution_alpha_simd(int thread_id, int thread_num, void* param1, void* param2); void efBorder_vertical_convolution_alpha_simd2(int thread_id, int thread_num, void* param1, void* param2); BOOL Border_t::func_proc(ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { if constexpr (true) { static stopwatch_mem sw{}; sw.start(); auto& border = *(reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efBorder_var_ptr)); auto& ExEditMemory = *(void**)(GLOBAL::exedit_base + OFS::ExEdit::memory_ptr); if (efp->track[0] <= 0) return TRUE; auto exdata = (ExEdit::Exdata::efBorder*)efp->exdata_ptr; int obj_w = efpip->obj_w; int obj_h = efpip->obj_h; int temp; int add_size = efp->track[0] * 2; border.inv_range = 0x1000 - efp->track[1] * 4096 / 1000; add_size = (std::min)({ add_size, efpip->obj_line - obj_w, efpip->obj_max_h - obj_h }); add_size &= 0xfffffffe; obj_w += add_size; obj_h += add_size; // efpip->obj_tempに画像を読み込む int file_w = 0; int file_h = 0; if (exdata->file[0] != '\0') { if (efp->exfunc->load_image((ExEdit::PixelYCA*)ExEditMemory, exdata->file, &file_w, &file_h, 0, 0)) { for (int i = 0; i < obj_h; i += file_h) { for (int j = 0; j < obj_w; j += file_w) { efp->exfunc->bufcpy(efpip->obj_temp, j, i, ExEditMemory, 0, 0, file_w, file_h, 0, 0x13000003); } } } } border.ExEditMemory = (unsigned short*)ExEditMemory; border.add_size = add_size; border.alpha = (int)round(65536.0 / ((double)efp->track[1] * add_size * 0.01 + 1.0)); temp = border.alpha; int sft = 0; while (sft < 16 && 64 < temp) { temp >>= 1; sft++; } border.alpha = temp; border._alpha_shift = 16 - sft; reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::rgb2yc)(&border.color_y, &border.color_cb, &border.color_cr, *(int*)&exdata->color & 0xffffff); if (efpip->obj_w <= add_size) { efp->aviutl_exfunc->exec_multi_thread_func(efBorder_horizontal_convolution_alpha_simd2, efp, efpip); } else { efp->aviutl_exfunc->exec_multi_thread_func(efBorder_horizontal_convolution_alpha_simd, efp, efpip); } if (efpip->obj_h <= add_size) { if (file_w == 0 || file_h == 0) { // 画像なし efp->aviutl_exfunc->exec_multi_thread_func(efBorder_vertical_convolution_alpha_and_put_color_simd2, efp, efpip); } else { // 画像あり efp->aviutl_exfunc->exec_multi_thread_func(efBorder_vertical_convolution_alpha_simd2, efp, efpip); } } else { if (file_w == 0 || file_h == 0) { // 画像なし efp->aviutl_exfunc->exec_multi_thread_func(efBorder_vertical_convolution_alpha_and_put_color_simd, efp, efpip); } else { // 画像あり efp->aviutl_exfunc->exec_multi_thread_func(efBorder_vertical_convolution_alpha_simd, efp, efpip); } } efp->exfunc->bufcpy(efpip->obj_temp, add_size / 2, add_size / 2, efpip->obj_edit, 0, 0, efpip->obj_w, efpip->obj_h, 0, 3); std::swap(efpip->obj_temp, efpip->obj_edit); efpip->obj_w = obj_w; efpip->obj_h = obj_h; sw.stop(); return TRUE; } else { static stopwatch_mem sw{}; sw.start(); auto ret = ((decltype(ExEdit::Filter::func_proc))(GLOBAL::exedit_base + OFS::ExEdit::efBorder_func_proc_ptr))(efp, efpip); sw.stop(); return ret; } } #define ALPHA_TEMP_MAX 0xFFFF void efBorder_horizontal_convolution_alpha_simd(int thread_id, int thread_num, void* param1, void* param2) { auto& border = *reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efBorder_var_ptr); auto efp = static_cast(param1); auto efpip = static_cast(param2); int begin_thread = efpip->obj_h * thread_id / thread_num; int end_thread = efpip->obj_h * (thread_id + 1) / thread_num; int y = begin_thread; if (enable_avx2()) { __m256i offset256 = _mm256_mullo_epi32(_mm256_set_epi32(14, 12, 10, 8, 6, 4, 2, 0), _mm256_set1_epi32(efpip->obj_line)); __m256i border_alpha256 = _mm256_set1_epi32(border.alpha); __m256i a_mem_max256 = _mm256_set1_epi32(ALPHA_TEMP_MAX); int end_y = end_thread - 7; for (; y < end_y; y += 8) { int* pix1 = (int*)((ExEdit::PixelYCA*)efpip->obj_edit + y * efpip->obj_line) + 1; int* pix2 = pix1; unsigned short* mem = border.ExEditMemory + y * efpip->obj_line; __m256i a_sum256 = _mm256_setzero_si256(); int x; for (x = 0; x <= border.add_size; x++) { __m256i a256 = _mm256_srli_epi32(_mm256_i32gather_epi32(pix1, offset256, 4), 16); a_sum256 = _mm256_add_epi32(a_sum256, a256); a256 = _mm256_mullo_epi32(a_sum256, border_alpha256); a256 = _mm256_srli_epi32(a256, border._alpha_shift); a256 = _mm256_min_epu32(a256, a_mem_max256); for (int i = 0; i < 8; i++) { mem[i * efpip->obj_line] = (unsigned short)a256.m256i_u32[i]; } pix1 += 2; mem++; } for (; x < efpip->obj_w; x++) { __m256i a256 = _mm256_srli_epi32(_mm256_i32gather_epi32(pix2, offset256, 4), 16); a_sum256 = _mm256_sub_epi32(a_sum256, a256); a256 = _mm256_srli_epi32(_mm256_i32gather_epi32(pix1, offset256, 4), 16); a_sum256 = _mm256_add_epi32(a_sum256, a256); a256 = _mm256_mullo_epi32(a_sum256, border_alpha256); a256 = _mm256_srli_epi32(a256, border._alpha_shift); a256 = _mm256_min_epu32(a256, a_mem_max256); for (int i = 0; i < 8; i++) { mem[i * efpip->obj_line] = (unsigned short)a256.m256i_u32[i]; } pix1 += 2; pix2 += 2; mem++; } int end_x = efpip->obj_w + border.add_size; for (; x < end_x; x++) { __m256i a256 = _mm256_srli_epi32(_mm256_i32gather_epi32(pix2, offset256, 4), 16); a_sum256 = _mm256_sub_epi32(a_sum256, a256); a256 = _mm256_mullo_epi32(a_sum256, border_alpha256); a256 = _mm256_srli_epi32(a256, border._alpha_shift); a256 = _mm256_min_epu32(a256, a_mem_max256); for (int i = 0; i < 8; i++) { mem[i * efpip->obj_line] = (unsigned short)a256.m256i_u32[i]; } pix2 += 2; mem++; } } } for (; y < end_thread; y++) { short* pixa1 = (short*)((ExEdit::PixelYCA*)efpip->obj_edit + y * efpip->obj_line) + 3; short* pixa2 = pixa1; unsigned short* mem = border.ExEditMemory + y * efpip->obj_line; int a_sum = 0; int x; for (x = 0; x <= border.add_size; x++) { a_sum += *pixa1; *mem = (unsigned short)min(a_sum * border.alpha >> border._alpha_shift, ALPHA_TEMP_MAX); pixa1 += 4; mem++; } for (; x < efpip->obj_w; x++) { a_sum += *pixa1 - *pixa2; *mem = (unsigned short)min(a_sum * border.alpha >> border._alpha_shift, ALPHA_TEMP_MAX); pixa1 += 4; pixa2 += 4; mem++; } for (x = 0; x < border.add_size; x++) { a_sum -= *pixa2; *mem = (unsigned short)min(a_sum * border.alpha >> border._alpha_shift, ALPHA_TEMP_MAX); pixa2 += 4; mem++; } } } void efBorder_horizontal_convolution_alpha_simd2(int thread_id, int thread_num, void* param1, void* param2) { // 51ae0 auto& border = *reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efBorder_var_ptr); auto efp = static_cast(param1); auto efpip = static_cast(param2); int begin_thread = efpip->obj_h * thread_id / thread_num; int end_thread = efpip->obj_h * (thread_id + 1) / thread_num; int y = begin_thread; if (enable_avx2()) { __m256i offset256 = _mm256_mullo_epi32(_mm256_set_epi32(14, 12, 10, 8, 6, 4, 2, 0), _mm256_set1_epi32(efpip->obj_line)); __m256i border_alpha256 = _mm256_set1_epi32(border.alpha); __m256i a_mem_max256 = _mm256_set1_epi32(ALPHA_TEMP_MAX); int end_y = end_thread - 7; for (; y < end_y; y += 8) { int* pix1 = (int*)((ExEdit::PixelYCA*)efpip->obj_edit + y * efpip->obj_line) + 1; int* pix2 = pix1; unsigned short* mem = border.ExEditMemory + y * efpip->obj_line; __m256i a_sum256 = _mm256_setzero_si256(); __m256i a256; int x; for (x = 0; x < efpip->obj_w; x++) { a256 = _mm256_srli_epi32(_mm256_i32gather_epi32(pix1, offset256, 4), 16); a_sum256 = _mm256_add_epi32(a_sum256, a256); a256 = _mm256_mullo_epi32(a_sum256, border_alpha256); a256 = _mm256_srli_epi32(a256, border._alpha_shift); a256 = _mm256_min_epu32(a256, a_mem_max256); for (int i = 0; i < 8; i++) { mem[i * efpip->obj_line] = (unsigned short)a256.m256i_u32[i]; } pix1 += 2; mem++; } for (; x < border.add_size; x++) { for (int i = 0; i < 8; i++) { mem[i * efpip->obj_line] = (unsigned short)a256.m256i_u32[i]; } mem++; } for (x = 0; x < efpip->obj_w; x++) { a256 = _mm256_srli_epi32(_mm256_i32gather_epi32(pix2, offset256, 4), 16); a_sum256 = _mm256_sub_epi32(a_sum256, a256); a256 = _mm256_mullo_epi32(a_sum256, border_alpha256); a256 = _mm256_srli_epi32(a256, border._alpha_shift); a256 = _mm256_min_epu32(a256, a_mem_max256); for (int i = 0; i < 8; i++) { mem[i * efpip->obj_line] = (unsigned short)a256.m256i_u32[i]; } pix2 += 2; mem++; } } } for (; y < end_thread; y++) { short* pixa1 = (short*)((ExEdit::PixelYCA*)efpip->obj_edit + y * efpip->obj_line) + 3; short* pixa2 = pixa1; unsigned short* mem = border.ExEditMemory + y * efpip->obj_line; unsigned int a_sum = 0; unsigned short a; int x; for (x = 0; x < efpip->obj_w; x++) { a_sum += *pixa1; *mem = a = (unsigned short)min(a_sum * border.alpha >> border._alpha_shift, ALPHA_TEMP_MAX); pixa1 += 4; mem++; } for (; x < border.add_size; x++) { *mem = a; mem++; } for (x = 0; x < efpip->obj_w; x++) { a_sum -= *pixa2; *mem = (unsigned short)min(a_sum * border.alpha >> border._alpha_shift, ALPHA_TEMP_MAX); pixa2 += 4; mem++; } } } void efBorder_vertical_convolution_alpha_and_put_color_simd(int thread_id, int thread_num, void* param1, void* param2) { auto& border = *reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efBorder_var_ptr); auto efp = static_cast(param1); auto efpip = static_cast(param2); ExEdit::PixelYCA* pix; ExEdit::PixelYCA color = { border.color_y, border.color_cb, border.color_cr,0 }; unsigned short* mem1; unsigned short* mem2; int begin_thread = (efpip->obj_w + border.add_size) * thread_id / thread_num; int end_thread = (efpip->obj_w + border.add_size) * (thread_id + 1) / thread_num; int x = begin_thread; if (enable_avx2()) { __m256i color256 = _mm256_set1_epi64x(*(long long*)&color); __m256i border_alpha256 = _mm256_set1_epi64x(border.alpha); __m256i a_pix_max256 = _mm256_set1_epi64x(0x1000); int end_x = end_thread - 3; for (; x < end_x; x += 4) { pix = (ExEdit::PixelYCA*)efpip->obj_temp + x; mem1 = mem2 = border.ExEditMemory + x; __m256i a_sum256 = _mm256_setzero_si256(); int y; for (y = 0; y <= border.add_size; y++) { a_sum256 = _mm256_add_epi64(a_sum256, _mm256_cvtepu16_epi64(*(__m128i*)mem1)); __m256i pix256 = _mm256_mullo_epi32(a_sum256, border_alpha256); pix256 = _mm256_srli_epi32(pix256, border._alpha_shift); pix256 = _mm256_min_epi32(pix256, a_pix_max256); pix256 = _mm256_slli_epi64(pix256, 48); *(__m256i*)pix = _mm256_or_si256(pix256, color256); pix += efpip->obj_line; mem1 += efpip->obj_line; } for (; y < efpip->obj_h; y++) { a_sum256 = _mm256_sub_epi64(a_sum256, _mm256_cvtepu16_epi64(*(__m128i*)mem2)); a_sum256 = _mm256_add_epi64(a_sum256, _mm256_cvtepu16_epi64(*(__m128i*)mem1)); __m256i pix256 = _mm256_mullo_epi32(a_sum256, border_alpha256); pix256 = _mm256_srli_epi32(pix256, border._alpha_shift); pix256 = _mm256_min_epi32(pix256, a_pix_max256); pix256 = _mm256_slli_epi64(pix256, 48); *(__m256i*)pix = _mm256_or_si256(pix256, color256); pix += efpip->obj_line; mem1 += efpip->obj_line; mem2 += efpip->obj_line; } for (y = 0; y < border.add_size; y++) { a_sum256 = _mm256_sub_epi64(a_sum256, _mm256_cvtepu16_epi64(*(__m128i*)mem2)); __m256i pix256 = _mm256_mullo_epi32(a_sum256, border_alpha256); pix256 = _mm256_srli_epi32(pix256, border._alpha_shift); pix256 = _mm256_min_epi32(pix256, a_pix_max256); pix256 = _mm256_slli_epi64(pix256, 48); *(__m256i*)pix = _mm256_or_si256(pix256, color256); pix += efpip->obj_line; mem2 += efpip->obj_line; } } } for (; x < end_thread; x++) { pix = (ExEdit::PixelYCA*)efpip->obj_temp + x; mem1 = mem2 = border.ExEditMemory + x; unsigned int a_sum = 0; int y; for (y = 0; y <= border.add_size; y++) { a_sum += *mem1; if (a_sum == 0) { pix->a = 0; } else { color.a = (short)min(a_sum * border.alpha >> border._alpha_shift, 0x1000); *pix = color; } pix += efpip->obj_line; mem1 += efpip->obj_line; } for (; y < efpip->obj_h; y++) { a_sum += *mem1 - *mem2; if (a_sum == 0) { pix->a = 0; } else { color.a = (short)min(a_sum * border.alpha >> border._alpha_shift, 0x1000); *pix = color; } pix += efpip->obj_line; mem1 += efpip->obj_line; mem2 += efpip->obj_line; } for (y = 0; y < border.add_size; y++) { a_sum -= *mem2; if (a_sum == 0) { pix->a = 0; } else { color.a = (short)min(a_sum * border.alpha >> border._alpha_shift, 0x1000); *pix = color; } pix += efpip->obj_line; mem2 += efpip->obj_line; } } } void efBorder_vertical_convolution_alpha_and_put_color_simd2(int thread_id, int thread_num, void* param1, void* param2) { auto& border = *reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efBorder_var_ptr); auto efp = static_cast(param1); auto efpip = static_cast(param2); ExEdit::PixelYCA* pix; ExEdit::PixelYCA color = { border.color_y, border.color_cb, border.color_cr,0 }; unsigned short* mem1; unsigned short* mem2; int begin_thread = (efpip->obj_w + border.add_size) * thread_id / thread_num; int end_thread = (efpip->obj_w + border.add_size) * (thread_id + 1) / thread_num; int x = begin_thread; if (enable_avx2()) { __m256i color256 = _mm256_set1_epi64x(*(long long*)&color); __m256i border_alpha256 = _mm256_set1_epi64x(border.alpha); __m256i a_pix_max256 = _mm256_set1_epi64x(0x1000); int end_x = end_thread - 3; for (; x < end_x; x += 4) { pix = (ExEdit::PixelYCA*)efpip->obj_temp + x; mem1 = mem2 = border.ExEditMemory + x; __m256i a_sum256 = _mm256_setzero_si256(); __m256i pix256; int y; for (y = 0; y < efpip->obj_h; y++) { a_sum256 = _mm256_add_epi64(a_sum256, _mm256_cvtepu16_epi64(*(__m128i*)mem1)); pix256 = _mm256_mullo_epi32(a_sum256, border_alpha256); pix256 = _mm256_srli_epi32(pix256, border._alpha_shift); pix256 = _mm256_min_epi32(pix256, a_pix_max256); pix256 = _mm256_slli_epi64(pix256, 48); *(__m256i*)pix = pix256 = _mm256_or_si256(pix256, color256); pix += efpip->obj_line; mem1 += efpip->obj_line; } for (; y < border.add_size; y++) { *(__m256i*)pix = pix256; pix += efpip->obj_line; } for (y = 0; y < efpip->obj_h; y++) { a_sum256 = _mm256_sub_epi64(a_sum256, _mm256_cvtepu16_epi64(*(__m128i*)mem2)); pix256 = _mm256_mullo_epi32(a_sum256, border_alpha256); pix256 = _mm256_srli_epi32(pix256, border._alpha_shift); pix256 = _mm256_min_epi32(pix256, a_pix_max256); pix256 = _mm256_slli_epi64(pix256, 48); *(__m256i*)pix = _mm256_or_si256(pix256, color256); pix += efpip->obj_line; mem2 += efpip->obj_line; } } } for (; x < end_thread; x++) { pix = (ExEdit::PixelYCA*)efpip->obj_temp + x; mem1 = mem2 = border.ExEditMemory + x; unsigned int a_sum = 0; int y; for (y = 0; y < efpip->obj_h; y++) { a_sum += *mem1; if (a_sum == 0) { pix->a = color.a = 0; } else { color.a = (short)min(a_sum * border.alpha >> border._alpha_shift, 0x1000); *pix = color; } pix += efpip->obj_line; mem1 += efpip->obj_line; } for (; y < border.add_size; y++) { *pix = color; pix += efpip->obj_line; } for (y = 0; y < efpip->obj_h; y++) { a_sum -= *mem2; if (a_sum == 0) { pix->a = 0; } else { color.a = (short)min(a_sum * border.alpha >> border._alpha_shift, 0x1000); *pix = color; } pix += efpip->obj_line; mem2 += efpip->obj_line; } } } void efBorder_vertical_convolution_alpha_simd(int thread_id, int thread_num, void* param1, void* param2) { auto& border = *reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efBorder_var_ptr); auto efp = static_cast(param1); auto efpip = static_cast(param2); unsigned short* mem1; unsigned short* mem2; int begin_thread = (efpip->obj_w + border.add_size) * thread_id / thread_num; int end_thread = (efpip->obj_w + border.add_size) * (thread_id + 1) / thread_num; int x = begin_thread; if (enable_avx2()) { __m256i offset256 = _mm256_set_epi32(14, 12, 10, 8, 6, 4, 2, 0); __m256i border_alpha256 = _mm256_set1_epi32(border.alpha); __m256i a_pix_max256 = _mm256_set1_epi32(0x1000); int end_x = end_thread - 7; for (; x < end_x; x += 8) { int* pixa = (int*)((ExEdit::PixelYCA*)efpip->obj_temp + x) + 1; mem1 = mem2 = border.ExEditMemory + x; __m256i a_sum256 = _mm256_setzero_si256(); int y; for (y = 0; y <= border.add_size; y++) { a_sum256 = _mm256_add_epi32(a_sum256, _mm256_cvtepu16_epi32(*(__m128i*)mem1)); __m256i a256 = _mm256_mullo_epi32(a_sum256, border_alpha256); a256 = _mm256_srli_epi32(a256, border._alpha_shift); a256 = _mm256_min_epu32(a256, a_pix_max256); __m256i pixa256 = _mm256_srli_epi32(_mm256_i32gather_epi32(pixa, offset256, 4), 16); a256 = _mm256_mullo_epi32(a256, pixa256); a256 = _mm256_srli_epi32(a256, 12); short* pixas = (short*)pixa + 1; for (int i = 0; i < 8; i++) { pixas[i * 4] = (unsigned short)a256.m256i_u32[i]; } pixa += efpip->obj_line * 2; mem1 += efpip->obj_line; } for (; y < efpip->obj_h; y++) { a_sum256 = _mm256_add_epi32(a_sum256, _mm256_cvtepu16_epi32(*(__m128i*)mem1)); a_sum256 = _mm256_sub_epi32(a_sum256, _mm256_cvtepu16_epi32(*(__m128i*)mem2)); __m256i a256 = _mm256_mullo_epi32(a_sum256, border_alpha256); a256 = _mm256_srli_epi32(a256, border._alpha_shift); a256 = _mm256_min_epu32(a256, a_pix_max256); __m256i pixa256 = _mm256_srli_epi32(_mm256_i32gather_epi32(pixa, offset256, 4), 16); a256 = _mm256_mullo_epi32(a256, pixa256); a256 = _mm256_srli_epi32(a256, 12); short* pixas = (short*)pixa + 1; for (int i = 0; i < 8; i++) { pixas[i * 4] = (unsigned short)a256.m256i_u32[i]; } pixa += efpip->obj_line * 2; mem1 += efpip->obj_line; mem2 += efpip->obj_line; } for (y = 0; y < border.add_size; y++) { a_sum256 = _mm256_sub_epi32(a_sum256, _mm256_cvtepu16_epi32(*(__m128i*)mem2)); __m256i a256 = _mm256_mullo_epi32(a_sum256, border_alpha256); a256 = _mm256_srli_epi32(a256, border._alpha_shift); a256 = _mm256_min_epu32(a256, a_pix_max256); __m256i pixa256 = _mm256_srli_epi32(_mm256_i32gather_epi32(pixa, offset256, 4), 16); a256 = _mm256_mullo_epi32(a256, pixa256); a256 = _mm256_srli_epi32(a256, 12); short* pixas = (short*)pixa + 1; for (int i = 0; i < 8; i++) { pixas[i * 4] = (unsigned short)a256.m256i_u32[i]; } pixa += efpip->obj_line * 2; mem2 += efpip->obj_line; } } } for (; x < end_thread; x++) { short* pixa = (short*)((ExEdit::PixelYCA*)efpip->obj_temp + x) + 3; mem1 = mem2 = border.ExEditMemory + x; int a; unsigned int a_sum = 0; int y; for (y = 0; y <= border.add_size; y++) { a_sum += *mem1; a = a_sum * border.alpha >> border._alpha_shift; if (a < 0x1000) { *pixa = (short)(*pixa * a >> 12); } pixa += efpip->obj_line * 4; mem1 += efpip->obj_line; } for (; y < efpip->obj_h; y++) { a_sum += *mem1 - *mem2; a = a_sum * border.alpha >> border._alpha_shift; if (a < 0x1000) { *pixa = (short)(*pixa * a >> 12); } pixa += efpip->obj_line * 4; mem1 += efpip->obj_line; mem2 += efpip->obj_line; } for (y = 0; y < border.add_size; y++) { a_sum -= *mem2; a = a_sum * border.alpha >> border._alpha_shift; if (a < 0x1000) { *pixa = (short)(*pixa * a >> 12); } pixa += efpip->obj_line * 4; mem2 += efpip->obj_line; } } } void efBorder_vertical_convolution_alpha_simd2(int thread_id, int thread_num, void* param1, void* param2) { auto& border = *reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efBorder_var_ptr); auto efp = static_cast(param1); auto efpip = static_cast(param2); unsigned short* mem1; unsigned short* mem2; int begin_thread = (efpip->obj_w + border.add_size) * thread_id / thread_num; int end_thread = (efpip->obj_w + border.add_size) * (thread_id + 1) / thread_num; int x = begin_thread; if (enable_avx2()) { __m256i offset256 = _mm256_set_epi32(14, 12, 10, 8, 6, 4, 2, 0); __m256i border_alpha256 = _mm256_set1_epi32(border.alpha); __m256i a_pix_max256 = _mm256_set1_epi32(0x1000); int end_x = end_thread - 7; for (; x < end_x; x += 8) { int* pixa = (int*)((ExEdit::PixelYCA*)efpip->obj_temp + x) + 1; mem1 = mem2 = border.ExEditMemory + x; __m256i a_sum256 = _mm256_setzero_si256(); __m256i a256; int y; for (y = 0; y < efpip->obj_h; y++) { a_sum256 = _mm256_add_epi32(a_sum256, _mm256_cvtepu16_epi32(*(__m128i*)mem1)); a256 = _mm256_mullo_epi32(a_sum256, border_alpha256); a256 = _mm256_srli_epi32(a256, border._alpha_shift); a256 = _mm256_min_epu32(a256, a_pix_max256); __m256i pixa256 = _mm256_srli_epi32(_mm256_i32gather_epi32(pixa, offset256, 4), 16); pixa256 = _mm256_mullo_epi32(a256, pixa256); pixa256 = _mm256_srli_epi32(pixa256, 12); short* pixas = (short*)pixa + 1; for (int i = 0; i < 8; i++) { pixas[i * 4] = (unsigned short)pixa256.m256i_u32[i]; } pixa += efpip->obj_line * 2; mem1 += efpip->obj_line; } for (; y < border.add_size; y++) { __m256i pixa256 = _mm256_srli_epi32(_mm256_i32gather_epi32(pixa, offset256, 4), 16); pixa256 = _mm256_mullo_epi32(a256, pixa256); pixa256 = _mm256_srli_epi32(pixa256, 12); short* pixas = (short*)pixa + 1; for (int i = 0; i < 8; i++) { pixas[i * 4] = (unsigned short)pixa256.m256i_u32[i]; } pixa += efpip->obj_line * 2; } for (y = 0; y < efpip->obj_h; y++) { a_sum256 = _mm256_sub_epi32(a_sum256, _mm256_cvtepu16_epi32(*(__m128i*)mem2)); a256 = _mm256_mullo_epi32(a_sum256, border_alpha256); a256 = _mm256_srli_epi32(a256, border._alpha_shift); a256 = _mm256_min_epu32(a256, a_pix_max256); __m256i pixa256 = _mm256_srli_epi32(_mm256_i32gather_epi32(pixa, offset256, 4), 16); pixa256 = _mm256_mullo_epi32(a256, pixa256); pixa256 = _mm256_srli_epi32(pixa256, 12); short* pixas = (short*)pixa + 1; for (int i = 0; i < 8; i++) { pixas[i * 4] = (unsigned short)pixa256.m256i_u32[i]; } pixa += efpip->obj_line * 2; mem2 += efpip->obj_line; } } } for (; x < end_thread; x++) { short* pixa = (short*)((ExEdit::PixelYCA*)efpip->obj_temp + x) + 3; mem1 = mem2 = border.ExEditMemory + x; int a; unsigned int a_sum = 0; int y; for (y = 0; y < efpip->obj_h; y++) { a_sum += *mem1; a = a_sum * border.alpha >> border._alpha_shift; if (a < 0x1000) { *pixa = (short)(*pixa * a >> 12); } pixa += efpip->obj_line * 4; mem1 += efpip->obj_line; } if (a < 0x1000) { for (; y < border.add_size; y++) { *pixa = (short)(*pixa * a >> 12); pixa += efpip->obj_line * 4; } } else { pixa += efpip->obj_line * 4 * (border.add_size - efpip->obj_h); } for (y = 0; y < efpip->obj_h; y++) { a_sum -= *mem2; a = a_sum * border.alpha >> border._alpha_shift; if (a < 0x1000) { *pixa = (short)(*pixa * a >> 12); } pixa += efpip->obj_line * 4; mem2 += efpip->obj_line; } } } } #endif // ifdef PATCH_SWITCH_FAST_BORDER ================================================ FILE: patch/patch_fast_border.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FAST_BORDER #include #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "global.hpp" #include "config_rw.hpp" namespace patch::fast { // init at exedit load // 縁取りのバグ修正&ちょっとだけ高速化 inline class Border_t { static BOOL func_proc(ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); bool enabled = true; bool enabled_i; inline static const char key[] = "fast.border"; public: struct efBorder_var { // 1b1e30 unsigned short* ExEditMemory; int add_size; int inv_range; int shift_x; int shift_y; int _undefined; char _exdata_def[260]; // 1b1e48 - 1b1f4b short color_cb; // 1b1f4c short color_cr; short color_y; short _alpha_shift;// short _padding; int alpha; }; void init() { enabled_i = enabled; if (!enabled_i)return; store_i32(GLOBAL::exedit_base + OFS::ExEdit::efBorder_func_proc_var_ptr, &func_proc); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } Border; } // namespace patch::fast #endif // ifdef PATCH_SWITCH_FAST_BORDER ================================================ FILE: patch/patch_fast_cl.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_CL #include #include #include #include "debug_log.hpp" #define __CL_ENABLE_EXCEPTIONS #define CL_USE_DEPRECATED_OPENCL_1_2_APIS #define CL_VERSION_1_0 1 #define CL_VERSION_1_1 1 #define CL_VERSION_1_2 1 #define CL_VERSION_2_0 0 #define CL_VERSION_2_1 0 #define CL_VERSION_2_2 0 #define CL_VERSION_3_0 0 #pragma warning(push) #pragma warning(disable: 4005) #include #pragma warning(pop) #pragma comment(lib, "opencl.lib") #include "cryptostring.hpp" #include "util.hpp" #include "debug_log.hpp" #include "config_rw.hpp" namespace patch::fast { inline class cl_t { #pragma region clprogram inline static auto program_str = make_cryptostring(R"( kernel void PolorTransform(global short* dst, global short* src, int obj_w, int obj_h, int obj_line, int center_length, int radius, float angle, float uzu, float uzu_a){ int x = get_global_id(0); int y = get_global_id(1); int x_dist = x - radius; int y_dist = y - radius; float dist = sqrt((float)(x_dist * x_dist + y_dist * y_dist)); int range = (int)round((float)obj_w / max(dist, 1.0f) * 57.6115417480468f + uzu_a); int yy_t256 = (int)round((float)(((obj_h + center_length) << 8) / radius) * dist); int yy_range_fr = 0x100 - (yy_t256 & 0xff); int yy_begin = (yy_t256 >> 8) - center_length; int xx_t256 = (int)round((((float)radius - dist) * uzu + angle - atan2((float)y_dist, (float)x_dist)) * (float)obj_w * 40.7436637878417f) - range / 2; int xx_range_fr = 0x100 - (xx_t256 & 0xff); int xx_begin = (xx_t256 >> 8) % obj_w; range = max(0x100,range); int yy = yy_begin; int sum_y = 0; int sum_cb = 0; int sum_cr = 0; int sum_a = 0; global short* pix; int src_a; if (0 <= yy && yy < obj_h) { int range_remain = range; int xx = xx_begin; if (xx_range_fr) { pix = src + (xx + yy * obj_line) * 4; sum_a = pix[3] * xx_range_fr * yy_range_fr >> 16; sum_y = pix[0] * sum_a >> 12; sum_cb = pix[1] * sum_a >> 12; sum_cr = pix[2] * sum_a >> 12; range_remain -= xx_range_fr; xx++; xx %= obj_w; } int pix_range = range_remain >> 8; for(int i=0;i> 8; sum_y += pix[0] * src_a >> 12; sum_cb += pix[1] * src_a >> 12; sum_cr += pix[2] * src_a >> 12; sum_a += src_a; xx++; xx %= obj_w; } range_remain &= 0xff; if (range_remain) { pix = src + (xx + yy * obj_line) * 4; src_a = pix[3] * range_remain * yy_range_fr >> 16; sum_y += pix[0] * src_a >> 12; sum_cb += pix[1] * src_a >> 12; sum_cr += pix[2] * src_a >> 12; sum_a += src_a; } } yy++; yy_range_fr = 0x100 - yy_range_fr; if (0 <= yy && yy < obj_h) { int range_remain = range; int xx = xx_begin; if (xx_range_fr != 0x100) { pix = src + (xx + yy * obj_line) * 4; src_a = pix[3] * xx_range_fr * yy_range_fr >> 16; sum_y += pix[0] * src_a >> 12; sum_cb += pix[1] * src_a >> 12; sum_cr += pix[2] * src_a >> 12; sum_a += src_a; range_remain -= xx_range_fr; xx++; xx %= obj_w; } int pix_range = range_remain >> 8; for(int i=0;i> 8; sum_y += pix[0] * src_a>> 12; sum_cb += pix[1] * src_a >> 12; sum_cr += pix[2] * src_a >> 12; sum_a += src_a; xx++; xx %= obj_w; } range_remain &= 0xff; if (range_remain) { pix = src + (xx + yy * obj_line) * 4; src_a = pix[3] * range_remain * yy_range_fr >> 16; sum_y += pix[0] * src_a >> 12; sum_cb += pix[1] * src_a >> 12; sum_cr += pix[2] * src_a >> 12; sum_a += src_a; } } dst += (x + y * obj_line) * 4; if (sum_a) { float a_float = 4096.0f / (float)sum_a; dst[0] = (short)round((float)sum_y * a_float); dst[1] = (short)round((float)sum_cb * a_float); dst[2] = (short)round((float)sum_cr * a_float); dst[3] = (short)((sum_a << 8) / range); } else { dst[0] = dst[1] = dst[2] = dst[3] = 0; } } )" R"( kernel void DisplacementMap_move(global short* dst, global short* src, global short* mem, int obj_w, int obj_h, int obj_line, int param0, int param1, int ox, int oy) { int x = get_global_id(0); int y = get_global_id(1); dst += (x + y * obj_line) * 4; mem += (x + y * obj_line) * 4; int p0 = min(mem[0], mem[obj_line * 4]); int p1 = max(mem[4], mem[obj_line * 4 + 4]); p0 = (p0 - 0x800) * param0 / 5; p1 = (p1 - 0x800) * param0 / 5 + 0x1000; if (p1 < p0) { int tmp = p0; p0 = p1; p1 = tmp; } int xx_range = p1 - p0; int xx_begin = p0 + (x << 12); int xx_end = xx_range + xx_begin; p0 = min(mem[1], mem[5]); p1 = max(mem[obj_line * 4 + 1], mem[obj_line * 4 + 5]); p0 = (p0 - 0x800) * param1 / 5; p1 = (p1 - 0x800) * param1 / 5 + 0x1000; if (p1 < p0) { int tmp = p0; p0 = p1; p1 = tmp; } int yy_range = p1 - p0; int yy_begin = p0 + (y << 12); int yy_end = yy_range + yy_begin; if (xx_range < 0x1000) { xx_begin += (xx_range - 0x1000) >> 1; xx_end = xx_begin + 0x1000; xx_range = 0x1000; } if (yy_range < 0x1000) { yy_begin += (yy_range - 0x1000) >> 1; yy_end = yy_begin + 0x1000; yy_range = 0x1000; } int xx_level = 12; int yy_level = 12; while (0x20000 < xx_range) { xx_begin >>= 1; xx_end++; xx_end >>= 1; xx_range = xx_end - xx_begin; xx_level--; } while (0x20000 < yy_range) { yy_begin >>= 1; yy_end++; yy_end >>= 1; yy_range = yy_end - yy_begin; yy_level--; } xx_level &= 0x1f; yy_level &= 0x1f; xx_begin = max(xx_begin, 0); xx_end = min(xx_end, obj_w << xx_level); yy_begin = max(yy_begin, 0); yy_end = min(yy_end, obj_h << yy_level); float dsum_y = 0.0f; float dsum_cb = 0.0f; float dsum_cr = 0.0f; float dsum_a = 0.0f; int yy = yy_begin; while (yy < yy_end) { int yy_itr = yy >> yy_level; int sum_y = 0; int sum_cb = 0; int sum_cr = 0; int sum_a = 0; int xx = xx_begin; while (xx < xx_end) { int xx_itr = xx >> xx_level; int fraction; if (xx & 0xfff) { fraction = -xx & 0xfff; } else { fraction = min(xx_end - xx, 0x1000); } global short* srct = src + (xx_itr + yy_itr * obj_line) * 4; int src_a = srct[3] * fraction >> 8; sum_y += srct[0] * src_a >> 16; sum_cb += srct[1] * src_a >> 16; sum_cr += srct[2] * src_a >> 16; sum_a += src_a; xx += fraction; } int fraction; if (yy & 0xfff) { fraction = -yy & 0xfff; } else { fraction = min(yy_end - yy, 0x1000); } float fraction_rate = (float)fraction * 0.000244140625f; dsum_y += (float)sum_y * fraction_rate; dsum_cb += (float)sum_cb * fraction_rate; dsum_cr += (float)sum_cr * fraction_rate; dsum_a += (float)sum_a * fraction_rate; yy += fraction; } if (256.0f <= dsum_a) { float inv_a = 65536.0f / dsum_a; dst[0] = (short)round(dsum_y * inv_a); dst[1] = (short)round(dsum_cb * inv_a); dst[2] = (short)round(dsum_cr * inv_a); dst[3] = (short)round(dsum_a / ((float)yy_range / 1024.0f) / ((float)xx_range / 1024.0f)); } else { dst[0] = dst[1] = dst[2] = dst[3] = 0; } } kernel void DisplacementMap_zoom(global short* dst, global short* src, global short* mem, int obj_w, int obj_h, int obj_line, int param0, int param1, int ox, int oy){ int x = get_global_id(0); int y = get_global_id(1); dst += (x + y * obj_line) * 4; mem += (x + y * obj_line) * 4; int xx_min, xx_max, yy_min, yy_max; int xx_temp, yy_temp; float zoom; float xxd = (float)(x * 0x1000 - ox); if (0 < param0) { zoom = (1024.0f / (float)(param0 + 1000) - 1.0) * 0.00048828125f; } else { zoom = (float)param0 * -0.00000048828125f; } float temp = xxd * zoom; xx_min = xx_max = x * 0x1000 + (int)((float)(mem[0] - 0x800) * temp); xx_temp = x * 0x1000 + (int)((float)(mem[obj_line * 4] - 0x800) * temp); xx_min = min(xx_min, xx_temp); xx_max = max(xx_max, xx_temp); temp = (xxd + 4096.0f) * zoom; xx_temp = (x + 1) * 0x1000 + (int)((float)(mem[4] - 0x800) * temp); xx_min = min(xx_min, xx_temp); xx_max = max(xx_max, xx_temp); xx_temp = (x + 1) * 0x1000 + (int)((float)(mem[(obj_line + 1) * 4] - 0x800) * temp); int xx_begin = min(xx_min, xx_temp); int xx_end = max(xx_max, xx_temp); float yyd = (float)(y * 0x1000 - oy); if (0 < param1) { zoom = (1024.0f / (float)(param1 + 1000) - 1.0) * 0.00048828125f; } else { zoom = (float)param1 * -0.00000048828125f; } temp = yyd * zoom; yy_min = yy_max = y * 0x1000 + (int)((float)(mem[1] - 0x800) * temp); yy_temp = y * 0x1000 + (int)((float)(mem[5] - 0x800) * temp); yy_min = min(yy_min, yy_temp); yy_max = max(yy_max, yy_temp); temp = (yyd + 4096.0f) * zoom; yy_temp = (y + 1) * 0x1000 + (int)((float)(mem[(obj_line + 1) * 4] - 0x800) * temp); yy_min = min(yy_min, yy_temp); yy_max = max(yy_max, yy_temp); yy_temp = (y + 1) * 0x1000 + (int)((float)(mem[obj_line * 4 + 5] - 0x800) * temp); int yy_begin = min(yy_min, yy_temp); int yy_end = max(yy_max, yy_temp); int xx_range = xx_end - xx_begin; int yy_range = yy_end - yy_begin; if (xx_range < 0x1000) { xx_begin += (xx_range - 0x1000) >> 1; xx_end = xx_begin + 0x1000; xx_range = 0x1000; } if (yy_range < 0x1000) { yy_begin += (yy_range - 0x1000) >> 1; yy_end = yy_begin + 0x1000; yy_range = 0x1000; } int xx_level = 12; int yy_level = 12; while (0x20000 < xx_range) { xx_begin >>= 1; xx_end++; xx_end >>= 1; xx_range = xx_end - xx_begin; xx_level--; } while (0x20000 < yy_range) { yy_begin >>= 1; yy_end++; yy_end >>= 1; yy_range = yy_end - yy_begin; yy_level--; } xx_level &= 0x1f; yy_level &= 0x1f; xx_begin = max(xx_begin, 0); xx_end = min(xx_end, obj_w << xx_level); yy_begin = max(yy_begin, 0); yy_end = min(yy_end, obj_h << yy_level); float dsum_y = 0.0f; float dsum_cb = 0.0f; float dsum_cr = 0.0f; float dsum_a = 0.0f; int yy = yy_begin; while (yy < yy_end) { int yy_itr = yy >> yy_level; int sum_y = 0; int sum_cb = 0; int sum_cr = 0; int sum_a = 0; int xx = xx_begin; while (xx < xx_end) { int xx_itr = xx >> xx_level; int fraction; if (xx & 0xfff) { fraction = -xx & 0xfff; } else { fraction = min(xx_end - xx, 0x1000); } global short* srct = src + (xx_itr + yy_itr * obj_line) * 4; int src_a = srct[3] * fraction >> 8; sum_y += srct[0] * src_a >> 16; sum_cb += srct[1] * src_a >> 16; sum_cr += srct[2] * src_a >> 16; sum_a += src_a; xx += fraction; } int fraction; if (yy & 0xfff) { fraction = -yy & 0xfff; } else { fraction = min(yy_end - yy, 0x1000); } float fraction_rate = (float)fraction * 0.000244140625f; dsum_y += (float)sum_y * fraction_rate; dsum_cb += (float)sum_cb * fraction_rate; dsum_cr += (float)sum_cr * fraction_rate; dsum_a += (float)sum_a * fraction_rate; yy += fraction; } if (256.0f <= dsum_a) { float inv_a = 65536.0f / dsum_a; dst[0] = (short)round(dsum_y * inv_a); dst[1] = (short)round(dsum_cb * inv_a); dst[2] = (short)round(dsum_cr * inv_a); dst[3] = (short)round(dsum_a / ((float)yy_range / 1024.0f) / ((float)xx_range / 1024.0f)); } else { dst[0] = dst[1] = dst[2] = dst[3] = 0; } } kernel void DisplacementMap_rot(global short* dst, global short* src, global short* mem, int obj_w, int obj_h, int obj_line, int param0, int param1, int ox, int oy){ int x = get_global_id(0); int y = get_global_id(1); dst += (x + y * obj_line) * 4; mem += (x + y * obj_line) * 4; int xx_min, xx_max, yy_min, yy_max; int xx_temp, yy_temp; float xxd = (float)((x << 12) - ox); float yyd = (float)((y << 12) - oy); float xxd_next = xxd + 4096.0f; float yyd_next = yyd + 4096.0f; float paramrad = (float)param0 * (float)-0.000003067961642955197f; float rad = (float)(mem[0] - 0x800) * paramrad; float sinv = sin(rad); float cosv = cos(rad); xx_min = xx_max = (int)(xxd * cosv - yyd * sinv); yy_min = yy_max = (int)(xxd * sinv + yyd * cosv); rad = (float)(mem[4] - 0x800) * paramrad; sinv = sin(rad); cosv = cos(rad); xx_temp = (int)(xxd_next * cosv - yyd * sinv); yy_temp = (int)(xxd_next * sinv + yyd * cosv); xx_min = min(xx_min, xx_temp); xx_max = max(xx_max, xx_temp); yy_min = min(yy_min, yy_temp); yy_max = max(yy_max, yy_temp); rad = (float)(mem[obj_line * 4] - 0x800) * paramrad; sinv = sin(rad); cosv = cos(rad); xx_temp = (int)(xxd * cosv - yyd_next * sinv); yy_temp = (int)(xxd * sinv + yyd_next * cosv); xx_min = min(xx_min, xx_temp); xx_max = max(xx_max, xx_temp); yy_min = min(yy_min, yy_temp); yy_max = max(yy_max, yy_temp); rad = (float)(mem[(obj_line + 1) * 4] - 0x800) * paramrad; sinv = sin(rad); cosv = cos(rad); xx_temp = (int)(xxd_next * cosv - yyd_next * sinv); yy_temp = (int)(xxd_next * sinv + yyd_next * cosv); int xx_begin = min(xx_min, xx_temp) + ox; int xx_end = max(xx_max, xx_temp) + ox; int yy_begin = min(yy_min, yy_temp) + oy; int yy_end = max(yy_max, yy_temp) + oy; int xx_range = xx_end - xx_begin; int yy_range = yy_end - yy_begin; if (xx_range < 0x1000) { xx_begin += (xx_range - 0x1000) >> 1; xx_end = xx_begin + 0x1000; xx_range = 0x1000; } if (yy_range < 0x1000) { yy_begin += (yy_range - 0x1000) >> 1; yy_end = yy_begin + 0x1000; yy_range = 0x1000; } int xx_level = 12; int yy_level = 12; while (0x20000 < xx_range) { xx_begin >>= 1; xx_end++; xx_end >>= 1; xx_range = xx_end - xx_begin; xx_level--; } while (0x20000 < yy_range) { yy_begin >>= 1; yy_end++; yy_end >>= 1; yy_range = yy_end - yy_begin; yy_level--; } xx_level &= 0x1f; yy_level &= 0x1f; xx_begin = max(xx_begin, 0); xx_end = min(xx_end, obj_w << xx_level); yy_begin = max(yy_begin, 0); yy_end = min(yy_end, obj_h << yy_level); float dsum_y = 0.0f; float dsum_cb = 0.0f; float dsum_cr = 0.0f; float dsum_a = 0.0f; int yy = yy_begin; while (yy < yy_end) { int yy_itr = yy >> yy_level; int sum_y = 0; int sum_cb = 0; int sum_cr = 0; int sum_a = 0; int xx = xx_begin; while (xx < xx_end) { int xx_itr = xx >> xx_level; int fraction; if (xx & 0xfff) { fraction = -xx & 0xfff; } else { fraction = min(xx_end - xx, 0x1000); } global short* srct = src + (xx_itr + yy_itr * obj_line) * 4; int src_a = srct[3] * fraction >> 8; sum_y += srct[0] * src_a >> 16; sum_cb += srct[1] * src_a >> 16; sum_cr += srct[2] * src_a >> 16; sum_a += src_a; xx += fraction; } int fraction; if (yy & 0xfff) { fraction = -yy & 0xfff; } else { fraction = min(yy_end - yy, 0x1000); } float fraction_rate = (float)fraction * 0.000244140625f; dsum_y += (float)sum_y * fraction_rate; dsum_cb += (float)sum_cb * fraction_rate; dsum_cr += (float)sum_cr * fraction_rate; dsum_a += (float)sum_a * fraction_rate; yy += fraction; } if (256.0f <= dsum_a) { float inv_a = 65536.0f / dsum_a; dst[0] = (short)round(dsum_y * inv_a); dst[1] = (short)round(dsum_cb * inv_a); dst[2] = (short)round(dsum_cr * inv_a); dst[3] = (short)round(dsum_a / ((float)yy_range / 1024.0f) / ((float)xx_range / 1024.0f)); } else { dst[0] = dst[1] = dst[2] = dst[3] = 0; } } )" R"( kernel void RadiationalBlur_Media( global short* dst, global short* src, int src_w, int src_h, int buffer_line, int rb_blur_cx, int rb_blur_cy, int rb_obj_cx, int rb_obj_cy, int rb_range, int rb_pixel_range) { int x = get_global_id(0); int y = get_global_id(1); int pixel_itr = x + y * buffer_line; x += rb_obj_cx; y += rb_obj_cy; int cx = rb_blur_cx - x; int cy = rb_blur_cy - y; int c_dist_times8 = (int)round(sqrt((float)(cx * cx + cy * cy)) * 8.0f); int range = rb_range * c_dist_times8 / 1000; if (rb_pixel_range < c_dist_times8) { range = rb_pixel_range * rb_range / 1000; c_dist_times8 = rb_pixel_range; } else if (8 < c_dist_times8) { c_dist_times8 *= 8; range *= 8; } else if (4 < c_dist_times8) { c_dist_times8 *= 4; range *= 4; } else if (2 < c_dist_times8) { c_dist_times8 *= 2; range *= 2; } if (2 <= c_dist_times8 && 2 <= range) { int sum_a = 0; int sum_cr = 0; int sum_cb = 0; int sum_y = 0; for (int i = 0; i < range; i++) { int x_itr = x + i * cx / c_dist_times8; int y_itr = y + i * cy / c_dist_times8; if (0 <= x_itr && x_itr < src_w && 0 <= y_itr && y_itr < src_h) { short4 itr = vload4(x_itr + y_itr * buffer_line, src); int itr_a = itr.w; sum_a += itr_a; if (0x1000 < itr_a) { itr_a = 0x1000; } sum_y += itr.x * itr_a / 4096; sum_cb += itr.y * itr_a / 4096; sum_cr += itr.z * itr_a / 4096; } } if (sum_a != 0) { vstore4( (short4)( round(sum_y * 4096.0f / sum_a), round(sum_cb * 4096.0f / sum_a), round(sum_cr * 4096.0f / sum_a), sum_a / range ), pixel_itr, dst ); } else { dst[pixel_itr * 4 + 3] = 0; } } else { if (x < 0 || y < 0 || src_w <= x || src_h <= y) { vstore4((short4)(0, 0, 0, 0), pixel_itr, dst); } else { vstore4(vload4(x + y * buffer_line, src), pixel_itr, dst); } } } kernel void RadiationalBlur_Filter( global short* dst, global short* src, int buffer_line, int rb_blur_cx, int rb_blur_cy, int rb_range, int rb_pixel_range) { int x = get_global_id(0); int y = get_global_id(1); int cx = rb_blur_cx - x; int cy = rb_blur_cy - y; int c_dist_times8 = (int)round(sqrt((float)(cx * cx + cy * cy)) * 8.0f); int range = rb_range * c_dist_times8 / 1000; if (rb_pixel_range < c_dist_times8) { range = (rb_pixel_range * rb_range) / 1000; c_dist_times8 = rb_pixel_range; } else if (8 < c_dist_times8) { c_dist_times8 *= 8; range *= 8; } else if (4 < c_dist_times8) { c_dist_times8 *= 4; range *= 4; } else if (2 < c_dist_times8) { c_dist_times8 *= 2; range *= 2; } int offset = (x + y * buffer_line) * 3; if (2 <= c_dist_times8 && 2 <= range) { int sum_y = 0; int sum_cb = 0; int sum_cr = 0; for (int i = 0; i < range; i++) { int x_itr = x + i * cx / c_dist_times8; int y_itr = y + i * cy / c_dist_times8; int pix_offset = (x_itr + y_itr * buffer_line) * 3; sum_y += src[pix_offset]; sum_cb += src[++pix_offset]; sum_cr += src[++pix_offset]; } dst[offset] = (short)(sum_y / range); dst[++offset] = (short)(sum_cb / range); dst[++offset] = (short)(sum_cr / range); } else { dst[offset] = src[offset]; dst[offset + 1] = src[offset + 1]; dst[offset + 2] = src[offset + 2]; } } kernel void RadiationalBlur_Filter_Far( global short* dst, global short* src, int scene_w, int scene_h, int buffer_line, int rb_blur_cx, int rb_blur_cy, int rb_range, int rb_pixel_range) { int x = get_global_id(0); int y = get_global_id(1); int cx = rb_blur_cx - x; int cy = rb_blur_cy - y; int c_dist_times8 = (int)round(sqrt((float)(cx * cx + cy * cy)) * 8.0f); int range = rb_range * c_dist_times8 / 1000; if (rb_pixel_range < c_dist_times8) { range = (rb_pixel_range * rb_range) / 1000; c_dist_times8 = rb_pixel_range; } else if (8 < c_dist_times8) { c_dist_times8 *= 8; range *= 8; } else if (4 < c_dist_times8) { c_dist_times8 *= 4; range *= 4; } else if (2 < c_dist_times8) { c_dist_times8 *= 2; range *= 2; } int offset = (x + y * buffer_line) * 3; if (2 <= c_dist_times8 && 2 <= range) { int sum_y = 0; int sum_cb = 0; int sum_cr = 0; for (int i = 0; i < range; i++) { int x_itr = x + i * cx / c_dist_times8; int y_itr = y + i * cy / c_dist_times8; if (0 <= x_itr && 0 <= y_itr && x_itr < scene_w && y_itr < scene_h) { int pix_offset = (x_itr + y_itr * buffer_line) * 3; sum_y += src[pix_offset]; sum_cb += src[++pix_offset]; sum_cr += src[++pix_offset]; } } dst[offset] = (short)(sum_y / range); dst[++offset] = (short)(sum_cb / range); dst[++offset] = (short)(sum_cr / range); } else { dst[offset] = src[offset]; dst[offset + 1] = src[offset + 1]; dst[offset + 2] = src[offset + 2]; } } )" R"( kernel void Flash(global short* dst, global short* src, int src_w, int src_h, int exedit_buffer_line, int g_cx, int g_cy, int g_range, int g_pixel_range, int g_temp_x, int g_temp_y, int g_r_intensity ) { int xi = get_global_id(0); int yi = get_global_id(1); int x = xi + g_temp_x; int y = yi + g_temp_y; int pixel_itr = xi + yi * exedit_buffer_line; int cx = g_cx - x; int cy = g_cy - y; int c_dist_times8 = (int)round(sqrt((float)(cx * cx + cy * cy)) * 8.0f); int range = g_range * c_dist_times8 / 1000; if (g_pixel_range < c_dist_times8) { range = g_pixel_range * g_range / 1000; c_dist_times8 = g_pixel_range; } else if (8 < c_dist_times8) { c_dist_times8 *= 8; range *= 8; } else if (4 < c_dist_times8) { c_dist_times8 *= 4; range *= 4; } else if (2 < c_dist_times8) { c_dist_times8 *= 2; range *= 2; } int sum_y, sum_cb, sum_cr; if (2 <= c_dist_times8 && 2 <= range) { sum_y = sum_cb = sum_cr = 0; for (int i = 0; i < range; i++) { int x_itr = x + i * cx / c_dist_times8; int y_itr = y + i * cy / c_dist_times8; if (0 <= x_itr && 0 <= y_itr && x_itr < src_w && y_itr < src_h) { short4 itr = vload4(x_itr + y_itr * exedit_buffer_line, src); if (itr.w != 0) { if (itr.w < 4096) { sum_y += itr.x * itr.w / 4096; sum_cb += itr.y * itr.w / 4096; sum_cr += itr.z * itr.w / 4096; } else { sum_y += itr.x; sum_cb += itr.y; sum_cr += itr.z; } } } } sum_y /= range; sum_cb /= range; sum_cr /= range; } else { if (x < 0 || y < 0 || src_w <= x || src_h <= y) { vstore4((short4)(0, 0, 0, 0), pixel_itr, dst); return; } else { short4 itr = vload4(x + y * exedit_buffer_line, src); sum_y = itr.x * itr.w / 4096; sum_cb = itr.y * itr.w / 4096; sum_cr = itr.z * itr.w / 4096; } } int ya = sum_y - g_r_intensity; if (ya < 1) { vstore4((short4)(0, 0, 0, 0), pixel_itr, dst); } else { sum_cb -= g_r_intensity * sum_cb / sum_y; sum_cr -= g_r_intensity * sum_cr / sum_y; if (ya < 4096) { vstore4( (short4)( 4096, sum_cb * 4096 / ya, sum_cr * 4096 / ya, ya ), pixel_itr, dst ); } else { vstore4( (short4)( ya, sum_cb, sum_cr, 4096 ), pixel_itr, dst ); } } } kernel void FlashColor(global short* dst, global short* src, int src_w, int src_h, int exedit_buffer_line, int g_cx, int g_cy, int g_range, int g_pixel_range, int g_temp_x, int g_temp_y, int g_r_intensity, short g_color_y, short g_color_cb, short g_color_cr ) { int xi = get_global_id(0); int yi = get_global_id(1); int x = xi + g_temp_x; int y = yi + g_temp_y; int pixel_itr = xi + yi * exedit_buffer_line; int cx = g_cx - x; int cy = g_cy - y; int c_dist_times8 = (int)round(sqrt((float)(cx * cx + cy * cy)) * 8.0f); int range = g_range * c_dist_times8 / 1000; if (g_pixel_range < c_dist_times8) { range = g_pixel_range * g_range / 1000; c_dist_times8 = g_pixel_range; } else if (8 < c_dist_times8) { c_dist_times8 *= 8; range *= 8; } else if (4 < c_dist_times8) { c_dist_times8 *= 4; range *= 4; } else if (2 < c_dist_times8) { c_dist_times8 *= 2; range *= 2; } int itr_y, itr_cb, itr_cr; if (2 <= c_dist_times8 && 2 <= range) { int sum_a = 0; for (int i = 0; i < range; i++) { int x_itr = x + i * cx / c_dist_times8; int y_itr = y + i * cy / c_dist_times8; if (0 <= x_itr && 0 <= y_itr && x_itr < src_w && y_itr < src_h) { short4 itr = vload4(x_itr + y_itr * exedit_buffer_line, src); int itr_a = itr.w; if (itr_a != 0) { if (itr_a < 4096) { sum_a += itr_a; } else { sum_a += 4096; } } } } sum_a /= range; itr_y = g_color_y * sum_a / 4096; itr_cb = g_color_cb * sum_a / 4096; itr_cr = g_color_cr * sum_a / 4096; } else { if (x < 0 || y < 0 || src_w <= x || src_h <= y) { vstore4((short4)(0, 0, 0, 0), pixel_itr, dst); return; } else { short4 itr = vload4(x + y * exedit_buffer_line, src); int itr_a = itr.w; itr_y = g_color_y * itr_a / 4096; itr_cb = g_color_cb * itr_a / 4096; itr_cr = g_color_cr * itr_a / 4096; } } int ya = itr_y - g_r_intensity; if (ya < 1) { vstore4((short4)(0, 0, 0, 0), pixel_itr, dst); } else { itr_cb -= g_r_intensity * itr_cb / itr_y; itr_cr -= g_r_intensity * itr_cr / itr_y; if (ya < 4096) { vstore4( (short4)( 4096, itr_cb * 4096 / ya, itr_cr * 4096 / ya, ya ), pixel_itr, dst ); } else { vstore4( (short4)( ya, itr_cb, itr_cr, 4096 ), pixel_itr, dst ); } } } )" R"( kernel void DirectionalBlur_Media(global short* dst, global short* src, int obj_w, int obj_h, int obj_line, int x_begin, int x_end, int x_step, int y_begin, int y_end, int y_step, int range) { int x = get_global_id(0); int y = get_global_id(1); int pix_range = range * 2 + 1; dst += (x + y * obj_line) * 4; int sum_y = 0; int sum_cb = 0; int sum_cr = 0; int sum_a = 0; int x_itr = ((x + x_begin) << 16) + 0x8000 - range * x_step; int y_itr = ((y + y_begin) << 16) + 0x8000 - range * y_step; for (int n = 0; n < pix_range; n++) { int xx = x_itr >> 16; int yy = y_itr >> 16; if (0 <= xx && xx < obj_w && 0 <= yy && yy < obj_h) { global short* pix = src + (xx + yy * obj_line) * 4; int src_a = min((int)pix[3], 0x1000); sum_y += pix[0] * src_a >> 12; sum_cb += pix[1] * src_a >> 12; sum_cr += pix[2] * src_a >> 12; sum_a += src_a; } x_itr += x_step; y_itr += y_step; } if (0 < sum_a) { float a_float = 4096.0f / (float)sum_a; dst[0] = (short)round((float)sum_y * a_float); dst[1] = (short)round((float)sum_cb * a_float); dst[2] = (short)round((float)sum_cr * a_float); } else { dst[0] = dst[1] = dst[2] = 0; } dst[3] = (short)(sum_a / pix_range); } kernel void DirectionalBlur_original_size(global short* dst, global short* src, int obj_w, int obj_h, int obj_line, int x_step, int y_step, int range) { int x = get_global_id(0); int y = get_global_id(1); int pix_range = range * 2 + 1; dst += (x + y * obj_line) * 4; int x_itr = (x << 16) + 0x8000 - range * x_step; int y_itr = (y << 16) + 0x8000 - range * y_step; int sum_y = 0; int sum_cb = 0; int sum_cr = 0; int sum_a = 0; int cnt = 0; for (int n = 0; n < pix_range; n++) { int xx = x_itr >> 16; int yy = y_itr >> 16; if (0 <= xx && xx < obj_w && 0 <= yy && yy < obj_h) { global short* pix = src + (xx + yy * obj_line) * 4; int src_a = min((int)pix[3], 0x1000); sum_y += pix[0] * src_a >> 12; sum_cb += pix[1] * src_a >> 12; sum_cr += pix[2] * src_a >> 12; sum_a += src_a; cnt++; } x_itr += x_step; y_itr += y_step; } if(cnt == 0) cnt = 0xffffff; if (0 < sum_a) { float a_float = 4096.0f / (float)sum_a; dst[0] = (short)round((float)sum_y * a_float); dst[1] = (short)round((float)sum_cb * a_float); dst[2] = (short)round((float)sum_cr * a_float); } else { dst[0] = dst[1] = dst[2] = 0; } dst[3] = (short)(sum_a / cnt); } kernel void DirectionalBlur_Filter(global short* dst, global short* src, int scene_w, int scene_h, int scene_line, int x_step, int y_step, int range) { int x = get_global_id(0); int y = get_global_id(1); int pix_range = range * 2 + 1; dst += (x + y * scene_line) * 3; int x_itr = (x << 16) + 0x8000 - range * x_step; int y_itr = (y << 16) + 0x8000 - range * y_step; int sum_y = 0; int sum_cb = 0; int sum_cr = 0; int cnt = 0; for (int n = 0; n < pix_range; n++) { int xx = x_itr >> 16; int yy = y_itr >> 16; if (0 <= xx && xx < scene_w && 0 <= yy && yy < scene_h) { global short* pix = src + (xx + yy * scene_line) * 3; sum_y += pix[0]; sum_cb += pix[1]; sum_cr += pix[2]; cnt++; } x_itr += x_step; y_itr += y_step; } if(cnt == 0) cnt = 0xffffff; dst[0] = (short)(sum_y / cnt); dst[1] = (short)(sum_cb / cnt); dst[2] = (short)(sum_cr / cnt); } )" R"( kernel void LensBlur_Media(global char* dst, global char* src, int obj_w, int obj_h, int obj_line, int range, int rangep05_sqr, int range_t3m1, int rangem1_sqr) { int x = get_global_id(0); int y = get_global_id(1); int top = -min(y, range); int bottom = min(obj_h - y - 1, range); int left = -min(x, range); int right = min(obj_w - x - 1, range); float sum_y = 0.0f; int sum_cb = 0; int sum_cr = 0; int sum_a = 0; int cor_sum = 0; int offset = (x + left + (y + top) * obj_line) * 8; for (int yy = top; yy <= bottom; yy++) { int sqr = yy * yy + left * left; int offset2 = offset; for (int xx = left; xx <= right; xx++) { if (sqr < rangep05_sqr) { int cor_a; if (rangem1_sqr < sqr) { cor_a = ((rangep05_sqr - sqr) << 12) / range_t3m1; } else { cor_a = 4096; } cor_sum += cor_a; cor_a = *(global short*)&src[offset2 + 6] * cor_a >> 12; sum_y += *(global float*)&src[offset2] * (float)cor_a; sum_cb += src[offset2 + 4] * cor_a; sum_cr += src[offset2 + 5] * cor_a; sum_a += cor_a; } sqr += 1 + xx * 2; offset2 += 8; } offset += obj_line * 8; } dst += (x + y * obj_line) * 8; if (0 < sum_a) { *(global float*)dst = sum_y / (float)sum_a; dst[4] = (char)(((sum_a >> 1) + sum_cb) / sum_a); dst[5] = (char)(((sum_a >> 1) + sum_cr) / sum_a); *(global short*)&dst[6] = (short)round((float)sum_a * (4096.0f / (float)cor_sum)); } else { *(global int*)dst = 0; *(global int*)&dst[4] = 0; } } kernel void LensBlur_Filter(global char* dst, global char* src, int scene_w, int scene_h, int scene_line, int range, int rangep05_sqr, int range_t3m1, int rangem1_sqr) { int x = get_global_id(0); int y = get_global_id(1); int top = -min(y, range); int bottom = min(scene_h - y - 1, range); int left = -min(x, range); int right = min(scene_w - x - 1, range); short tofloat[2]; float sum_y = 0.0f; int sum_cb = 0; int sum_cr = 0; int sum_a = 0; int offset = (x + left + (y + top) * scene_line) * 6; for (int yy = top; yy <= bottom; yy++) { int sqr = yy * yy + left * left; int offset2 = offset; for (int xx = left; xx <= right; xx++) { if (sqr < rangep05_sqr) { int cor_a; if (rangem1_sqr < sqr) { cor_a = ((rangep05_sqr - sqr) << 12) / range_t3m1; } else { cor_a = 4096; } tofloat[0] = *(global short*)&src[offset2]; tofloat[1] = *(global short*)&src[offset2 + 2]; sum_y += *(float*)tofloat * (float)cor_a; sum_cb += src[offset2 + 4] * cor_a; sum_cr += src[offset2 + 5] * cor_a; sum_a += cor_a; } sqr += 1 + xx * 2; offset2 += 6; } offset += scene_line * 6; } dst += (x + y * scene_line) * 6; *(float*)tofloat = sum_y / (float)sum_a; *(global short*)&dst[0] = tofloat[0]; *(global short*)&dst[2] = tofloat[1]; dst[4] = (char)(((sum_a >> 1) + sum_cb) / sum_a); dst[5] = (char)(((sum_a >> 1) + sum_cr) / sum_a); } )"); #pragma endregion template static void KernelSetArg(cl::Kernel& kernel, Head head) { kernel.setArg(i, head); } template static void KernelSetArg(cl::Kernel& kernel, Head head, Tail... tail) { kernel.setArg(i, head); KernelSetArg(kernel, tail...); } bool enabled = true; bool enabled_i; inline static const char key[] = "fast.cl"; public: cl::Platform platform; std::vector devices; cl::Context context; std::byte program_mem[sizeof(cl::Program)]; bool program_opt; cl::CommandQueue queue; HMODULE CLLib; enum class State { NotYet, OK, Failed } state; cl_t() :state(State::NotYet), CLLib(NULL) {} ~cl_t() { FreeLibrary(CLLib); if (program_opt) { auto program = reinterpret_cast(program_mem); program->~Program(); } } bool init() { enabled_i = enabled; if (!enabled_i)return true; if (![]() { __try { auto load_ret = __HrLoadAllImportsForDll("OpenCL.dll"); if (FAILED(load_ret)) { [load_ret]() { debug_log("OpenCL not available {}", "delay load failed {}"_fmt(load_ret)); }(); return false; } return true; } __except ([](int code) { if ( code == VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND) || code == VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND) ) { return EXCEPTION_EXECUTE_HANDLER; } return EXCEPTION_CONTINUE_SEARCH; } (GetExceptionCode())) { debug_log("OpenCL not available {}\n", "delay load exception"); return false; } }()) { state = State::Failed; return false; } switch (state) { case State::NotYet: try { cl::Platform::get(&platform); platform.getDevices(CL_DEVICE_TYPE_ALL, &devices); context = cl::Context(devices); new (&program_mem[0]) cl::Program(context, program_str.get(), false); program_opt = true; reinterpret_cast(program_mem)->build(); program_str.re_encrypt(); struct DeviceInfo { cl::Device device; cl_device_type device_type; //std::string version; constexpr bool operator<(const DeviceInfo& rhs) { //if (auto cmpver = version <=> rhs.version; cmpver != 0) return cmpver < 0; return this->device_type < rhs.device_type; } }; std::vector device_info; for (const auto& d : devices) { device_info.emplace_back( d, d.getInfo() ); } std::sort(device_info.rbegin(), device_info.rend()); auto device_itr = devices.begin(); for (const auto& di : device_info) { *device_itr = di.device; device_itr++; } queue = cl::CommandQueue(context, devices[0]); } catch (const cl::Error& err) { program_str.re_encrypt(); if (err.err() == CL_BUILD_PROGRAM_FAILURE) { try { if (program_opt) { auto program = reinterpret_cast(program_mem); if (auto status = program->getBuildInfo(devices[0]); status == CL_BUILD_ERROR) { debug_log( "OpenCL Error (CL_BUILD_PROGRAM_FAILURE : CL_BUILD_ERROR)\n{}", program->getBuildInfo(devices[0]).c_str() ); } else { debug_log("OpenCL Error (CL_BUILD_PROGRAM_FAILURE)\nstatus: {}", status); } program_opt = false; program->~Program(); state = State::Failed; return false; } } catch (const cl::Error& err) { debug_log("OpenCL Error\n({}) {}", err.err(), err.what()); state = State::Failed; return false; } } debug_log("OpenCL Error\n({}) {}", err.err(), err.what()); state = State::Failed; return false; } state = State::OK; [[fallthrough]]; case State::OK: return true; default: return false; } } template cl::Kernel readyKernel(std::string_view name, Args&&... args) { auto program = reinterpret_cast(program_mem); cl::Kernel kernel(*program, name.data()); KernelSetArg<0>(kernel, args...); return kernel; } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } cl; } // namespace patch::fast #endif ================================================ FILE: patch/patch_fast_create_figure.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_fast_create_figure.hpp" #ifdef PATCH_SWITCH_FAST_CREATE_FIGURE #include "debug_log.hpp" //#define PATCH_STOPWATCH #include "stopwatch.hpp" namespace patch::fast { static stopwatch_mem sw; void __cdecl CreateFigure_t::CreateFigure_circle(int thread_id, int thread_num, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { // 73d20 auto& figure = *reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::CreateFigure_var_ptr); int begin_thread = thread_id * (efpip->obj_h + 1 >> 1) / thread_num; int end_thread = (thread_id + 1) * (efpip->obj_h + 1 >> 1) / thread_num; int obj_half_w = efpip->obj_w + 1 >> 1; ExEdit::PixelYCA yca = { figure.color_y, figure.color_cb, figure.color_cr, 0 }; int inner = 0; int sizesq = figure.size * figure.size; int size_t8 = sizesq * 8 / efpip->obj_w * figure.size / efpip->obj_h; if (figure.line_width) { inner = figure.size - figure.line_width * 2 - 1; if (inner < 0) { inner = 0; } } int yy = begin_thread * 2 - efpip->obj_h + 1; if (inner) { int inner_t8 = (((figure.size * inner * 8) / efpip->obj_w) * figure.size) / efpip->obj_h; int innersq = inner * inner; for (int y = begin_thread; y < end_thread; y++) { int yysq = yy * figure.size / efpip->obj_h; yysq *= yysq; int innersq_myyaq = yysq + inner_t8 - innersq; ExEdit::PixelYCA* pixlt = (ExEdit::PixelYCA*)efpip->obj_edit + efpip->obj_line * y; ExEdit::PixelYCA* pixlb = (ExEdit::PixelYCA*)efpip->obj_edit + efpip->obj_line * (efpip->obj_h - 1 - y); ExEdit::PixelYCA* pixrt = pixlt + efpip->obj_w - 1; ExEdit::PixelYCA* pixrb = pixlb + efpip->obj_w - 1; int xx = 1 - efpip->obj_w; for (int x = 0; x < obj_half_w; x++) { int xxsq = xx * figure.size / efpip->obj_w; xxsq *= xxsq; int a = sizesq - yysq - xxsq; if (a <= 0) { a = 0; } else if (a < size_t8) { a = a * 0x1000 / size_t8; } else { a = 0x1000; } int a_inner = xxsq + innersq_myyaq; if (a_inner < 0) { a = 0; } else if (a_inner < inner_t8) { a = a * a_inner / inner_t8; } yca.a = (short)a; *pixlt = *pixrt = *pixlb = *pixrb = yca; pixlt++; pixrt--; pixlb++; pixrb--; xx += 2; } yy += 2; } } else { for (int y = begin_thread; y < end_thread; y++) { int yysq = yy * figure.size / efpip->obj_h; yysq *= yysq; ExEdit::PixelYCA* pixlt = (ExEdit::PixelYCA*)efpip->obj_edit + efpip->obj_line * y; ExEdit::PixelYCA* pixlb = (ExEdit::PixelYCA*)efpip->obj_edit + efpip->obj_line * (efpip->obj_h - 1 - y); ExEdit::PixelYCA* pixrt = pixlt + efpip->obj_w - 1; ExEdit::PixelYCA* pixrb = pixlb + efpip->obj_w - 1; int xx = 1 - efpip->obj_w; int x; for (x = 0; x < obj_half_w; x++) { int xxsq = xx * figure.size / efpip->obj_w; xxsq *= xxsq; int a = sizesq - yysq - xxsq; if (a <= 0) { a = 0; } else if (a < size_t8) { a = a * 0x1000 / size_t8; } else { break; } yca.a = (short)a; *pixlt = *pixrt = *pixlb = *pixrb = yca; pixlt++; pixrt--; pixlb++; pixrb--; xx += 2; } yca.a = 0x1000; for (; x < obj_half_w; x++) { *pixlt = *pixrt = *pixlb = *pixrb = yca; pixlt++; pixrt--; pixlb++; pixrb--; } yy += 2; } } } void __cdecl CreateFigure_t::CreateFigure_polygons(int thread_id, int thread_num, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { auto& figure = *reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::CreateFigure_var_ptr); int xp[10]; int xylen[10]; int yp[10]; int inner = 0; if (figure.type == 10) { double angle = 0.0; double sina0 = 0.0; double cosa0 = 1.0; for (int i = 0; i < 10; i += 2) { angle += 1.256637061435917; double sina1 = sin(angle); double cosa1 = cos(angle); double xx0 = sina1 * 65536.0; xp[i] = (int)xx0; double yy0 = cosa1 * 65536.0; yp[i] = (int)-yy0; double xx1 = sina0 * 65536.0; xp[i + 1] = (int)xx1; double yy1 = cosa0 * 65536.0; yp[i + 1] = (int)-yy1; xylen[i] = (int)((sina0 * xx0 + cosa0 * yy0) * (double)figure.size) + 0x20000; xylen[i + 1] = (int)((sina1 * xx1 + cosa1 * yy1) * (double)figure.size) + 0x20000; sina0 = sina1; cosa0 = cosa1; } if (figure.line_width) { inner = (int)((double)figure.line_width * 40642.48062015503876) + 0x20000; } } else { double angle_rate = 3.141592653589793 / (double)figure.type; double angle0 = 0.0; for (int i = 0; i < figure.type; i++) { double angle1 = angle_rate + angle0; double xx = sin(angle1) * 65536.0; xp[i] = (int)xx; double yy = cos(angle1) * 65536.0; yp[i] = (int)-yy; xylen[i] = (int)((sin(angle0) * xx + cos(angle0) * yy) * (double)figure.size) + 0x20000; angle0 = angle1 + angle_rate; } if (figure.line_width) { inner = (int)((double)(figure.line_width << 17) * cos(angle_rate)) + 0x20000; } } int thread_begin = thread_id * efpip->obj_h / thread_num; int thread_end = (thread_id + 1) * efpip->obj_h / thread_num; int obj_half_w = efpip->obj_w + 1 >> 1; int a; ExEdit::PixelYCA yca = { figure.color_y, figure.color_cb, figure.color_cr, 0 }; double angle_rate = (double)figure.type / 6.283185307179586; int yy = (thread_begin * 2 - efpip->obj_h) + 1; for (int y = thread_begin; y < thread_end; y++) { ExEdit::PixelYCA* pixl = (ExEdit::PixelYCA*)efpip->obj_edit + efpip->obj_line * y; ExEdit::PixelYCA* pixr = pixl + efpip->obj_w - 1; int xx = 1 - efpip->obj_w; for (int x = 0; x < obj_half_w; x++) { int pt = (int)((atan2((double)-xx, (double)yy) + 3.141592653589793) * angle_rate) % figure.type; int dist = xylen[pt] - xp[pt] * xx - yp[pt] * yy; if (0x40000 <= dist) { a = 0x1000; } else if (dist <= 0) { a = 0; } else { a = dist >> 6; } if (inner) { int subinner = dist - inner; if (0 < subinner) { if (subinner < 0x40000) { a = a * (0x40000 - subinner) >> 18; } else { a = 0; } } } yca.a = (short)a; *pixl = *pixr = yca; pixl++; pixr--; xx += 2; } yy += 2; } } } // namespace patch::fast #endif // ifdef PATCH_SWITCH_FAST_CREATE_FIGURE ================================================ FILE: patch/patch_fast_create_figure.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FAST_CREATE_FIGURE #include #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "global.hpp" #include "config_rw.hpp" namespace patch::fast { // init at exedit load // <図形、部分フィルタ、マスク、ディスプレイスメントマップ>の図形(円、三角、五角、六角、星)の計算を効率化し少しだけ速度アップ inline class CreateFigure_t { static void __cdecl CreateFigure_circle(int thread_id, int thread_num, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); static void __cdecl CreateFigure_polygons(int thread_id, int thread_num, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); bool enabled = true; bool enabled_i; inline static const char key[] = "fast.create_figure"; public: struct CreateFigure_var { // 1e4798 int type; int _padding1; char _module_path[260]; int type_num; short color_cb; // 1e48a8 short _padding2; int line_width; short color_cr; short _padding3; HMENU popup; short color_y; short _padding4; int size; }; void init() { enabled_i = enabled; if (!enabled_i)return; ReplaceNearJmp(GLOBAL::exedit_base + OFS::ExEdit::CreateFigure_circle_func_call, &CreateFigure_circle); { OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::CreateFigure_circle_func_mt_call, 4); h.store_i32(0, &CreateFigure_circle); } ReplaceNearJmp(GLOBAL::exedit_base + OFS::ExEdit::CreateFigure_polygons_func_call, &CreateFigure_polygons); { OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::CreateFigure_polygons_func_mt_call, 4); h.store_i32(0, &CreateFigure_polygons); } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } create_figure; } // namespace patch::fast #endif // ifdef PATCH_SWITCH_FAST_CREATE_FIGURE ================================================ FILE: patch/patch_fast_directionalblur.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_fast_directionalblur.hpp" #ifdef PATCH_SWITCH_FAST_DIRECTIONALBLUR #include "debug_log.hpp" #include "patch_fast_cl.hpp" //#define PATCH_STOPWATCH #include "stopwatch.hpp" namespace patch::fast { static stopwatch_mem sw; BOOL __cdecl DirectionalBlur_t::func_proc(ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { efDirectionalBlur_var& dblur = *(efDirectionalBlur_var*)uintptr_t(reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efDirectionalBlur_var_ptr)); int range = efp->track[0]; if (range == 0) { return TRUE; } double rad = efp->track[1] * 0.00174532925199433; int x_step = (int)(sin(rad) * -65536.0); // PI / 1800 int y_step = (int)(cos(rad) * 65536.0); int temp_range = range * std::abs(x_step) >> 16; dblur.x_begin = -temp_range; dblur.x_end = efpip->obj_w + temp_range; temp_range = range * std::abs(y_step) >> 16; dblur.y_begin = -temp_range; dblur.y_end = efpip->obj_h + temp_range; if (range < 16) { x_step = (int)(x_step + (x_step >> 0x1f & 3)) >> 2; y_step = (int)(y_step + (y_step >> 0x1f & 3)) >> 2; range <<= 2; } else if (range < 32) { x_step >>= 1; y_step >>= 1; range <<= 1; } else if (128 < range) { x_step *= range; y_step *= range; x_step = (int)(x_step + (x_step >> 0x1f & 0x7f)) >> 7; y_step = (int)(y_step + (y_step >> 0x1f & 0x7f)) >> 7; range = 128; } if (has_flag(efpip->flag, ExEdit::FilterProcInfo::Flag::fast_preview) && 50 < range) { dblur.range = 50; dblur.x_step = (x_step * range) / 50; dblur.y_step = (y_step * range) / 50; } else { dblur.range = range; dblur.x_step = x_step; dblur.y_step = y_step; } if (efp->check[0] == 0) { int oversize = dblur.x_end - dblur.x_begin - efpip->obj_line; if (0 < oversize) { oversize++; oversize >>= 1; dblur.x_begin += oversize; dblur.x_end -= oversize; } oversize = dblur.y_end - dblur.y_begin - efpip->obj_max_h; if (0 < oversize) { oversize++; oversize >>= 1; dblur.y_begin += oversize; dblur.y_end -= oversize; } try { const auto src_size = efpip->obj_line * efpip->obj_h * sizeof(ExEdit::PixelYCA); cl::Buffer clmem_src(cl.context, CL_MEM_READ_ONLY, src_size); cl.queue.enqueueWriteBuffer(clmem_src, CL_TRUE, 0, src_size, efpip->obj_edit); const auto dst_size = efpip->obj_line * (dblur.y_end - dblur.y_begin) * sizeof(ExEdit::PixelYCA); cl::Buffer clmem_dst(cl.context, CL_MEM_WRITE_ONLY, dst_size); cl::Kernel kernel; kernel = cl.readyKernel( "DirectionalBlur_Media", clmem_dst, clmem_src, efpip->obj_w, efpip->obj_h, efpip->obj_line, dblur.x_begin, dblur.x_end, dblur.x_step, dblur.y_begin, dblur.y_end, dblur.y_step, dblur.range ); cl.queue.enqueueNDRangeKernel(kernel, { 0,0 }, { (size_t)(dblur.x_end - dblur.x_begin), (size_t)(dblur.y_end - dblur.y_begin) }); cl.queue.enqueueReadBuffer(clmem_dst, CL_TRUE, 0, dst_size, efpip->obj_temp); } catch (const cl::Error& err) { debug_log("OpenCL Error\n({}) {}", err.err(), err.what()); efp->aviutl_exfunc->exec_multi_thread_func(reinterpret_cast(GLOBAL::exedit_base + 0xc4a0), efp, efpip); return TRUE; } efpip->obj_data.cx += (efpip->obj_w - dblur.x_end - dblur.x_begin) * 0x800; efpip->obj_data.cy += (efpip->obj_h - dblur.y_end - dblur.y_begin) * 0x800; efpip->obj_w = dblur.x_end - dblur.x_begin; efpip->obj_h = dblur.y_end - dblur.y_begin; } else { // サイズ固定 dblur.x_begin = 0; dblur.y_begin = 0; dblur.x_end = efpip->obj_w; dblur.y_end = efpip->obj_h; try { const auto src_size = efpip->obj_line * efpip->obj_h * sizeof(ExEdit::PixelYCA); cl::Buffer clmem_src(cl.context, CL_MEM_READ_ONLY, src_size); cl.queue.enqueueWriteBuffer(clmem_src, CL_TRUE, 0, src_size, efpip->obj_edit); cl::Buffer clmem_dst(cl.context, CL_MEM_WRITE_ONLY, src_size); cl::Kernel kernel; kernel = cl.readyKernel( "DirectionalBlur_original_size", clmem_dst, clmem_src, efpip->obj_w, efpip->obj_h, efpip->obj_line, dblur.x_step, dblur.y_step, dblur.range ); cl.queue.enqueueNDRangeKernel(kernel, { 0,0 }, { (size_t)efpip->obj_w, (size_t)efpip->obj_h }); cl.queue.enqueueReadBuffer(clmem_dst, CL_TRUE, 0, src_size, efpip->obj_temp); } catch (const cl::Error& err) { debug_log("OpenCL Error\n({}) {}", err.err(), err.what()); efp->aviutl_exfunc->exec_multi_thread_func(reinterpret_cast(GLOBAL::exedit_base + 0xc720), efp, efpip); return TRUE; } } std::swap(efpip->obj_temp, efpip->obj_edit); return TRUE; } void __cdecl DirectionalBlur_t::filter_mt_wrap00cae8(AviUtl::MultiThreadFunc func, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { efDirectionalBlur_var& dblur = *(efDirectionalBlur_var*)uintptr_t(reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efDirectionalBlur_var_ptr)); try { const auto src_size = efpip->scene_line * efpip->scene_h * sizeof(ExEdit::PixelYC); cl::Buffer clmem_src(cl.context, CL_MEM_READ_ONLY, src_size); cl.queue.enqueueWriteBuffer(clmem_src, CL_TRUE, 0, src_size, efpip->frame_edit); cl::Buffer clmem_dst(cl.context, CL_MEM_WRITE_ONLY, src_size); cl::Kernel kernel; kernel = cl.readyKernel( "DirectionalBlur_Filter", clmem_dst, clmem_src, efpip->scene_w, efpip->scene_h, efpip->scene_line, dblur.x_step, dblur.y_step, dblur.range ); cl.queue.enqueueNDRangeKernel(kernel, { 0,0 }, { (size_t)efpip->scene_w, (size_t)efpip->scene_h }); cl.queue.enqueueReadBuffer(clmem_dst, CL_TRUE, 0, src_size, efpip->frame_temp); } catch (const cl::Error& err) { debug_log("OpenCL Error\n({}) {}", err.err(), err.what()); efp->aviutl_exfunc->exec_multi_thread_func(func, efp, efpip); } } } // namespace patch::fast #endif // ifdef PATCH_SWITCH_FAST_DIRECTIONALBLUR ================================================ FILE: patch/patch_fast_directionalblur.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FAST_DIRECTIONALBLUR #include #include "util_magic.hpp" #include "offset_address.hpp" #include "global.hpp" #include "config_rw.hpp" namespace patch::fast { // init at exedit load // 方向ブラーの高速化 inline class DirectionalBlur_t { static BOOL func_proc(ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); static void __cdecl filter_mt_wrap00cae8(AviUtl::MultiThreadFunc func, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); bool enabled = true; bool enabled_i; inline static const char key[] = "fast.directionalblur"; public: struct efDirectionalBlur_var { // d75cc int x_step; int y_step; int x_end; int y_end; int x_begin; int range; int y_begin; }; void init() { enabled_i = enabled; if (!enabled_i)return; store_i32(GLOBAL::exedit_base + OFS::ExEdit::efDirectionalBlur_func_proc_ptr, &func_proc); OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::efDirectionalBlur_Filter_mt_func_call, 6); h.store_i16(0, '\x90\xe8'); // nop; call (rel32) h.replaceNearJmp(2, &filter_mt_wrap00cae8); } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } DirectionalBlur; } // namespace patch::fast #endif // ifdef PATCH_SWITCH_FAST_DIRECTIONALBLUR ================================================ FILE: patch/patch_fast_displacementmap.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "patch_fast_displacementmap.hpp" #ifdef PATCH_SWITCH_FAST_DISPLACEMENTMAP #include #include "global.hpp" #include "offset_address.hpp" #include "util_int.hpp" #include "patch_fast_cl.hpp" #include "debug_log.hpp" //#define PATCH_STOPWATCH #include "stopwatch.hpp" static stopwatch_mem sw; namespace patch::fast { BOOL DisplacementMap_t::mt_func(AviUtl::MultiThreadFunc original_func_ptr, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { if constexpr (true) { if (256 < efpip->obj_w * efpip->obj_h) { sw.start(); try { efDisplacementMap_var& dmap = *reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efDisplacementMap_var_ptr); auto& ExEditMemory = *(void**)(GLOBAL::exedit_base + OFS::ExEdit::memory_ptr); const auto buf_size = efpip->obj_line * efpip->obj_h * sizeof(ExEdit::PixelYCA); cl::Buffer clmem_src1(cl.context, CL_MEM_READ_ONLY, buf_size); cl.queue.enqueueWriteBuffer(clmem_src1, CL_TRUE, 0, buf_size, efpip->obj_edit); cl::Buffer clmem_src2(cl.context, CL_MEM_READ_ONLY, buf_size); cl.queue.enqueueWriteBuffer(clmem_src2, CL_TRUE, 0, buf_size, ExEditMemory); cl::Buffer clmem_dst(cl.context, CL_MEM_WRITE_ONLY, buf_size); int calc_id = ((ExEdit::Exdata::efDisplacementMap*)efp->exdata_ptr)->calc; if (calc_id < 0 && 2 < calc_id) { calc_id = 0; } auto kernel = cl.readyKernel( cl_func_name[calc_id], clmem_dst, clmem_src1, clmem_src2, efpip->obj_w, efpip->obj_h, efpip->obj_line, dmap.param0, dmap.param1, dmap.ox, dmap.oy ); cl.queue.enqueueNDRangeKernel(kernel, { 0,0 }, { (size_t)efpip->obj_w ,(size_t)efpip->obj_h }); cl.queue.enqueueReadBuffer(clmem_dst, CL_TRUE, 0, buf_size, efpip->obj_temp); } catch (const cl::Error& err) { debug_log("OpenCL Error\n({}) {}", err.err(), err.what()); return efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); } sw.stop(); return TRUE; } else { return efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); } } else { sw.start(); const auto ret = efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); sw.stop(); return ret; } } } #endif // ifdef PATCH_SWITCH_FAST_DISPLACEMENTMAP ================================================ FILE: patch/patch_fast_displacementmap.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FAST_DISPLACEMENTMAP #include #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "global.hpp" #include "config_rw.hpp" namespace patch::fast { // init at exedit load // ディスプレイスメントマップの高速化 inline class DisplacementMap_t { static BOOL mt_func(AviUtl::MultiThreadFunc original_func_ptr, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); inline static const char* cl_func_name[3] = { "DisplacementMap_move","DisplacementMap_zoom","DisplacementMap_rot" }; bool enabled = true; bool enabled_i; inline static const char key[] = "fast.displacementmap"; public: struct efDisplacementMap_var { // 11effc int ox; // 11effc int oy; // 11f000 void** mode_func; // 11f004 int param1; // 11f008 int param0; // 11f00c }; void init() { enabled_i = enabled; if (!enabled_i)return; OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::efDisplacementMap_mt_func_call, 6); h.store_i16(0, '\x90\xe8'); // nop; call (rel32) h.replaceNearJmp(2, &mt_func); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } DisplacementMap; } // namespace patch::fast #endif // ifdef PATCH_SWITCH_FAST_DISPLACEMENTMAP ================================================ FILE: patch/patch_fast_exeditwindow.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_fast_exeditwindow.hpp" #ifdef PATCH_SWITCH_FAST_EXEDITWINDOW #pragma comment(lib, "Msimg32.lib") #include "util_others.hpp" //#define PATCH_STOPWATCH #include "stopwatch.hpp" namespace patch { static stopwatch_mem sw; void __cdecl fast_exeditwindow_t::FUN_10036a70_Wrap_gradation(HDC hDC, LPRECT prect, int r1, int g1, int b1, int r2, int g2, int b2, int gradation_left, int gradation_right) { static GRADIENT_RECT gr[] = { { .UpperLeft = 0, .LowerRight = 1 } }; TRIVERTEX tv[2]; tv[0].y = prect->top; tv[1].y = prect->bottom; tv[0].Alpha = 0; tv[1].Alpha = 0; int64_t real_diff = static_cast(gradation_right) - gradation_left; if (prect->left < gradation_left) { if (prect->right < gradation_left) { SetDCBrushColor(hDC, RGB(r1, g1, b1)); FillRect(hDC, prect, (HBRUSH)GetStockObject(DC_BRUSH)); return; } SetDCBrushColor(hDC, RGB(r1, g1, b1)); RECT rect{ prect->left, prect->top, gradation_left, prect->bottom }; FillRect(hDC, prect, (HBRUSH)GetStockObject(DC_BRUSH)); const auto cr1 = r1 << 8, cg1 = g1 << 8, cb1 = b1 << 8; const auto cr2 = r2 << 8, cg2 = g2 << 8, cb2 = b2 << 8; tv[0].x = gradation_left; tv[0].Red = static_cast(cr1); tv[0].Green = static_cast(cg1); tv[0].Blue = static_cast(cb1); if (gradation_right < prect->right) { SetDCBrushColor(hDC, RGB(r2, g2, b2)); RECT rect{ gradation_right, prect->top, prect->right, prect->bottom }; FillRect(hDC, &rect, (HBRUSH)GetStockObject(DC_BRUSH)); tv[1].x = gradation_right; tv[1].Red = static_cast(cr2); tv[1].Green = static_cast(cg2); tv[1].Blue = static_cast(cb2); } else { tv[1].x = prect->right; if (real_diff == 0) { tv[1].Red = static_cast(cr2); tv[1].Green = static_cast(cg2); tv[1].Blue = static_cast(cb2); } else { tv[1].Red = static_cast(cr1 + static_cast(cr2 - cr1) * (static_cast(prect->right) - gradation_left) / real_diff); tv[1].Green = static_cast(cg1 + static_cast(cg2 - cg1) * (static_cast(prect->right) - gradation_left) / real_diff); tv[1].Blue = static_cast(cb1 + static_cast(cb2 - cb1) * (static_cast(prect->right) - gradation_left) / real_diff); } } GradientFill(hDC, tv, std::size(tv), &gr, std::size(gr), GRADIENT_FILL_RECT_H); } else { if (gradation_right < prect->left) { SetDCBrushColor(hDC, RGB(r2, g2, b2)); FillRect(hDC, prect, (HBRUSH)GetStockObject(DC_BRUSH)); return; } const auto cr1 = r1 << 8, cg1 = g1 << 8, cb1 = b1 << 8; const auto cr2 = r2 << 8, cg2 = g2 << 8, cb2 = b2 << 8; tv[0].x = prect->left; if (real_diff == 0) { tv[0].Red = cr1; tv[0].Green = cg1; tv[0].Blue = cb1; } else { tv[0].Red = static_cast(cr1 + static_cast(cr2 - cr1) * (static_cast(prect->left) - gradation_left) / real_diff); tv[0].Green = static_cast(cg1 + static_cast(cg2 - cg1) * (static_cast(prect->left) - gradation_left) / real_diff); tv[0].Blue = static_cast(cb1 + static_cast(cb2 - cb1) * (static_cast(prect->left) - gradation_left) / real_diff); } if (gradation_right < prect->right) { SetDCBrushColor(hDC, RGB(r2, g2, b2)); RECT rect{ gradation_right, prect->top, prect->right, prect->bottom }; FillRect(hDC, &rect, (HBRUSH)GetStockObject(DC_BRUSH)); tv[1].x = gradation_right; tv[1].Red = static_cast(cr2); tv[1].Green = static_cast(cg2); tv[1].Blue = static_cast(cb2); } else { tv[1].x = prect->right; if (real_diff == 0) { tv[1].Red = static_cast(cr2); tv[1].Green = static_cast(cg2); tv[1].Blue = static_cast(cb2); } else { tv[1].Red = static_cast(cr1 + static_cast(cr2 - cr1) * (static_cast(prect->right) - gradation_left) / real_diff); tv[1].Green = static_cast(cg1 + static_cast(cg2 - cg1) * (static_cast(prect->right) - gradation_left) / real_diff); tv[1].Blue = static_cast(cb1 + static_cast(cb2 - cb1) * (static_cast(prect->right) - gradation_left) / real_diff); } } GradientFill(hDC, tv, std::size(tv), &gr, std::size(gr), GRADIENT_FILL_RECT_H); } } void __cdecl fast_exeditwindow_t::FUN_10036a70_Wrap_step(HDC hDC, LPRECT prect, int r1, int g1, int b1, int r2, int g2, int b2, int gradation_left, int gradation_right) { auto steps = patch::fast_exeditwindow.step; auto brush = (HBRUSH)GetStockObject(DC_BRUSH); if (steps == 1) { SetDCBrushColor(hDC, RGB(r1, g1, b1)); FillRect(hDC, prect, brush); return; } auto real_diff = gradation_right - gradation_left; if (prect->left < gradation_left) { if (prect->right < gradation_left) { SetDCBrushColor(hDC, RGB(r1, g1, b1)); FillRect(hDC, prect, brush); return; } SetDCBrushColor(hDC, RGB(r1, g1, b1)); RECT rect{ prect->left, prect->top, gradation_left, prect->bottom }; FillRect(hDC, prect, brush); if (gradation_right < prect->right) { SetDCBrushColor(hDC, RGB(r2, g2, b2)); RECT rect{ gradation_right, prect->top, prect->right, prect->bottom }; FillRect(hDC, &rect, brush); } } else { if (gradation_right < prect->left) { SetDCBrushColor(hDC, RGB(r2, g2, b2)); FillRect(hDC, prect, brush); return; } if (gradation_right < prect->right) { SetDCBrushColor(hDC, RGB(r2, g2, b2)); RECT rect{ gradation_right, prect->top, prect->right, prect->bottom }; FillRect(hDC, &rect, brush); } } LONG L, R; R = gradation_left; RECT rect; rect.top = prect->top; rect.bottom = prect->bottom; for (int i = 0; i < steps; i++) { L = R; R = static_cast(gradation_left + static_cast(gradation_right - gradation_left) * (i + 1) / steps); if (R < prect->left) continue; if (prect->right < L) continue; int dL = std::max<>(prect->left, L); int dR = std::min<>(prect->right, R); SetDCBrushColor(hDC, RGB( r1 + (r2 - r1) * i / (steps - 1), g1 + (g2 - g1) * i / (steps - 1), b1 + (b2 - b1) * i / (steps - 1) )); rect.left = dL; rect.right = dR; FillRect(hDC, &rect, brush); } } static HDC frontdc; static HBITMAP bitmap; static HBITMAP bitmap_old; static int width, height; #define DO 1 HDC WINAPI fast_exeditwindow_t::GetDC_Wrap(HWND hwnd) { sw.start(); #if DO frontdc = GetDC(hwnd); RECT rect; GetClientRect(hwnd, &rect); width = rect.right - rect.left; height = rect.bottom - rect.top; auto backdc = CreateCompatibleDC(frontdc); bitmap = CreateCompatibleBitmap(frontdc, width, height); bitmap_old = (HBITMAP)SelectObject(backdc, bitmap); BitBlt(backdc, 0, 0, width, height, frontdc, 0, 0, SRCCOPY); return backdc; #else return GetDC(hwnd); #endif } int WINAPI fast_exeditwindow_t::ReleaseDC_Wrap(HWND hwnd, HDC hdc) { #if DO BitBlt(frontdc, 0, 0, width, height, hdc, 0, 0, SRCCOPY); SelectObject(hdc, bitmap_old); DeleteObject(bitmap); DeleteObject(hdc); #endif sw.stop(); return ReleaseDC(hwnd, frontdc); } } // namespace patch #endif // ifdef PATCH_SWITCH_FAST_EXEDITWINDOW ================================================ FILE: patch/patch_fast_exeditwindow.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FAST_EXEDITWINDOW #include #include "util_magic.hpp" #include "global.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // 拡張編集ウィンドウの高速化 inline class fast_exeditwindow_t { static void __cdecl FUN_10036a70_Wrap_gradation(HDC hDC, LPRECT prect, int r1, int g1, int b1, int r2, int g2, int b2, int real_left, int real_right); static void __cdecl FUN_10036a70_Wrap_step(HDC hDC, LPRECT prect, int r1, int g1, int b1, int r2, int g2, int b2, int real_left, int real_right); static HDC WINAPI GetDC_Wrap(HWND hwnd); static int WINAPI ReleaseDC_Wrap(HWND hwnd, HDC hdc); inline static auto GetDC_Wrap_ptr = &GetDC_Wrap; inline static auto ReleaseDC_Wrap_ptr = &ReleaseDC_Wrap; bool enabled = true; bool enabled_i; int step = 0; int step_i; inline static const char key[] = "fast.exeditwindow"; inline static const char c_step_name[] = "step"; public: void init() { enabled_i = enabled; step_i = step; if (!enabled_i)return; if (step >= 0) { decltype(&FUN_10036a70_Wrap_gradation) f_036a70_ptr; if (step == 0) { f_036a70_ptr = &FUN_10036a70_Wrap_gradation; } else { f_036a70_ptr = &FUN_10036a70_Wrap_step; } ReplaceNearJmp(GLOBAL::exedit_base + 0x0374fb, f_036a70_ptr); ReplaceNearJmp(GLOBAL::exedit_base + 0x037563, f_036a70_ptr); ReplaceNearJmp(GLOBAL::exedit_base + 0x0375bb, f_036a70_ptr); } OverWriteOnProtectHelper(GLOBAL::exedit_base + 0x0387fd, 4).store_i32(0, &GetDC_Wrap_ptr); OverWriteOnProtectHelper(GLOBAL::exedit_base + 0x038927, 4).store_i32(0, &ReleaseDC_Wrap_ptr); OverWriteOnProtectHelper(GLOBAL::exedit_base + 0x039309, 4).store_i32(0, &GetDC_Wrap_ptr); OverWriteOnProtectHelper(GLOBAL::exedit_base + 0x039350, 4).store_i32(0, &ReleaseDC_Wrap_ptr); OverWriteOnProtectHelper(GLOBAL::exedit_base + 0x0392a8, 4).store_i32(0, &GetDC_Wrap_ptr); OverWriteOnProtectHelper(GLOBAL::exedit_base + 0x0392e1, 4).store_i32(0, &ReleaseDC_Wrap_ptr); OverWriteOnProtectHelper(GLOBAL::exedit_base + 0x039379, 4).store_i32(0, &GetDC_Wrap_ptr); OverWriteOnProtectHelper(GLOBAL::exedit_base + 0x0393f0, 4).store_i32(0, &ReleaseDC_Wrap_ptr); OverWriteOnProtectHelper(GLOBAL::exedit_base + 0x0394d6, 4).store_i32(0, &GetDC_Wrap_ptr); OverWriteOnProtectHelper(GLOBAL::exedit_base + 0x03953c, 4).store_i32(0, &ReleaseDC_Wrap_ptr); //OverWriteOnProtectHelper(GLOBAL::exedit_base + 0x03943c, 4).store_i32(0, &GetDC_Wrap_ptr); //OverWriteOnProtectHelper(GLOBAL::exedit_base + 0x039483, 4).store_i32(0, &ReleaseDC_Wrap_ptr); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void set_step(int x) { step = x; } int get_step() { return step; } int get_step_i() { return step_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } void config_load(ConfigReader& cr) { cr.regist(c_step_name, [this](json_value_s* value) { ConfigReader::load_variable(value, step); }); } void config_store(ConfigWriter& cw) { cw.append(c_step_name, step); } } fast_exeditwindow; } // namespace patch #endif // ifdef PATCH_SWITCH_FAST_EXEDITWINDOW ================================================ FILE: patch/patch_fast_flash.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_fast_flash.hpp" #ifdef PATCH_SWITCH_FAST_FLASH #include "debug_log.hpp" #include "patch_fast_cl.hpp" //#define PATCH_STOPWATCH #include "stopwatch.hpp" namespace patch::fast { static stopwatch_mem sw; BOOL Flash_t::func_proc(ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { if constexpr (true) { sw.start(); auto exedit_max_w = load_i32(GLOBAL::exedit_base + OFS::ExEdit::exedit_max_w); auto exedit_max_h = load_i32(GLOBAL::exedit_base + OFS::ExEdit::exedit_max_h); auto exedit_buffer_line = load_i32(GLOBAL::exedit_base + OFS::ExEdit::exedit_buffer_line); efFlash_var& flash = *(efFlash_var*)uintptr_t(reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efFlash_var_ptr)); int intensity = efp->track[0]; int cx = efp->track[1]; int cy = efp->track[2]; flash.range = 750; unsigned int* exdata = (unsigned int*)efp->exdata_ptr; int pixel_range, temp_range; if (intensity == 0) { return TRUE; } flash.corrected_intensity = (intensity * 4096) / 1000; flash.r_intensity = 4096 - flash.corrected_intensity; if (flash.r_intensity < 0) { flash.r_intensity = 0; } flash.cx = cx + efpip->obj_w / 2; flash.cy = cy + efpip->obj_h / 2; pixel_range = (std::max)({ std::abs(flash.cx), std::abs(flash.cy), std::abs(flash.cx - efpip->obj_w), std::abs(flash.cy - efpip->obj_h) }); temp_range = (int)round(sqrt(efpip->obj_h * efpip->obj_h + efpip->obj_w * efpip->obj_w)); if (temp_range < pixel_range) { pixel_range = temp_range; } if (has_flag(efpip->flag, ExEdit::FilterProcInfo::Flag::fast_preview)) if (50 < pixel_range) pixel_range = 50; flash.pixel_range = pixel_range / 4 + pixel_range / 2; if (efp->check[2]) { // サイズ固定 flash.temp_x = 0; flash.temp_y = 0; flash.temp_w = efpip->obj_w; flash.temp_h = efpip->obj_h; } else { int tx, ty, tw, th; if (flash.cx < 0) { tx = 0; } else { tx = -3 * flash.cx; } if (flash.cy < 0) { ty = 0; } else { ty = -3 * flash.cy; } if (efpip->obj_w < flash.cx) { tw = 0; } else { tw = 3 * (efpip->obj_w - flash.cx); } if (efpip->obj_h < flash.cy) { th = 0; } else { th = 3 * (efpip->obj_h - flash.cy); } tx = tx * flash.corrected_intensity / 4096; ty = ty * flash.corrected_intensity / 4096; tw = (tw * flash.corrected_intensity / 4096) + efpip->obj_w; th = (th * flash.corrected_intensity / 4096) + efpip->obj_h; int tmin = (std::min)({ exedit_max_w, efpip->scene_w + efpip->obj_w * 2 }); int sub1 = tw - tx - tmin; if (0 < sub1) { int sub2 = efpip->obj_w - tx - tw; if (0 < sub2) { if (sub2 < sub1) { tx += sub2; sub1 -= sub2; } else { tx += sub1; sub1 = 0; } } else { if (-sub2 < sub1) { tw += sub2; sub1 += sub2; } else { tw -= sub1; sub1 = 0; } } if (sub1 & 1) { tw--; sub1--; } if (0 < sub1) { tx += sub1 / 2; tw -= sub1 / 2; } } tmin = (std::min)({ exedit_max_h, efpip->scene_h + efpip->obj_h * 2 }); sub1 = th - ty - tmin; if (0 < sub1) { int sub2 = efpip->obj_h - ty - th; if (0 < sub2) { if (sub2 < sub1) { ty += sub2; sub1 -= sub2; } else { ty += sub1; sub1 = 0; } } else { if (-sub2 < sub1) { th += sub2; sub1 += sub2; } else { th -= sub1; sub1 = 0; } } if (sub1 & 1) { th--; sub1--; } if (0 < sub1) { ty += sub1 / 2; th -= sub1 / 2; } } flash.temp_x = tx; flash.temp_y = ty; flash.temp_w = tw; flash.temp_h = th; } const auto dst_w = flash.temp_w - flash.temp_x; const auto dst_h = flash.temp_h - flash.temp_y; reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::rgb2yc)(&flash.color_y, &flash.color_cb, &flash.color_cr, exdata[0] & 0xffffff); try { const auto src_size = exedit_buffer_line * efpip->obj_h * sizeof(ExEdit::PixelYCA); cl::Buffer clmem_src(cl.context, CL_MEM_READ_ONLY, src_size); cl.queue.enqueueWriteBuffer(clmem_src, CL_TRUE, 0, src_size, efpip->obj_edit); const auto dst_size = exedit_buffer_line * dst_h * sizeof(ExEdit::PixelYCA); cl::Buffer clmem_dst(cl.context, CL_MEM_WRITE_ONLY, dst_size); cl::Kernel kernel; if (exdata[0] & 0x1000000) { // 指定なし(元画像の色) kernel = cl.readyKernel( "Flash", clmem_dst, clmem_src, efpip->obj_w, efpip->obj_h, exedit_buffer_line, flash.cx, flash.cy, flash.range, flash.pixel_range, flash.temp_x, flash.temp_y, flash.r_intensity ); } else { kernel = cl.readyKernel( "FlashColor", clmem_dst, clmem_src, efpip->obj_w, efpip->obj_h, exedit_buffer_line, flash.cx, flash.cy, flash.range, flash.pixel_range, flash.temp_x, flash.temp_y, flash.r_intensity, flash.color_y, flash.color_cb, flash.color_cr ); } cl.queue.enqueueNDRangeKernel(kernel, { 0,0 }, { (size_t)dst_w, (size_t)dst_h }); cl.queue.enqueueReadBuffer(clmem_dst, CL_TRUE, 0, dst_size, efpip->obj_temp); } catch (const cl::Error& err) { debug_log("OpenCL Error\n({}) {}", err.err(), err.what()); return FALSE; } switch (exdata[1]) { //合成モード case 0: // 前方に合成 efp->exfunc->bufcpy(efpip->obj_temp, -flash.temp_x, -flash.temp_y, efpip->obj_edit, 0, 0, efpip->obj_w, efpip->obj_h, 0, 0x11000003); break; case 1: // 後方に合成 efp->exfunc->bufcpy(efpip->obj_temp, -flash.temp_x, -flash.temp_y, efpip->obj_edit, 0, 0, efpip->obj_w, efpip->obj_h, 0, 3); break; // case 2: // 光成分のみ } std::swap(efpip->obj_temp, efpip->obj_edit); efpip->obj_data.cx += (efpip->obj_w - flash.temp_w - flash.temp_x) * 2048; efpip->obj_data.cy += (efpip->obj_h - flash.temp_h - flash.temp_y) * 2048; efpip->obj_w = flash.temp_w - flash.temp_x; efpip->obj_h = flash.temp_h - flash.temp_y; sw.stop(); return TRUE; } else { sw.start(); const auto ret = ((BOOL(*)(ExEdit::Filter*, ExEdit::FilterProcInfo*))(GLOBAL::exedit_base + OFS::ExEdit::efRadiationalBlur_func_proc))(efp, efpip); sw.stop(); return ret; } } } // namespace patch::fast #endif // ifdef PATCH_SWITCH_FAST_FLASH ================================================ FILE: patch/patch_fast_flash.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FAST_FLASH #include #include "util_magic.hpp" #include "offset_address.hpp" #include "global.hpp" #include "config_rw.hpp" namespace patch::fast { // init at exedit load // 閃光の高速化 inline class Flash_t { static BOOL func_proc(ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); bool enabled = true; bool enabled_i; inline static const char key[] = "fast.flash"; public: struct efFlash_var { // 1a6b7c int r_intensity; int cx; int cy; int temp_w; int temp_h; short color_cb; short _padding1; int corrected_intensity; int pixel_range; short color_cr; short _padding2; int temp_x; int range; int temp_y; short color_y; }; void init() { enabled_i = enabled; if (!enabled_i)return; store_i32(GLOBAL::exedit_base + OFS::ExEdit::efFlash_func_proc_ptr, &func_proc); } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } Flash; } // namespace patch::fast #endif // ifdef PATCH_SWITCH_FAST_FLASH ================================================ FILE: patch/patch_fast_getputpixeldata.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_fast_getputpixeldata.hpp" #ifdef PATCH_SWITCH_FAST_GETPUTPIXELDATA #include #include #include "multi_threading.hpp" namespace patch::fast { static BOOL BufCpyBGRA2YCA(void* dst, void* src, int w, int h, int line) { } static BOOL BufCpyYCA2BGRA(void* dst, void* src, int w, int h, int line) { } int getputpixeldata_t::avx_getpixeldata(lua_State* L) { auto n = lua_gettop(L); bool is_alloc = false; bool is_work = false; for (int i = 0; i < n; i++) { auto s = lua_tostring(L, i + 1); if (lstrcmpiA(s, "alloc") == 0)is_alloc = true; if (lstrcmpiA(s, "work") == 0)is_work = true; } auto efpip_g = load_i32(GLOBAL::exedit_base + OFS::ExEdit::efpip_g); if (is_work) { if (is_alloc) { lua_newuserdata(L, efpip_g->obj_w * efpip_g->obj_h * 4 + 16); } else { lua_pushlightuserdata(L, reinterpret_cast(efpip_g->obj_temp) + load_i32(GLOBAL::exedit_base + OFS::ExEdit::exedit_max_h_add8) * load_i32(GLOBAL::exedit_base + OFS::ExEdit::exedit_buffer_line) * 4); } } else { ExEdit::PixelBGRA* ptr; if (is_alloc) { ptr = static_cast(lua_newuserdata(L, efpip_g->obj_w * efpip_g->obj_h * 4 + 16)); } else { ptr = static_cast(static_cast(efpip_g->obj_temp)) + load_i32(GLOBAL::exedit_base + OFS::ExEdit::exedit_max_h_add8) * load_i32(GLOBAL::exedit_base + OFS::ExEdit::exedit_buffer_line); lua_pushlightuserdata(L, ptr); } constexpr static __m256i y_c = { .m256i_i16 = { 16320, 16320, 16320, 0, 16320, 16320, 16320, 0, 16320, 16320, 16320, 0, 16320, 16320, 16320, 0 } }; constexpr static __m256i cb_c = { .m256i_i16 = { 28919, -5616, 0, 0, 28919, -5616, 0, 0, 28919, -5616, 0, 0, 28919, -5616, 0, 0 } }; constexpr static __m256i cr_c = { .m256i_i16 = { 0, -11655, 22881, 16320, 0, -11655, 22881, 16320, 0, -11655, 22881, 16320, 0, -11655, 22881, 16320 } }; //concurrency::parallel_for(0, efpip_g->obj_h, [=](int y) { for (int y = 0; y < efpip_g->obj_h; y++) { auto src_itr = efpip_g->obj_edit + y * efpip_g->obj_line; auto dst_itr = ptr + y * efpip_g->obj_w; for (int x = 0; x < efpip_g->obj_w / 4; x++) { auto src = _mm256_loadu_epi16(src_itr); auto dst = dst_itr; auto m_y = _mm256_shufflehi_epi16(_mm256_shufflelo_epi16(src, 0b1100'0000), 0b1100'0000); auto m_cb = _mm256_shufflehi_epi16(_mm256_shufflelo_epi16(src, 0b1101'0101), 0b1101'0101); auto m_cr = _mm256_shufflehi_epi16(_mm256_shufflelo_epi16(src, 0b1110'1010), 0b1110'1010); m_y = _mm256_mulhi_epi16(m_y , y_c); m_cb = _mm256_mulhi_epi16(m_cb, cb_c); m_cr = _mm256_mulhi_epi16(m_cr, cr_c); auto result_i16 = _mm256_adds_epi16(m_cb, m_cr); result_i16 = _mm256_adds_epi16(result_i16, m_y); result_i16 = _mm256_adds_epi16(result_i16, _mm256_set1_epi16(3)); result_i16 = _mm256_srai_epi16(result_i16, 2); auto result_i8 = _mm_packus_epi16(_mm256_extracti128_si256(result_i16, 0), _mm256_extracti128_si256(result_i16, 1)); _mm_storeu_epi8(dst, result_i8); src_itr += 4; dst_itr += 4; } if (auto mod = efpip_g->obj_w % 4; mod) { auto src = _mm256_loadu_epi16(src_itr); auto dst = dst_itr; auto m_y = _mm256_shufflehi_epi16(_mm256_shufflelo_epi16(src, 0b1100'0000), 0b1100'0000); auto m_cb = _mm256_shufflehi_epi16(_mm256_shufflelo_epi16(src, 0b1101'0101), 0b1101'0101); auto m_cr = _mm256_shufflehi_epi16(_mm256_shufflelo_epi16(src, 0b1110'1010), 0b1110'1010); m_y = _mm256_mulhi_epi16(m_y , y_c); m_cb = _mm256_mulhi_epi16(m_cb, cb_c); m_cr = _mm256_mulhi_epi16(m_cr, cr_c); auto result_i16 = _mm256_adds_epi16(m_cb, m_cr); result_i16 = _mm256_adds_epi16(result_i16, m_y); result_i16 = _mm256_adds_epi16(result_i16, _mm256_set1_epi16(3)); result_i16 = _mm256_srai_epi16(result_i16, 2); auto result_i8 = _mm_packus_epi16(_mm256_extracti128_si256(result_i16, 0), _mm256_extracti128_si256(result_i16, 1)); switch (mod) { case 1: _mm_storeu_si32(dst, result_i8); break; case 2: _mm_storeu_si64(dst, result_i8); break; case 3: _mm_maskstore_epi32(reinterpret_cast(dst), _mm_set_epi32(0, -1, -1, -1), result_i8); break; } } //}); } } lua_pushinteger(L, efpip_g->obj_w); lua_pushinteger(L, efpip_g->obj_h); return 3; } int getputpixeldata_t::avx_putpixeldata(lua_State* L) { if (!lua_isuserdata(L, 1)) return 0; auto pixelp = static_cast(lua_touserdata(L, 1)); if (pixelp == nullptr)return 0; return 0; } #if 0 int avx_putpixeldata_old(lua_State* L) { static constexpr m128_256 y_ef = { .m256 = { 0.299f / 255.f * 4096.f, 0.587f / 255.f * 4096.f, 0.114f / 255.f * 4096.f, 0.f, 0.299f / 255.f * 4096.f, 0.587f / 255.f * 4096.f, 0.114f / 255.f * 4096.f, 0.f, } }; static constexpr m128_256 cb_ef = { .m256 = { -0.169f / 255.f * 4096.f, -0.331f / 255.f * 4096.f, 0.5f / 255.f * 4096.f, 0.f, -0.169f / 255.f * 4096.f, -0.331f / 255.f * 4096.f, 0.5f / 255.f * 4096.f, 0.f, } }; static constexpr m128_256 cr_ef = { .m256 = { 0.5f / 255.f * 4096.f, -0.419f / 255.f * 4096.f, -0.081f / 255.f * 4096.f, 0.f, 0.5f / 255.f * 4096.f, -0.419f / 255.f * 4096.f, -0.081f / 255.f * 4096.f, 0.f, } }; static constexpr m128_256 a_ef = { .m256 = { 0.f,0.f,0.f,1.f / 255.f * 4096.f, 0.f,0.f,0.f,1.f / 255.f * 4096.f, } }; auto n = lua_gettop(L); if (auto data = static_cast(lua_touserdata(L, 1)); data) { auto efpip = *reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efpip_g); multi_threading([data, efpip](size_t i, size_t n) { const auto w = efpip->obj_w; const auto h = efpip->obj_h; const auto y_min = h * i / n; const auto y_max = h * (i + 1) / n; for (int y = y_min; std::cmp_less(y, h); y++) { for (int x = 0; std::cmp_less(x, w - (w & 1)); x += 2) { auto p128 = _mm_loadu_si64(data + x + y * efpip->obj_h); auto p256i = _mm256_cvtepu8_epi32(p128); /* auto p256ps = _mm256_cvtepi32_ps(p256i); auto ry = _mm256_dp_ps(p256ps, y_ef.m256, 0b01110001); auto rcb = _mm256_dp_ps(p256ps, cb_ef.m256, 0b01110010); auto rcr = _mm256_dp_ps(p256ps, cr_ef.m256, 0b01110100); auto ra = _mm256_dp_ps(p256ps, a_ef.m256, 0b01111000); auto rycb = _mm256_or_ps(ry, rcb); auto rcra = _mm256_or_ps(rcr, ra); auto r256ps = _mm256_or_ps(rycb, rcra); r256ps = _mm256_round_ps(r256ps, 0); auto r256i = _mm256_cvtps_epi32(r256ps); */ auto pr = _mm256_shuffle_epi32(p256i, 0b00000000); pr = _mm256_mullo_epi32(pr, _mm256_set_epi32(4918, -2775, 8224, 0, 4918, -2775, 8224, 0)); pr = _mm256_add_epi32(pr, _mm256_set_epi32(354, 240, 256, 0, 354, 240, 256, 0)); pr = _mm256_srai_epi32(pr, 10); auto pg = _mm256_shuffle_epi32(p256i, 0b01010101); pg = _mm256_mullo_epi32(pg, _mm256_set_epi32(9655, -5449, -6887, 0, 9655, -5449, -6887, 0)); pg = _mm256_add_epi32(pg, _mm256_set_epi32(585, 515, 110, 0, 585, 515, 110, 0)); pg = _mm256_srai_epi32(pg, 10); auto pb = _mm256_shuffle_epi32(p256i, 0b10101010); pb = _mm256_mullo_epi32(pb, _mm256_set_epi32(1875, 8224, -1337, 0, 1875, 8224, -1337, 0)); pb = _mm256_add_epi32(pb, _mm256_set_epi32(512, 256, 646, 0, 512, 256, 646, 0)); pb = _mm256_srai_epi32(pb, 10); auto pa = _mm256_shuffle_epi32(p256i, 0b11111111); pa = _mm256_mullo_epi32(pa, _mm256_set1_epi32(4096)); pa = _mm256_div_epi32(pa, _mm256_set1_epi32(255)); auto r = _mm256_add_epi32(pr, pg); r = _mm256_add_epi32(r, pb); r = _mm256_blend_epi32(r, pa, 0b10001000); auto r128 = _mm256_extracti128_si256(_mm256_packs_epi32(r, r), 0); _mm_storeu_si128((__m128i*)(efpip->obj_edit + efpip->obj_line * y + x), r128); } if (w & 1) { auto p128 = _mm_loadu_si64(data + w - 1 + y * efpip->obj_h); auto p128i = _mm_cvtepu8_epi32(p128); auto p128ps = _mm_cvtepi32_ps(p128i); auto ry = _mm_dp_ps(p128ps, y_ef.m128, 0b01110001); auto rcb = _mm_dp_ps(p128ps, cb_ef.m128, 0b01110010); auto rcr = _mm_dp_ps(p128ps, cr_ef.m128, 0b01110100); auto ra = _mm_dp_ps(p128ps, a_ef.m128, 0b01111000); auto rycb = _mm_or_ps(ry, rcb); auto rcra = _mm_or_ps(rcr, ra); auto r128ps = _mm_or_ps(rycb, rcra); r128ps = _mm_round_ps(r128ps, 0); auto r128i = _mm_cvtps_epi32(r128ps); auto r128 = _mm_cvtepi32_epi16(r128i); _mm_storeu_si64(efpip->obj_edit + efpip->obj_line * y + w - 1, r128); } } }); } return 0; } #endif } // namespace patch::fast #endif // ifdef PATCH_SWITCH_FAST_GETPUTPIXELDATA ================================================ FILE: patch/patch_fast_getputpixeldata.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FAST_GETPUTPIXELDATA #include #include "global.hpp" #include "offset_address.hpp" #include "mylua.hpp" #include "util_magic.hpp" namespace patch::fast { // init at ExEdit init // obj.getpixeldata/putpixeldata 他の動作を高速化 // AVXを使用 inline class getputpixeldata_t { static int avx_getpixeldata(lua_State* L); static int avx_putpixeldata(lua_State* L); static BOOL BufCpyBGRA2YCA(void* dst, void* src, int w, int h, int line); static BOOL BufCpyYCA2BGRA(void* dst, void* src, int w, int h, int line); union m128_256 { __m256 m256; __m128 m128; }; public: void operator()() { OverWriteOnProtectHelper(GLOBAL::exedit_base + OFS::ExEdit::getpixeldata, 4).store_i32(0, &avx_getpixeldata); } } getputpixeldata; } // namespace patch::fast #endif // ifdef PATCH_SWITCH_FAST_GETPUTPIXELDATA ================================================ FILE: patch/patch_fast_glow.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "patch_fast_glow.hpp" #ifdef PATCH_SWITCH_FAST_GLOW #include #include "global.hpp" #include "offset_address.hpp" #include "util_int.hpp" #include "debug_log.hpp" #include namespace patch::fast { void __cdecl Glow_t::lower_right_convolution1_wrap(int thread_id, int thread_num, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { thread_num *= 2; int func_ptr = GLOBAL::exedit_base + 0x570d0; reinterpret_cast(func_ptr)(thread_id, thread_num, efp, efpip); reinterpret_cast(func_ptr)(thread_num - thread_id - 1, thread_num, efp, efpip); } void __cdecl Glow_t::lower_right_convolution2_wrap(int thread_id, int thread_num, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { thread_num *= 2; int func_ptr = GLOBAL::exedit_base + 0x57730; reinterpret_cast(func_ptr)(thread_id, thread_num, efp, efpip); reinterpret_cast(func_ptr)(thread_num - thread_id - 1, thread_num, efp, efpip); } void __cdecl Glow_t::lower_left_convolution1_wrap(int thread_id, int thread_num, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { thread_num *= 2; int func_ptr = GLOBAL::exedit_base + 0x57d90; reinterpret_cast(func_ptr)(thread_id, thread_num, efp, efpip); reinterpret_cast(func_ptr)(thread_num - thread_id - 1, thread_num, efp, efpip); } void __cdecl Glow_t::lower_left_convolution2_wrap(int thread_id, int thread_num, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { thread_num *= 2; int func_ptr = GLOBAL::exedit_base + 0x58430; reinterpret_cast(func_ptr)(thread_id, thread_num, efp, efpip); reinterpret_cast(func_ptr)(thread_num - thread_id - 1, thread_num, efp, efpip); } struct fastGlow256 { __m256i data; __m256i y, cb, cr; __m256i offset; }; void __declspec(noinline) __fastcall fg256_add(fastGlow256* fg256, ExEdit::PixelYCA* src) { __m256i ycb256 = _mm256_i32gather_epi32((int*)src, fg256->offset, 1); __m256i y256 = _mm256_srai_epi32(_mm256_slli_epi32(ycb256, 16), 16); fg256->y = _mm256_add_epi32(fg256->y, y256); __m256i cb256 = _mm256_srai_epi32(ycb256, 16); fg256->cb = _mm256_add_epi32(fg256->cb, cb256); __m256i cbcr256 = _mm256_i32gather_epi32((int*)&src->cb, fg256->offset, 1); __m256i cr256 = _mm256_srai_epi32(cbcr256, 16); fg256->cr = _mm256_add_epi32(fg256->cr, cr256); } void __declspec(noinline) __fastcall fg256_sub(fastGlow256* fg256, ExEdit::PixelYCA* src) { __m256i ycb256 = _mm256_i32gather_epi32((int*)src, fg256->offset, 1); __m256i y256 = _mm256_srai_epi32(_mm256_slli_epi32(ycb256, 16), 16); fg256->y = _mm256_sub_epi32(fg256->y, y256); __m256i cb256 = _mm256_srai_epi32(ycb256, 16); fg256->cb = _mm256_sub_epi32(fg256->cb, cb256); __m256i cbcr256 = _mm256_i32gather_epi32((int*)&src->cb, fg256->offset, 1); __m256i cr256 = _mm256_srai_epi32(cbcr256, 16); fg256->cr = _mm256_sub_epi32(fg256->cr, cr256); } void __declspec(noinline) __fastcall fg256_put_average(fastGlow256* fg256, ExEdit::PixelYCA* dst, int n) { __m256i ave_y256 = _mm256_div_epi32(fg256->y, fg256->data); __m256i ave_cb256 = _mm256_div_epi32(fg256->cb, fg256->data); __m256i ave_cr256 = _mm256_div_epi32(fg256->cr, fg256->data); for (int i = 0; i < 16; i += 2) { dst->y = ave_y256.m256i_i16[i]; dst->cb = ave_cb256.m256i_i16[i]; dst->cr = ave_cr256.m256i_i16[i]; dst = (ExEdit::PixelYCA*)((int)dst + n); } } void __declspec(noinline) __fastcall fg_put256_weight(fastGlow256* fg256, ExEdit::PixelYCA* dst, int n) { fastGlow256 fg256s; __m256i y256 = _mm256_srai_epi32(fg256->y, 4); y256 = _mm256_mullo_epi32(y256, fg256->data); fg256s.y = _mm256_srai_epi32(y256, 10); __m256i cb256 = _mm256_srai_epi32(fg256->cb, 4); cb256 = _mm256_mullo_epi32(cb256, fg256->data); fg256s.cb = _mm256_srai_epi32(cb256, 10); __m256i cr256 = _mm256_srai_epi32(fg256->cr, 4); cr256 = _mm256_mullo_epi32(cr256, fg256->data); fg256s.cr = _mm256_srai_epi32(cr256, 10); fg256s.offset = fg256->offset; fg256_add(&fg256s, dst); for (int i = 0; i < 8; i++) { int y = fg256s.y.m256i_i32[i]; if (0x2000 < y) { dst->y = 0x2000; dst->cb = (short)((fg256s.cb.m256i_i32[i] << 13) / y); dst->cr = (short)((fg256s.cr.m256i_i32[i] << 13) / y); } else { dst->y = (short)y; dst->cb = fg256s.cb.m256i_i16[i * 2]; dst->cr = fg256s.cr.m256i_i16[i * 2]; } dst = (ExEdit::PixelYCA*)((int)dst + n); } } struct fastGlow128 { __m128i data; int y, cb, cr, a; }; void __declspec(noinline) __fastcall fg_put128_weight(fastGlow128* fg128, ExEdit::PixelYCA* dst) { __m128i yc128 = _mm_srai_epi32(_mm_loadu_si128((__m128i*)&fg128->y), 4); yc128 = _mm_mullo_epi32(yc128, fg128->data); yc128 = _mm_srai_epi32(yc128, 10); yc128 = _mm_add_epi32(yc128, _mm_cvtepi16_epi32(_mm_loadu_epi64(dst))); int y = yc128.m128i_i32[0]; if (0x2000 < y) { dst->y = 0x2000; dst->cb = (yc128.m128i_i32[1] << 13) / y; dst->cr = (yc128.m128i_i32[2] << 13) / y; } else { dst->y = (short)y; dst->cb = yc128.m128i_i16[2]; dst->cr = yc128.m128i_i16[4]; } } void __cdecl Glow_t::vertical_convolution(int thi, int thn, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { auto glow = (efGlow_var*)(GLOBAL::exedit_base + OFS::ExEdit::efGlow_var_ptr); int w = glow->src_w + glow->diffusion_w * 2; int h = glow->src_h + glow->diffusion_h * 2; int blur = min(glow->blur, (h - 1) / 2); int range = blur * 2 + 1; int range_h = h - range; int linesize = efpip->obj_line * sizeof(struct ExEdit::PixelYCA); int x_end = (thi + 1) * w / thn; fastGlow256 fg256; fg256.data = _mm256_set1_epi32(range); fg256.offset = _mm256_set_epi32(7 * sizeof(struct ExEdit::PixelYCA), 6 * sizeof(struct ExEdit::PixelYCA), 5 * sizeof(struct ExEdit::PixelYCA), 4 * sizeof(struct ExEdit::PixelYCA), 3 * sizeof(struct ExEdit::PixelYCA), 2 * sizeof(struct ExEdit::PixelYCA), sizeof(struct ExEdit::PixelYCA), 0); int x = thi * w / thn; int x_end256 = x_end - 7; for (; x < x_end256; x += 8) { auto pix1 = (ExEdit::PixelYCA*)((int)glow->buf_temp + x * sizeof(struct ExEdit::PixelYCA)); auto pix2 = pix1; auto mem = (ExEdit::PixelYCA*)((int)glow->buf_temp2 + x * sizeof(struct ExEdit::PixelYCA)); fg256.y = _mm256_setzero_si256(); fg256.cb = _mm256_setzero_si256(); fg256.cr = _mm256_setzero_si256(); for (int y = 0; y < blur; y++) { fg256_add(&fg256, pix1); pix1 = (ExEdit::PixelYCA*)((int)pix1 + linesize); } for (int y = 0; y <= blur; y++) { fg256_add(&fg256, pix1); pix1 = (ExEdit::PixelYCA*)((int)pix1 + linesize); fg256_put_average(&fg256, mem, sizeof(struct ExEdit::PixelYCA)); mem = (ExEdit::PixelYCA*)((int)mem + linesize); } for (int y = 0; y < range_h; y++) { fg256_sub(&fg256, pix2); pix2 = (ExEdit::PixelYCA*)((int)pix2 + linesize); fg256_add(&fg256, pix1); pix1 = (ExEdit::PixelYCA*)((int)pix1 + linesize); fg256_put_average(&fg256, mem, sizeof(struct ExEdit::PixelYCA)); mem = (ExEdit::PixelYCA*)((int)mem + linesize); } for (int y = 0; y < blur; y++) { fg256_sub(&fg256, pix2); pix2 = (ExEdit::PixelYCA*)((int)pix2 + linesize); fg256_put_average(&fg256, mem, sizeof(struct ExEdit::PixelYCA)); mem = (ExEdit::PixelYCA*)((int)mem + linesize); } } for (; x < x_end; x++) { auto pix1 = (ExEdit::PixelYCA*)((int)glow->buf_temp + x * sizeof(struct ExEdit::PixelYCA)); auto pix2 = pix1; auto mem = (ExEdit::PixelYCA*)((int)glow->buf_temp2 + x * sizeof(struct ExEdit::PixelYCA)); int sum_y = 0; int sum_cb = 0; int sum_cr = 0; for (int y = 0; y < blur; y++) { sum_y += pix1->y; sum_cb += pix1->cb; sum_cr += pix1->cr; pix1 = (ExEdit::PixelYCA*)((int)pix1 + linesize); } for (int y = 0; y <= blur; y++) { sum_y += pix1->y; sum_cb += pix1->cb; sum_cr += pix1->cr; pix1 = (ExEdit::PixelYCA*)((int)pix1 + linesize); mem->y = (short)(sum_y / range); mem->cb = (short)(sum_cb / range); mem->cr = (short)(sum_cr / range); mem = (ExEdit::PixelYCA*)((int)mem + linesize); } for (int y = 0; y < range_h; y++) { sum_y += pix1->y - pix2->y; sum_cb += pix1->cb - pix2->cb; sum_cr += pix1->cr - pix2->cr; pix1 = (ExEdit::PixelYCA*)((int)pix1 + linesize); pix2 = (ExEdit::PixelYCA*)((int)pix2 + linesize); mem->y = (short)(sum_y / range); mem->cb = (short)(sum_cb / range); mem->cr = (short)(sum_cr / range); mem = (ExEdit::PixelYCA*)((int)mem + linesize); } for (int y = 0; y < blur; y++) { sum_y -= pix2->y; sum_cb -= pix2->cb; sum_cr -= pix2->cr; pix2 = (ExEdit::PixelYCA*)((int)pix2 + linesize); mem->y = (short)(sum_y / range); mem->cb = (short)(sum_cb / range); mem->cr = (short)(sum_cr / range); mem = (ExEdit::PixelYCA*)((int)mem + linesize); } } } void __cdecl Glow_t::horizontal_convolution(int thi, int thn, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { auto glow = (efGlow_var*)(GLOBAL::exedit_base + OFS::ExEdit::efGlow_var_ptr); int h = glow->src_h + glow->diffusion_h * 2; int w = glow->src_w + glow->diffusion_w * 2; int blur = min(glow->blur, (w - 1) / 2); int range = blur * 2 + 1; int range_w = w - range; int linesize = efpip->obj_line * sizeof(struct ExEdit::PixelYCA); int y_begin = thi * h / thn; int y_end = (thi + 1) * h / thn; int offset = y_begin * linesize; fastGlow256 fg256; fg256.data = _mm256_set1_epi32(range); fg256.offset = _mm256_mullo_epi32(_mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0), _mm256_set1_epi32(linesize)); int y = y_begin; int y_end256 = y_end - 7; for (; y < y_end256; y += 8) { auto mem1 = (ExEdit::PixelYCA*)((int)glow->buf_temp2 + offset); auto mem2 = mem1; auto pix = (ExEdit::PixelYCA*)((int)glow->buf_temp + offset); fg256.y = _mm256_setzero_si256(); fg256.cb = _mm256_setzero_si256(); fg256.cr = _mm256_setzero_si256(); for (int x = 0; x < blur; x++) { fg256_add(&fg256, mem1); mem1++; } for (int x = 0; x <= blur; x++) { fg256_add(&fg256, mem1); mem1++; fg256_put_average(&fg256, pix, linesize); pix++; } for (int x = 0; x < range_w; x++) { fg256_sub(&fg256, mem2); mem2++; fg256_add(&fg256, mem1); mem1++; fg256_put_average(&fg256, pix, linesize); pix++; } for (int x = 0; x < blur; x++) { fg256_sub(&fg256, mem2); mem2++; fg256_put_average(&fg256, pix, linesize); pix++; } offset += linesize * 8; } for (; y < y_end; y++) { auto mem1 = (ExEdit::PixelYCA*)((int)glow->buf_temp2 + offset); auto mem2 = mem1; auto pix = (ExEdit::PixelYCA*)((int)glow->buf_temp + offset); int sum_y = 0; int sum_cb = 0; int sum_cr = 0; for (int x = 0; x < blur; x++) { sum_y += mem1->y; sum_cb += mem1->cb; sum_cr += mem1->cr; mem1++; } for (int x = 0; x <= blur; x++) { sum_y += mem1->y; sum_cb += mem1->cb; sum_cr += mem1->cr; mem1++; pix->y = (short)(sum_y / range); pix->cb = (short)(sum_cb / range); pix->cr = (short)(sum_cr / range); pix++; } for (int x = 0; x < range_w; x++) { sum_y += mem1->y - mem2->y; sum_cb += mem1->cb - mem2->cb; sum_cr += mem1->cr - mem2->cr; mem1++; mem2++; pix->y = (short)(sum_y / range); pix->cb = (short)(sum_cb / range); pix->cr = (short)(sum_cr / range); pix++; } for (int x = 0; x < blur; x++) { sum_y -= mem2->y; sum_cb -= mem2->cb; sum_cr -= mem2->cr; mem2++; pix->y = (short)(sum_y / range); pix->cb = (short)(sum_cb / range); pix->cr = (short)(sum_cr / range); pix++; } offset += linesize; } } void __cdecl Glow_t::horizontal_convolution_intensity_blur(int thi, int thn, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { auto glow = (efGlow_var*)(GLOBAL::exedit_base + OFS::ExEdit::efGlow_var_ptr); int h = glow->src_h + glow->diffusion_h * 2; int blur = glow->blur; int range_w = glow->src_w + (glow->diffusion_w - blur) * 2 - 1; int intensity = glow->intensity; int linesize = efpip->obj_line * sizeof(struct ExEdit::PixelYCA); int y_begin = thi * h / thn; int y_end = (thi + 1) * h / thn; int offset = y_begin * linesize; fastGlow256 fg256; fg256.data = _mm256_set1_epi32(intensity); fg256.offset = _mm256_mullo_epi32(_mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0), _mm256_set1_epi32(linesize)); int y = y_begin; int y_end256 = y_end - 7; for (; y < y_end256; y += 8) { auto mem1 = (ExEdit::PixelYCA*)((int)glow->buf_temp2 + offset); auto mem2 = mem1; auto pix = (ExEdit::PixelYCA*)((int)glow->buf_temp + offset); fg256.y = _mm256_setzero_si256(); fg256.cb = _mm256_setzero_si256(); fg256.cr = _mm256_setzero_si256(); for (int x = 0; x < blur; x++) { fg256_add(&fg256, mem1); mem1++; } for (int x = 0; x <= blur; x++) { fg256_add(&fg256, mem1); mem1++; fg_put256_weight(&fg256, pix, linesize); pix++; } for (int x = 0; x < range_w; x++) { fg256_sub(&fg256, mem2); mem2++; fg256_add(&fg256, mem1); mem1++; fg_put256_weight(&fg256, pix, linesize); pix++; } for (int x = 0; x < blur; x++) { fg256_sub(&fg256, mem2); mem2++; fg_put256_weight(&fg256, pix, linesize); pix++; } offset += linesize * 8; } fastGlow128 fg128; fg128.data = _mm_set1_epi32(intensity); for (; y < y_end; y++) { auto mem1 = (ExEdit::PixelYCA*)((int)glow->buf_temp2 + offset); auto mem2 = mem1; auto pix = (ExEdit::PixelYCA*)((int)glow->buf_temp + offset); fg128.y = 0; fg128.cb = 0; fg128.cr = 0; for (int x = 0; x < blur; x++) { fg128.y += mem1->y; fg128.cb += mem1->cb; fg128.cr += mem1->cr; mem1++; } for (int x = 0; x <= blur; x++) { fg128.y += mem1->y; fg128.cb += mem1->cb; fg128.cr += mem1->cr; mem1++; fg_put128_weight(&fg128, pix); pix++; } for (int x = 0; x < range_w; x++) { fg128.y += mem1->y - mem2->y; fg128.cb += mem1->cb - mem2->cb; fg128.cr += mem1->cr - mem2->cr; mem1++; mem2++; fg_put128_weight(&fg128, pix); pix++; } for (int x = 0; x < blur; x++) { fg128.y -= mem2->y; fg128.cb -= mem2->cb; fg128.cr -= mem2->cr; mem2++; fg_put128_weight(&fg128, pix); pix++; } offset += linesize; } } void vertical_convolution_intensity_main(int thi, int thn, int n, ExEdit::FilterProcInfo* efpip) { auto glow = (Glow_t::efGlow_var*)(GLOBAL::exedit_base + OFS::ExEdit::efGlow_var_ptr); int w = glow->src_w; int h = glow->src_h; int diff_h = glow->diffusion_h; int diff = min(diff_h / n, (h - 1) / 2); int diff2 = diff * 2; int range = h - diff2 - 1; int linesize = efpip->obj_line * sizeof(struct ExEdit::PixelYCA); int intensity = glow->intensity * n; int x_end = (thi + 1) * w / thn; auto pix_temp = (ExEdit::PixelYCA*)((int)glow->buf_temp + (diff_h - diff) * linesize + glow->diffusion_w * sizeof(struct ExEdit::PixelYCA)); fastGlow256 fg256; fg256.data = _mm256_set1_epi32(intensity); fg256.offset = _mm256_set_epi32(7 * sizeof(struct ExEdit::PixelYCA), 6 * sizeof(struct ExEdit::PixelYCA), 5 * sizeof(struct ExEdit::PixelYCA), 4 * sizeof(struct ExEdit::PixelYCA), 3 * sizeof(struct ExEdit::PixelYCA), 2 * sizeof(struct ExEdit::PixelYCA), sizeof(struct ExEdit::PixelYCA), 0); int x = thi * w / thn; int x_end256 = x_end - 7; for (; x < x_end256; x += 8) { auto mem1 = (ExEdit::PixelYCA*)((int)glow->buf_temp2 + x * sizeof(struct ExEdit::PixelYCA)); auto mem2 = mem1; auto pix = (ExEdit::PixelYCA*)((int)pix_temp + x * sizeof(struct ExEdit::PixelYCA)); fg256.y = _mm256_setzero_si256(); fg256.cb = _mm256_setzero_si256(); fg256.cr = _mm256_setzero_si256(); for (int y = 0; y <= diff2; y++) { fg256_add(&fg256, mem1); mem1 = (ExEdit::PixelYCA*)((int)mem1 + linesize); fg_put256_weight(&fg256, pix, sizeof(struct ExEdit::PixelYCA)); pix = (ExEdit::PixelYCA*)((int)pix + linesize); } for (int y = 0; y < range; y++) { fg256_sub(&fg256, mem2); mem2 = (ExEdit::PixelYCA*)((int)mem2 + linesize); fg256_add(&fg256, mem1); mem1 = (ExEdit::PixelYCA*)((int)mem1 + linesize); fg_put256_weight(&fg256, pix, sizeof(struct ExEdit::PixelYCA)); pix = (ExEdit::PixelYCA*)((int)pix + linesize); } for (int y = 0; y < diff2; y++) { fg256_sub(&fg256, mem2); mem2 = (ExEdit::PixelYCA*)((int)mem2 + linesize); fg_put256_weight(&fg256, pix, sizeof(struct ExEdit::PixelYCA)); pix = (ExEdit::PixelYCA*)((int)pix + linesize); } } fastGlow128 fg128; fg128.data = _mm_set1_epi32(intensity); for (; x < x_end; x++) { auto mem1 = (ExEdit::PixelYCA*)((int)glow->buf_temp2 + x * sizeof(struct ExEdit::PixelYCA)); auto mem2 = mem1; auto pix = (ExEdit::PixelYCA*)((int)pix_temp + x * sizeof(struct ExEdit::PixelYCA)); fg128.y = 0; fg128.cb = 0; fg128.cr = 0; for (int y = 0; y <= diff2; y++) { fg128.y += mem1->y; fg128.cb += mem1->cb; fg128.cr += mem1->cr; mem1 = (ExEdit::PixelYCA*)((int)mem1 + linesize); fg_put128_weight(&fg128, pix); pix = (ExEdit::PixelYCA*)((int)pix + linesize); } for (int y = 0; y < range; y++) { fg128.y += mem1->y - mem2->y; fg128.cb += mem1->cb - mem2->cb; fg128.cr += mem1->cr - mem2->cr; mem1 = (ExEdit::PixelYCA*)((int)mem1 + linesize); mem2 = (ExEdit::PixelYCA*)((int)mem2 + linesize); fg_put128_weight(&fg128, pix); pix = (ExEdit::PixelYCA*)((int)pix + linesize); } for (int y = 0; y < diff2; y++) { fg128.y -= mem2->y; fg128.cb -= mem2->cb; fg128.cr -= mem2->cr; mem2 = (ExEdit::PixelYCA*)((int)mem2 + linesize); fg_put128_weight(&fg128, pix); pix = (ExEdit::PixelYCA*)((int)pix + linesize); } } } void __cdecl Glow_t::vertical_convolution_intensity3(int thi, int thn, ExEdit::Filter * efp, ExEdit::FilterProcInfo * efpip) { vertical_convolution_intensity_main(thi, thn, 1, efpip); vertical_convolution_intensity_main(thi, thn, 2, efpip); vertical_convolution_intensity_main(thi, thn, 4, efpip); } void horizontal_convolution_intensity_main(int thi, int thn, int n, ExEdit::FilterProcInfo* efpip) { auto glow = (Glow_t::efGlow_var*)(GLOBAL::exedit_base + OFS::ExEdit::efGlow_var_ptr); int w = glow->src_w; int h = glow->src_h; int diff_w = glow->diffusion_w; int diff = min(diff_w / n, (w - 1) / 2); int diff2 = diff * 2; int range = w - diff2 - 1; int linesize = efpip->obj_line * sizeof(struct ExEdit::PixelYCA); int intensity = glow->intensity * n; int y_begin = thi * h / thn; int y_end = (thi + 1) * h / thn; int offset = y_begin * linesize; auto pix_temp = (ExEdit::PixelYCA*)((int)glow->buf_temp + glow->diffusion_h * linesize + (diff_w - diff) * sizeof(struct ExEdit::PixelYCA)); fastGlow256 fg256; fg256.data = _mm256_set1_epi32(intensity); fg256.offset = _mm256_mullo_epi32(_mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0), _mm256_set1_epi32(linesize)); int y = y_begin; int y_end256 = y_end - 7; for (; y < y_end256; y += 8) { auto mem1 = (ExEdit::PixelYCA*)((int)glow->buf_temp2 + offset); auto mem2 = mem1; auto pix = (ExEdit::PixelYCA*)((int)pix_temp + offset); fg256.y = _mm256_setzero_si256(); fg256.cb = _mm256_setzero_si256(); fg256.cr = _mm256_setzero_si256(); for (int x = 0; x <= diff2; x++) { fg256_add(&fg256, mem1); mem1++; fg_put256_weight(&fg256, pix, linesize); pix++; } for (int x = 0; x < range; x++) { fg256_sub(&fg256, mem2); mem2++; fg256_add(&fg256, mem1); mem1++; fg_put256_weight(&fg256, pix, linesize); pix++; } for (int x = 0; x < diff2; x++) { fg256_sub(&fg256, mem2); mem2++; fg_put256_weight(&fg256, pix, linesize); pix++; } offset += linesize * 8; } fastGlow128 fg128; fg128.data = _mm_set1_epi32(intensity); for (; y < y_end; y++) { auto mem1 = (ExEdit::PixelYCA*)((int)glow->buf_temp2 + offset); auto mem2 = mem1; auto pix = (ExEdit::PixelYCA*)((int)pix_temp + offset); fg128.y = 0; fg128.cb = 0; fg128.cr = 0; for (int x = 0; x <= diff2; x++) { fg128.y += mem1->y; fg128.cb += mem1->cb; fg128.cr += mem1->cr; mem1++; fg_put128_weight(&fg128, pix); pix++; } for (int x = 0; x < range; x++) { fg128.y += mem1->y - mem2->y; fg128.cb += mem1->cb - mem2->cb; fg128.cr += mem1->cr - mem2->cr; mem1++; mem2++; fg_put128_weight(&fg128, pix); pix++; } for (int x = 0; x < diff2; x++) { fg128.y -= mem2->y; fg128.cb -= mem2->cb; fg128.cr -= mem2->cr; mem2++; fg_put128_weight(&fg128, pix); pix++; } offset += linesize; } } void __cdecl Glow_t::horizontal_convolution_intensity3(int thi, int thn, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { horizontal_convolution_intensity_main(thi, thn, 1, efpip); horizontal_convolution_intensity_main(thi, thn, 2, efpip); horizontal_convolution_intensity_main(thi, thn, 4, efpip); } } #endif // ifdef PATCH_SWITCH_FAST_GLOW ================================================ FILE: patch/patch_fast_glow.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FAST_GLOW #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "global.hpp" #include "config_rw.hpp" namespace patch::fast { // init at exedit load // グローちょっとだけ速度アップ // クロス斜め以外:AVX2を使用 /* クロス斜め:マルチスレッド処理の効率が悪かった部分を修正(AVX2処理にするのは難しい部分) スレッドIDによってループ数に大きく差が出る部分があったのでなるべく均等になるように分担 理想的な均等にするなら「正方形」と「残り」の形にしてから行う必要がある。(関数の作り変えも必要) 簡易的に実装し元の関数を再利用する。(元より悪くなることは無いはず) */ inline class Glow_t { static void __cdecl lower_right_convolution1_wrap(int thi, int thn, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); static void __cdecl lower_right_convolution2_wrap(int thi, int thn, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); static void __cdecl lower_left_convolution1_wrap(int thi, int thn, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); static void __cdecl lower_left_convolution2_wrap(int thi, int thn, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); static void __cdecl vertical_convolution(int thi, int thn, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); static void __cdecl horizontal_convolution(int thi, int thn, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); static void __cdecl vertical_convolution_intensity3(int thi, int thn, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); static void __cdecl horizontal_convolution_intensity3(int thi, int thn, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); static void __cdecl horizontal_convolution_intensity_blur(int thi, int thn, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); bool enabled = true; bool enabled_i; inline static const char key[] = "fast.glow"; public: struct efGlow_var { // 1b2010 int src_h; int src_w; int intensity; int blur; int diffusion_h; int diffusion_w; int diffusion_length; short light_cb; short light_cr; short light_y; short _padding; void* buf_temp; void* buf_temp2; int threshold; // 1b203c }; void init() { enabled_i = enabled; if (!enabled_i)return; { // クロス斜め { { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x55363, 4); h.store_i32(0, &lower_right_convolution1_wrap); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x553cb, 4); h.store_i32(0, &lower_right_convolution1_wrap); } } { { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x55373, 4); h.store_i32(0, &lower_right_convolution2_wrap); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x553db, 4); h.store_i32(0, &lower_right_convolution2_wrap); } } { { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x55383, 4); h.store_i32(0, &lower_left_convolution1_wrap); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x553eb, 4); h.store_i32(0, &lower_left_convolution1_wrap); } } { { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x55393, 4); h.store_i32(0, &lower_left_convolution2_wrap); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x553fb, 4); h.store_i32(0, &lower_left_convolution2_wrap); } } } { // クロス斜め以外 auto cpucmdset = get_CPUCmdSet(); if (!has_flag(cpucmdset, CPUCmdSet::F_AVX2))return; { { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x551ea, 4); h.store_i32(0, &vertical_convolution); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x5528a, 4); h.store_i32(0, &vertical_convolution); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x552ca, 4); h.store_i32(0, &vertical_convolution); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x55309, 4); h.store_i32(0, &vertical_convolution); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x55444, 4); h.store_i32(0, &vertical_convolution); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x55464, 4); h.store_i32(0, &vertical_convolution); } } { { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x55454, 4); h.store_i32(0, &horizontal_convolution); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x55474, 4); h.store_i32(0, &horizontal_convolution); } } { { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x5525a, 4); h.store_i32(0, &horizontal_convolution_intensity_blur); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x552a3, 4); h.store_i32(0, &horizontal_convolution_intensity_blur); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x552e5, 4); h.store_i32(0, &horizontal_convolution_intensity_blur); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x55326, 4); h.store_i32(0, &horizontal_convolution_intensity_blur); } } { { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x5533b, 4); h.store_i32(0, &vertical_convolution_intensity3); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x553ab, 4); h.store_i32(0, &vertical_convolution_intensity3); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x55422, 4); h.store_i32(0, &vertical_convolution_intensity3); } } { { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x5534b, 4); h.store_i32(0, &horizontal_convolution_intensity3); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x553bb, 4); h.store_i32(0, &horizontal_convolution_intensity3); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x55410, 4); h.store_i32(0, &horizontal_convolution_intensity3); } } } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } Glow; } // namespace patch::fast #endif // ifdef PATCH_SWITCH_FAST_GLOW ================================================ FILE: patch/patch_fast_lensblur.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_fast_lensblur.hpp" #ifdef PATCH_SWITCH_FAST_LENSBLUR #include "debug_log.hpp" #include "patch_fast_cl.hpp" //#define PATCH_STOPWATCH #include "stopwatch.hpp" namespace patch::fast { static stopwatch_mem sw; BOOL LensBlur_t::media_mt_func(AviUtl::MultiThreadFunc original_func_ptr, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { if constexpr (true) { if (256 < efpip->obj_w * efpip->obj_h) { sw.start(); try { const auto buf_size = efpip->obj_line * efpip->obj_h * sizeof(ExEdit::PixelYCA); cl::Buffer clmem_src(cl.context, CL_MEM_READ_ONLY, buf_size); cl.queue.enqueueWriteBuffer(clmem_src, CL_TRUE, 0, buf_size, efpip->obj_edit); cl::Buffer clmem_dst(cl.context, CL_MEM_WRITE_ONLY, buf_size); efLensBlur_var& lensblur = *(efLensBlur_var*)uintptr_t(reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efLensBlur_var_ptr)); auto kernel = cl.readyKernel( "LensBlur_Media", clmem_dst, clmem_src, efpip->obj_w, efpip->obj_h, efpip->obj_line, lensblur.range, lensblur.rangep05_sqr, lensblur.range_t3m1, lensblur.rangem1_sqr ); cl.queue.enqueueNDRangeKernel(kernel, { 0,0 }, { (size_t)efpip->obj_w ,(size_t)efpip->obj_h }); cl.queue.enqueueReadBuffer(clmem_dst, CL_TRUE, 0, buf_size, efpip->obj_temp); } catch (const cl::Error& err) { debug_log("OpenCL Error\n({}) {}", err.err(), err.what()); return efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); } sw.stop(); return TRUE; } else { return efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); } } else { sw.start(); const auto ret = efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); sw.stop(); return ret; } } BOOL LensBlur_t::filter_mt_func(AviUtl::MultiThreadFunc original_func_ptr, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { if constexpr (true) { sw.start(); try { const auto buf_size = efpip->scene_line * efpip->scene_h * sizeof(ExEdit::PixelYC); cl::Buffer clmem_src(cl.context, CL_MEM_READ_ONLY, buf_size); cl.queue.enqueueWriteBuffer(clmem_src, CL_TRUE, 0, buf_size, efpip->frame_edit); cl::Buffer clmem_dst(cl.context, CL_MEM_WRITE_ONLY, buf_size); efLensBlur_var& lensblur = *(efLensBlur_var*)uintptr_t(reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efLensBlur_var_ptr)); auto kernel = cl.readyKernel( "LensBlur_Filter", clmem_dst, clmem_src, efpip->scene_w, efpip->scene_h, efpip->scene_line, lensblur.range, lensblur.rangep05_sqr, lensblur.range_t3m1, lensblur.rangem1_sqr ); cl.queue.enqueueNDRangeKernel(kernel, { 0,0 }, { (size_t)efpip->scene_w ,(size_t)efpip->scene_h }); cl.queue.enqueueReadBuffer(clmem_dst, CL_TRUE, 0, buf_size, efpip->frame_temp); } catch (const cl::Error& err) { debug_log("OpenCL Error\n({}) {}", err.err(), err.what()); return efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); } sw.stop(); return TRUE; } else { sw.start(); const auto ret = efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); sw.stop(); return ret; } } } // namespace patch::fast #endif // ifdef PATCH_SWITCH_FAST_LENSBLUR ================================================ FILE: patch/patch_fast_lensblur.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FAST_LENSBLUR #include #include "util_magic.hpp" #include "offset_address.hpp" #include "global.hpp" #include "config_rw.hpp" namespace patch::fast { // init at exedit load // レンズブラーの高速化 inline class LensBlur_t { static BOOL media_mt_func(AviUtl::MultiThreadFunc original_func_ptr, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); static BOOL filter_mt_func(AviUtl::MultiThreadFunc original_func_ptr, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); bool enabled = true; bool enabled_i; inline static const char key[] = "fast.lensblur"; public: struct efLensBlur_var { // 11ec5c int range; // 11ec5c int rangep05_sqr; // 11ec60 int range_t3m1; // 11ec64 int rangem1_sqr; // 11ec68 }; void init() { enabled_i = enabled; if (!enabled_i)return; { OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::efLensBlur_Media_mt_func_call, 6); h.store_i16(0, '\x90\xe8'); // nop; call (rel32) h.replaceNearJmp(2, &media_mt_func); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::efLensBlur_Filter_mt_func_call, 6); h.store_i16(0, '\x90\xe8'); // nop; call (rel32) h.replaceNearJmp(2, &filter_mt_func); } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } LensBlur; } // namespace patch::fast #endif // ifdef PATCH_SWITCH_FAST_LENSBLUR ================================================ FILE: patch/patch_fast_polortransform.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "patch_fast_polortransform.hpp" #ifdef PATCH_SWITCH_FAST_POLORTRANSFORM #include #include "global.hpp" #include "offset_address.hpp" #include "util_int.hpp" #include "patch_fast_cl.hpp" #include "debug_log.hpp" //#define PATCH_STOPWATCH #include "stopwatch.hpp" static stopwatch_mem sw; namespace patch::fast { BOOL PolorTransform_t::mt_func(AviUtl::MultiThreadFunc original_func_ptr, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { if constexpr (true) { if (256 < efpip->obj_w * efpip->obj_h) { sw.start(); try { efPolorTransform_var& polor = *reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efPolorTransform_var_ptr); const auto src_size = efpip->obj_line * polor.src_h * sizeof(ExEdit::PixelYCA); cl::Buffer clmem_src(cl.context, CL_MEM_READ_ONLY, src_size); cl.queue.enqueueWriteBuffer(clmem_src, CL_TRUE, 0, src_size, efpip->obj_edit); const auto dst_size = efpip->obj_line * polor.output_size * 8; cl::Buffer clmem_dst(cl.context, CL_MEM_WRITE_ONLY, dst_size); auto kernel = cl.readyKernel( "PolorTransform", clmem_dst, clmem_src, polor.src_w, polor.src_h, efpip->obj_line, polor.center_length, polor.radius, static_cast(polor.angle), static_cast(polor.uzu), static_cast(polor.uzu_a) ); cl.queue.enqueueNDRangeKernel(kernel, { 0,0 }, { (size_t)polor.output_size ,(size_t)polor.output_size }); cl.queue.enqueueReadBuffer(clmem_dst, CL_TRUE, 0, dst_size, efpip->obj_temp); } catch (const cl::Error& err) { debug_log("OpenCL Error\n({}) {}", err.err(), err.what()); return efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); } sw.stop(); return TRUE; } else { return efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); } } else { sw.start(); const auto ret = efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); sw.stop(); return ret; } } } #endif // ifdef PATCH_SWITCH_FAST_POLORTRANSFORM ================================================ FILE: patch/patch_fast_polortransform.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FAST_POLORTRANSFORM #include #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "global.hpp" #include "config_rw.hpp" namespace patch::fast { // init at exedit load // 極座標変換の高速化 inline class PolorTransform_t { static BOOL mt_func(AviUtl::MultiThreadFunc original_func_ptr, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); bool enabled = true; bool enabled_i; inline static const char key[] = "fast.polortransform"; public: struct efPolorTransform_var { // 1e48c0 int src_h; int radius; int src_w; int _padding; double uzu; double uzu_a; double angle; int center_length; int output_size; }; void init() { enabled_i = enabled; if (!enabled_i)return; OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::efPolorTransform_mt_func_call, 6); h.store_i16(0, '\x90\xe8'); // nop; call (rel32) h.replaceNearJmp(2, &mt_func); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } PolorTransform; } // namespace patch::fast #endif // ifdef PATCH_SWITCH_FAST_POLORTRANSFORM ================================================ FILE: patch/patch_fast_radiationalblur.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_fast_radiationalblur.hpp" #ifdef PATCH_SWITCH_FAST_RADIATIONALBLUR #include "debug_log.hpp" #include "patch_fast_cl.hpp" //#define PATCH_STOPWATCH #include "stopwatch.hpp" namespace patch::fast { static stopwatch_mem sw; BOOL RadiationalBlur_t::media_mt_func(AviUtl::MultiThreadFunc original_func_ptr, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { if constexpr (true) { sw.start(); try { auto& rb = *reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efRadiationalBlur_var_ptr); const auto src_size = efpip->obj_line * efpip->obj_h * sizeof(ExEdit::PixelYCA); cl::Buffer clmem_src(cl.context, CL_MEM_READ_ONLY, src_size); cl.queue.enqueueWriteBuffer(clmem_src, CL_TRUE, 0, src_size, efpip->obj_edit); const auto dst_size = efpip->obj_line * (rb.h - rb.obj_cy) * sizeof(ExEdit::PixelYCA); cl::Buffer clmem_dst(cl.context, CL_MEM_WRITE_ONLY, dst_size); auto kernel = cl.readyKernel( "RadiationalBlur_Media", clmem_dst, clmem_src, efpip->obj_w, efpip->obj_h, efpip->obj_line, rb.blur_cx, rb.blur_cy, rb.obj_cx, rb.obj_cy, rb.range, rb.pixel_range ); cl.queue.enqueueNDRangeKernel(kernel, { 0,0 }, { (size_t)rb.w - rb.obj_cx ,(size_t)rb.h - rb.obj_cy }); cl.queue.enqueueReadBuffer(clmem_dst, CL_TRUE, 0, dst_size, efpip->obj_temp); } catch (const cl::Error& err) { debug_log("OpenCL Error\n({}) {}", err.err(), err.what()); return efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); } sw.stop(); return TRUE; } else { sw.start(); const auto ret = efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); sw.stop(); return ret; } } BOOL RadiationalBlur_t::filter_mt_func(AviUtl::MultiThreadFunc original_func_ptr, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { if constexpr (true) { sw.start(); try { const auto buf_size = efpip->scene_line * efpip->scene_h * sizeof(ExEdit::PixelYC); cl::Buffer clmem_src(cl.context, CL_MEM_READ_ONLY, buf_size); cl.queue.enqueueWriteBuffer(clmem_src, CL_TRUE, 0, buf_size, efpip->frame_edit); cl::Buffer clmem_dst(cl.context, CL_MEM_WRITE_ONLY, buf_size); auto& rb = *reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efRadiationalBlur_var_ptr); auto kernel = cl.readyKernel( "RadiationalBlur_Filter", clmem_dst, clmem_src, efpip->scene_line, rb.blur_cx, rb.blur_cy, rb.range, rb.pixel_range ); cl.queue.enqueueNDRangeKernel(kernel, { 0,0 }, { (size_t)efpip->scene_w ,(size_t)efpip->scene_h }); cl.queue.enqueueReadBuffer(clmem_dst, CL_TRUE, 0, buf_size, efpip->frame_temp); } catch (const cl::Error& err) { debug_log("OpenCL Error\n({}) {}", err.err(), err.what()); return efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); } sw.stop(); return TRUE; } else { sw.start(); const auto ret = efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); sw.stop(); return ret; } } BOOL RadiationalBlur_t::filter_mt_far_func(AviUtl::MultiThreadFunc original_func_ptr, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip) { if constexpr (true) { sw.start(); try { const auto buf_size = efpip->scene_line * efpip->scene_h * sizeof(ExEdit::PixelYC); cl::Buffer clmem_src(cl.context, CL_MEM_READ_ONLY, buf_size); cl.queue.enqueueWriteBuffer(clmem_src, CL_TRUE, 0, buf_size, efpip->frame_edit); cl::Buffer clmem_dst(cl.context, CL_MEM_WRITE_ONLY, buf_size); auto& rb = *reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::efRadiationalBlur_var_ptr); auto kernel = cl.readyKernel( "RadiationalBlur_Filter_Far", clmem_dst, clmem_src, efpip->scene_w, efpip->scene_h, efpip->scene_line, rb.blur_cx, rb.blur_cy, rb.range, rb.pixel_range ); cl.queue.enqueueNDRangeKernel(kernel, { 0,0 }, { (size_t)efpip->scene_w ,(size_t)efpip->scene_h }); cl.queue.enqueueReadBuffer(clmem_dst, CL_TRUE, 0, buf_size, efpip->frame_temp); } catch (const cl::Error& err) { debug_log("OpenCL Error\n({}) {}", err.err(), err.what()); return efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); } sw.stop(); return TRUE; } else { sw.start(); const auto ret = efp->aviutl_exfunc->exec_multi_thread_func(original_func_ptr, efp, efpip); sw.stop(); return ret; } } } // namespace patch::fast #endif // ifdef PATCH_SWITCH_FAST_RADIATIONALBLUR ================================================ FILE: patch/patch_fast_radiationalblur.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FAST_RADIATIONALBLUR #include #include "util_magic.hpp" #include "offset_address.hpp" #include "global.hpp" #include "config_rw.hpp" namespace patch::fast { // init at exedit load // 放射ブラーの高速化 inline class RadiationalBlur_t { static BOOL media_mt_func(AviUtl::MultiThreadFunc original_func_ptr, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); static BOOL filter_mt_func(AviUtl::MultiThreadFunc original_func_ptr, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); static BOOL filter_mt_far_func(AviUtl::MultiThreadFunc original_func_ptr, ExEdit::Filter* efp, ExEdit::FilterProcInfo* efpip); bool enabled = true; bool enabled_i; inline static const char key[] = "fast.radiationalblur"; public: struct efRadiationalBlur_var { // d75a8 int blur_cx; // ブラーの中心位置 int blur_cy; int w; int h; int pixel_range; int obj_cx; int range; int obj_cy; }; void init() { enabled_i = enabled; if (!enabled_i)return; { // Media object OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x00b5c1, 6); h.store_i16(0, '\x90\xe8'); // nop; call (rel32) h.replaceNearJmp(2, &media_mt_func); } { // Filter object OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x00bb39, 6); h.store_i16(0, '\x90\xe8'); // nop; call (rel32) h.replaceNearJmp(2, &filter_mt_func); } { // Filter object OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x00bb4f, 6); h.store_i16(0, '\x90\xe8'); // nop; call (rel32) h.replaceNearJmp(2, &filter_mt_far_func); } { // SceneChange OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x00c1ec, 6); h.store_i16(0, '\x90\xe8'); // nop; call (rel32) h.replaceNearJmp(2, &filter_mt_func); } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } RadiationalBlur; } // namespace patch::fast #endif // ifdef PATCH_SWITCH_FAST_RADIATIONALBLUR ================================================ FILE: patch/patch_fast_setting_dialog.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_fast_setting_dialog.hpp" #ifdef PATCH_SWITCH_FAST_SETTINGDIALOG #include //#define PATCH_STOPWATCH #include "stopwatch.hpp" namespace patch { static stopwatch_mem sw; void __cdecl fast_setting_dialog_t::FUN_10030500_Wrap() { sw.start(); auto hwnd = load_i32(GLOBAL::exedit_base + 0x1539c8); SendMessageA(hwnd, WM_SETREDRAW, FALSE, NULL); reinterpret_cast(GLOBAL::exedit_base + 0x030500)(); SendMessageA(hwnd, WM_SETREDRAW, TRUE, NULL); UpdateWindow(hwnd); sw.stop(); } BOOL __cdecl fast_setting_dialog_t::FUN_100305e0_Wrap(int param1) { sw.start(); auto hwnd = load_i32(GLOBAL::exedit_base + 0x1539c8); SendMessageA(hwnd, WM_SETREDRAW, FALSE, NULL); auto ret = reinterpret_cast(GLOBAL::exedit_base + 0x0305e0)(param1); SendMessageA(hwnd, WM_SETREDRAW, TRUE, NULL); UpdateWindow(hwnd); sw.stop(); return ret; } void __cdecl fast_setting_dialog_t::FUN_10030500_Wrap2() { sw.start(); auto hwnd = load_i32(GLOBAL::exedit_base + 0x1539c8); SendMessageA(hwnd, WM_SETREDRAW, FALSE, NULL); reinterpret_cast(GLOBAL::exedit_base + 0x030500)(); } BOOL __cdecl fast_setting_dialog_t::FUN_100305e0_Wrap2(int param1) { auto hwnd = load_i32(GLOBAL::exedit_base + 0x1539c8); auto ret = reinterpret_cast(GLOBAL::exedit_base + 0x0305e0)(param1); SendMessageA(hwnd, WM_SETREDRAW, TRUE, NULL); UpdateWindow(hwnd); sw.stop(); return ret; } void __cdecl fast_setting_dialog_t::FUN_10030500_Wrap3() { reinterpret_cast(GLOBAL::exedit_base + 0x030500)(); } void __cdecl fast_setting_dialog_t::FUN_1002bf10_Wrap(HDC hDC) { if (load_i32(GLOBAL::exedit_base + 0x1e0fa4) == nullptr) return; if (load_i32(GLOBAL::exedit_base + 0x177a10) == -1)return; reinterpret_cast(GLOBAL::exedit_base + 0x02bf10)(hDC); } } // namespace patch #endif // ifdef PATCH_SWITCH_FAST_SETTINGDIALOG ================================================ FILE: patch/patch_fast_setting_dialog.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FAST_SETTINGDIALOG #include "global.hpp" #include "util_magic.hpp" #include "global.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // 設定ダイアログの高速化 inline class fast_setting_dialog_t { static void __cdecl FUN_10030500_Wrap(); static BOOL __cdecl FUN_100305e0_Wrap(int param1); static void __cdecl FUN_10030500_Wrap2(); static BOOL __cdecl FUN_100305e0_Wrap2(int param1); static void __cdecl FUN_10030500_Wrap3(); static void __cdecl FUN_1002bf10_Wrap(HDC hDC); bool enabled = true; bool enabled_i; inline static const char key[] = "fast_settingdialog"; public: void init() { enabled_i = enabled; if (!enabled_i) return; // 単体呼び出し ReplaceNearJmp(GLOBAL::exedit_base + 0x0417c8, &FUN_10030500_Wrap); ReplaceNearJmp(GLOBAL::exedit_base + 0x04194a, &FUN_10030500_Wrap); ReplaceNearJmp(GLOBAL::exedit_base + 0x0419eb, &FUN_10030500_Wrap); ReplaceNearJmp(GLOBAL::exedit_base + 0x041b4f, &FUN_10030500_Wrap); ReplaceNearJmp(GLOBAL::exedit_base + 0x041c65, &FUN_10030500_Wrap); ReplaceNearJmp(GLOBAL::exedit_base + 0x02cd04, &FUN_100305e0_Wrap); ReplaceNearJmp(GLOBAL::exedit_base + 0x02da5d, &FUN_100305e0_Wrap); ReplaceNearJmp(GLOBAL::exedit_base + 0x03957d, &FUN_100305e0_Wrap); ReplaceNearJmp(GLOBAL::exedit_base + 0x0417d3, &FUN_100305e0_Wrap); ReplaceNearJmp(GLOBAL::exedit_base + 0x041956, &FUN_100305e0_Wrap); ReplaceNearJmp(GLOBAL::exedit_base + 0x0419f7, &FUN_100305e0_Wrap); ReplaceNearJmp(GLOBAL::exedit_base + 0x041b5a, &FUN_100305e0_Wrap); ReplaceNearJmp(GLOBAL::exedit_base + 0x041c71, &FUN_100305e0_Wrap); ReplaceNearJmp(GLOBAL::exedit_base + 0x041f52, &FUN_100305e0_Wrap); ReplaceNearJmp(GLOBAL::exedit_base + 0x08d75b, &FUN_100305e0_Wrap); // 30500の直後に305e0を呼ぶとき ReplaceNearJmp(GLOBAL::exedit_base + 0x041ade, &FUN_10030500_Wrap2); ReplaceNearJmp(GLOBAL::exedit_base + 0x041ae9, &FUN_100305e0_Wrap2); // 305e0中での30500の呼び出し //ReplaceNearJmp(GLOBAL::exedit_base + 0x0306ac, &FUN_10030500_Wrap3); // 2bf2c 例外対策 ReplaceNearJmp(GLOBAL::exedit_base + 0x02ceb7, &FUN_1002bf10_Wrap); // テキスト の行間等のコントロールの描画がおかしくなる //OverWriteOnProtectHelper(GLOBAL::exedit_base + 0x02e881, 4).store_i32(0, WS_EX_TOOLWINDOW | WS_EX_COMPOSITED); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } fast_setting_dialog; } // namespace patch #endif // ifdef PATCH_SWITCH_FAST_SETTINGDIALOG ================================================ FILE: patch/patch_fast_text.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_fast_text.hpp" #ifdef PATCH_SWITCH_FAST_TEXT #include "global.hpp" namespace patch::fast { HFONT __cdecl text_t::MyCreateFont(const char* fontname, int height, int weight, BOOL italic, BOOL high_precision, BOOL vertical) { HFONT& currentFont = load_i32(GLOBAL::exedit_base + 0x236388); height = -height; if (high_precision) { height *= 2; } char fontname_v[LF_FACESIZE + 1]; if (vertical) { fontname_v[0] = '@'; strncpy_s(fontname_v + 1, LF_FACESIZE + 1, fontname, LF_FACESIZE); fontname = fontname_v; } auto font = ::CreateFontA(height, 0, 0, 0, weight, italic, 0, 0, 1, 8, 0, 4, 0, fontname); if (font == NULL)return currentFont = NULL; LOGFONTW lfw; ::GetObjectW(font, sizeof(LOGFONTW), &lfw); std::lock_guard lock(text.mtx); auto [val, b] = text.map.try_emplace(lfw, font); if (!b) { ::DeleteObject(font); } return currentFont = val->second.font; } HFONT WINAPI text_t::CreateFontIndirectW(const LOGFONTW* lplf) { char facename[LF_FACESIZE]; auto const facename_size = ::WideCharToMultiByte(CP_ACP, 0U, lplf->lfFaceName, -1, nullptr, 0, nullptr, nullptr); if (::WideCharToMultiByte(CP_ACP, 0U, lplf->lfFaceName, -1, facename, sizeof(facename), nullptr, nullptr) == 0) { return NULL; } std::lock_guard lock(text.mtx); auto& map = text.map; if (auto itr = map.find(*lplf); itr != map.end()) { return itr->second.font; } return map.try_emplace(*lplf, ::CreateFontIndirectW(lplf)).first->second.font; } DWORD WINAPI text_t::GetGlyphOutlineW(HDC hdc, UINT uChar, UINT fuFormat, LPGLYPHMETRICS lpgm, DWORD cjBuffer, LPVOID pvBuffer, CONST MAT2* lpmat2) { auto font = reinterpret_cast(GetCurrentObject(hdc, OBJ_FONT)); LOGFONTW lfw; ::GetObjectW(font, sizeof(LOGFONTW), &lfw); std::lock_guard lock(text.mtx); auto itr = text.map.find(lfw); if (itr == text.map.end()) { return ::GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cjBuffer, pvBuffer, lpmat2); } auto& glyph = itr->second.glyph_map; GlyphKey glyphkey{ .uChar = uChar, .fuFormat = fuFormat }; auto itr2 = glyph.find(glyphkey); if (itr2 != glyph.end()) { auto& val = itr2->second; memcpy(lpgm, &val.gm, sizeof(GLYPHMETRICS)); if (cjBuffer && pvBuffer) { if (val.size == GDI_ERROR)return GDI_ERROR; memcpy_s(pvBuffer, cjBuffer, &val.data[0], val.size); } auto now = text_detail::gettime(); val.last_use = now; itr->second.last_use = now; return val.size; } auto size = ::GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, 0, nullptr, lpmat2); auto& val = glyph.try_emplace(glyphkey, size, text_detail::gettime(), lpgm, nullptr).first->second; if (size == GDI_ERROR)return GDI_ERROR; val.data.reset(new byte[size]); ::GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, size, val.data.get(), lpmat2); if (cjBuffer && pvBuffer) { if (val.size == GDI_ERROR)return GDI_ERROR; memcpy_s(pvBuffer, cjBuffer, &val.data[0], val.size); } return size; } BOOL WINAPI text_t::DeleteObject(HGDIOBJ ho) { std::lock_guard lock(text.mtx); for (const auto& v : text.map) { if (v.second.font == ho)return TRUE; } return ::DeleteObject(ho); } void text_t::collect(int elapse) { std::lock_guard lock(text.mtx); auto& font_map = text.map; auto now = text_detail::gettime(); #ifdef _DEBUG size_t count = 0; for (auto fitr = font_map.begin(); fitr != font_map.end();) { if (now - fitr->second.last_use > elapse) { printf("collected font\n"); font_map.erase(fitr++); } else { auto& glyph_map = fitr->second.glyph_map; for (auto gitr = glyph_map.begin(); gitr != glyph_map.end();) { if (now - gitr->second.last_use > elapse) { //printf("collected glyph\n"); glyph_map.erase(gitr++); } else { count += sizeof GlyphKey; count += sizeof GlyphValue; count += gitr->second.size; gitr++; } } count += sizeof LOGFONTW; count += sizeof FontValue; fitr++; } } printf("[lighttext]using memory: %dKB\n", count / 1000); #else for (auto fitr = font_map.begin(); fitr != font_map.end();) { if (now - fitr->second.last_use > elapse) { font_map.erase(fitr++); } else { auto& glyph_map = fitr->second.glyph_map; for (auto gitr = glyph_map.begin(); gitr != glyph_map.end();) { if (now - gitr->second.last_use > elapse) { glyph_map.erase(gitr++); } else { gitr++; } } fitr++; } } #endif } } #endif ================================================ FILE: patch/patch_fast_text.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FAST_TEXT #include #include #include #include #include #include #include "cryptostring.hpp" #include "util_magic.hpp" #include "timer.hpp" #include "config_rw.hpp" namespace patch::fast { namespace text_detail { inline auto gettime() { return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); } using FontKey = LOGFONTW; struct GlyphKey { UINT uChar; UINT fuFormat; }; inline bool operator<(const GlyphKey& l, const GlyphKey& r) { return std::tie(l.uChar, l.fuFormat) < std::tie(r.uChar, r.fuFormat); } struct GlyphValue { DWORD size = 0; time_t last_use = 0; GLYPHMETRICS gm; std::shared_ptr data; GlyphValue(DWORD size_, time_t time_, LPGLYPHMETRICS lpgm_, void* data_) :size(size_), last_use(time_) { memcpy(&gm, lpgm_, sizeof(GLYPHMETRICS)); if (size == GDI_ERROR)return; data = std::make_unique(size); if (data_) { memcpy(data.get(), data_, size_); } } }; struct FontValue { HFONT font; time_t last_use; std::map glyph_map; FontValue(HFONT font_) : font(font_), last_use(gettime()), glyph_map() {} ~FontValue() { DeleteObject(font); } }; inline std::strong_ordering operator<=>(const FontKey& a, const FontKey& b) { #define comp(member) if (auto cmp = a.##member <=> b.##member; cmp != 0) do { return cmp; } while(0) #define compb(member) \ if(a.##member == TRUE) { \ if(b.##member != TRUE) \ return std::strong_ordering::less; /*a==TRUE b==FALSE */ \ } else { \ if (b.##member == TRUE) \ return std::strong_ordering::greater; /*a==FALSE b==TRUE */ \ } comp(lfHeight); comp(lfWidth); comp(lfEscapement); comp(lfOrientation); comp(lfWeight); compb(lfItalic); compb(lfUnderline); compb(lfStrikeOut); comp(lfCharSet); comp(lfOutPrecision); comp(lfClipPrecision); comp(lfQuality); comp(lfPitchAndFamily); #undef comp #undef compb auto cmp = wcscmp(a.lfFaceName, b.lfFaceName); if (cmp < 0)return std::strong_ordering::less; if (cmp > 0)return std::strong_ordering::greater; return std::strong_ordering::equal; } struct comp_fontkey { bool operator()(const FontKey& a, const FontKey& b) const { return (a <=> b) < 0; } }; } inline class text_t { using FontKey = text_detail::FontKey; using FontValue = text_detail::FontValue; using GlyphKey = text_detail::GlyphKey; using GlyphValue = text_detail::GlyphValue; public: static HFONT __cdecl MyCreateFont(const char* fontname, int height, int weight, BOOL italic, BOOL high_precision, BOOL vertical); static HFONT WINAPI CreateFontIndirectW(const LOGFONTW* lplf); static BOOL WINAPI DeleteObject(HGDIOBJ ho); static DWORD WINAPI GetGlyphOutlineW(HDC hdc, UINT uChar, UINT fuFormat, LPGLYPHMETRICS lpgm, DWORD cjBuffer, LPVOID pvBuffer, CONST MAT2* lpmat2); void collect(int elapse); private: std::map map; std::mutex mtx; bool enabled = true; bool enabled_i; int release_time = 120; inline static const char key[] = "fast.text"; inline static const char key_release_time[] = "release_time"; public: void init() { enabled_i = enabled; if (!enabled_i)return; ExchangeFunction(GLOBAL::exedit_hmod, cstr_gdi32_dll.get(), cstr_GetGlyphOutlineW.get(), &GetGlyphOutlineW); ExchangeFunction(GLOBAL::exedit_hmod, cstr_gdi32_dll.get(), cstr_DeleteObject.get(), &DeleteObject); ExchangeFunction(GLOBAL::exedit_hmod, cstr_gdi32_dll.get(), cstr_CreateFontIndirectW.get(), &CreateFontIndirectW); ReplaceFunction(GLOBAL::exedit_base + 0x8a720, &MyCreateFont); timer.set([this]() { collect(release_time); }, release_time * 1000); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void config_load(ConfigReader& cr) { cr.regist(key_release_time, [this](json_value_s* value) { ConfigReader::load_variable(value, release_time); }); } void config_store(ConfigWriter& cw) { cw.append(key_release_time, release_time); } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } text; } #endif ================================================ FILE: patch/patch_fileinfo.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FILEINFO #include #include "config_rw.hpp" #include "global.hpp" #include "util.hpp" namespace patch { // init at patch load // ファイルの情報を開くと落ちるのを修正 inline class fileinfo_t { bool enabled = true; bool enabled_i; inline static const char key[] = "fileinfo"; public: void init() { enabled_i = enabled; if (!enabled_i)return; OverWriteOnProtectHelper h(GLOBAL::aviutl_base + 0x01c47a, 6); h.store_i16(0, '\x90\xb8'); h.store_i32(2, GLOBAL::aviutl_base + 0x0b87b0); /* 0041c47a 8b800c040000 mov eax,dword ptr[eax + 0x40c] ; editp+0x40c ↓ 0041c47a 90 nop 0041c47b b8XxXxXxXx mov eax,aviutl + 0xb87b0 ; eaxが本来はaviutl+0xb87b0でなければいけないのにプロジェクト保存時のアドレスを使っている */ } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } fileinfo; } // namespace patch #endif // ifdef PATCH_SWITCH_FILEINFO ================================================ FILE: patch/patch_font_dialog.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_FONT_DIALOG #include #include "global.hpp" namespace patch { // init at exedit load // フォント選択ダイアログを表示 // コンボボックスの右クリで適当なダイアログを召喚する inline class font_dialog_t { //inline static constexpr LPCWSTR class_name = L"PATCH_FONTDLG"; bool enabled = true; bool enabled_i; inline static const char key[] = "font_dialog"; public: void init() { enabled_i = enabled; if (!enabled_i)return; /*WNDCLASSW wc{ .style = 0, .lpfnWndProc = nullptr, .cbClsExtra = 0, .cbWndExtra = 0, .hInstance = GLOBAL::patchaul_hinst, .hIcon = NULL, .hCursor = NULL, .hbrBackground = HBRUSH(COLOR_BACKGROUND + 1), .lpszMenuName = NULL, .lpszClassName = class_name, }; RegisterClassW(&wc); */ } ~font_dialog_t() { //UnregisterClassW(class_name, GLOBAL::patchaul_hinst); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } font_dialog; } // namespace patch #endif // ifdef PATCH_SWITCH_FONT_DIALOG ================================================ FILE: patch/patch_helpful_msgbox.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_helpful_msgbox.hpp" #ifdef PATCH_SWITCH_HELPFUL_MSGBOX namespace patch { int WINAPI helpful_msgbox_t::MessageBoxAWrap(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) { std::optional localText, localCaption; UINT id = 0; if (auto itr = strptr2rid.find(lpText); itr != strptr2rid.end()) { id = itr->second; localText = resource_string_a(id); if (localText) lpText = localText->c_str(); } if (auto itr = strptr2rid.find(lpCaption); itr != strptr2rid.end()) { localCaption = resource_string_a(itr->second); if (localCaption)lpCaption = localCaption->c_str(); } return HelpedMsg(hWnd, lpText, lpCaption, uType, id); } int helpful_msgbox_t::HelpedMsg(HWND hwnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, UINT id) { MSGBOXPARAMSA param{ .cbSize = sizeof(param), .hwndOwner = hwnd, .hInstance = NULL, .lpszText = lpText, .lpszCaption = lpCaption, .dwStyle = uType | (id ? MB_HELP : 0), .dwContextHelpId = id, .lpfnMsgBoxCallback = [](LPHELPINFO hip) { const auto& itr = rid2md.find(hip->dwContextId); if (itr == rid2md.end()) { MessageBoxW(NULL, L"ヘルプは設定されていません", L"patch.aul", MB_ICONINFORMATION | MB_TASKMODAL); return; } const auto& data = itr->second; UrlConfirm(data.url); } }; return MessageBoxIndirectA(¶m); } void helpful_msgbox_t::UrlConfirm(std::wstring_view url) { auto ret = MessageBoxW(NULL, L"次のリンクを開こうとしています。同意しますか?\n{}"_fmt(url).c_str(), L"patch.aul", MB_ICONQUESTION | MB_YESNO | MB_TASKMODAL); switch (ret) { case IDYES: ShellExecuteW(NULL, L"open", url.data(), NULL, NULL, SW_SHOW); break; default: break; } } } // namespace patch #endif // ifdef PATCH_SWITCH_HELPFUL_MSGBOX ================================================ FILE: patch/patch_helpful_msgbox.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_HELPFUL_MSGBOX #include #include #include "cryptostring.hpp" #include "global.hpp" #include "util_resource.hpp" #include "util_magic.hpp" #include "restorable_patch.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // メッセージボックスの拡張 // メッセージの翻訳をしたりヘルプを表示したり inline class helpful_msgbox_t { struct MessageData { std::wstring url; }; // メッセージ文字列のポインタからメッセージID(リソースID)に変換 inline static std::unordered_map strptr2rid; // strptr2ridで拡張編集のオフセットのものだけ inline static std::pair strptr2rid_ofs_ee[]{ { reinterpret_cast(0x09da28), 10010 }, // "動画ファイルの読み込みに失敗しました\n対応していないフォーマットの可能性があります" }; // メッセージIDをMessageDataに変換 inline static std::unordered_map rid2md{ { 10010, { L"https://scrapbox.io/aviutl/**%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF%E3%81%AB%E5%A4%B1%E6%95%97%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F_%E5%AF%BE%E5%BF%9C%E3%81%97%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E3%81%AE%E5%8F%AF%E8%83%BD%E6%80%A7%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99" }}, }; static void UrlConfirm(std::wstring_view url); // ヘルプを表示できるメッセージボックス関数 static int HelpedMsg(HWND hwnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, UINT id); static int WINAPI MessageBoxAWrap(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType); bool enabled = true; inline static const char key[] = "helpful_msgbox"; std::optional rp; public: void init() { if (!enabled)return; for (auto& p : strptr2rid_ofs_ee) { strptr2rid.emplace(GLOBAL::exedit_base + p.first, p.second); } auto address = search_import(GLOBAL::exedit_hmod, cstr_user32_dll.get(), cstr_MessageBoxA.get()); rp.emplace(reinterpret_cast(address), reinterpret_cast(&MessageBoxAWrap)); } void switching(bool flag) { rp->switching(enabled = flag); } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } helpful_msgbox; } // namespace patch #endif // ifdef PATCH_SWITCH_HELPFUL_MSGBOX ================================================ FILE: patch/patch_ignore_media_param_reset.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_IGNORE_MEDIA_PARAM_RESET #include "global.hpp" #include "util_magic.hpp" #include "restorable_patch.hpp" namespace patch { // init at exedit load // 動画ファイル と 音声ファイル で中間点を打っていないときでもファイルを再参照しても再生位置などの情報を変更しない inline class ignore_media_param_reset_t { std::optional rp1; std::optional rp2; bool enabled = false; inline static const char key[] = "ignore_media_param_reset"; public: void init() { rp1.emplace(GLOBAL::exedit_base + OFS::ExEdit::ignore_media_param_reset_mov, '\x90\xe9'); rp2.emplace(GLOBAL::exedit_base + OFS::ExEdit::ignore_media_param_reset_aud, '\xeb'); rp1->switching(enabled); rp2->switching(enabled); } void switching(bool flag) { enabled = flag; rp1->switching(enabled); rp2->switching(enabled); } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } ignore_media_param_reset; } // namespace patch #endif // ifdef PATCH_SWITCH_IGNORE_MEDIA_PARAM_RESET ================================================ FILE: patch/patch_lua.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_lua.hpp" #ifdef PATCH_SWITCH_LUA #include #include "debug_log.hpp" #include "global.hpp" #include "offset_address.hpp" #include "patch_lua_getvalueex.hpp" #include "patch_lua_rand.hpp" #include "patch_lua_randex.hpp" namespace patch { static void assign_to_luastate(lua_State* L) { // _G, obj の順で積んでる lua_pushstring(L, PATCH_VERSION_NAME); lua_setfield(L, -3, "_PATCH"); #ifdef PATCH_SWITCH_LUA_RAND if (lua_rand.is_enabled_i()) lua_rand_t::require(L); #endif #ifdef PATCH_SWITCH_LUA_RANDEX if (lua_randex.is_enabled_i()) lua_randex_t::require(L); #endif #ifdef PATCH_SWITCH_LUA_GETVALUE if (lua_getvalueex.is_enabled_i()) lua_getvalueex_t::require(L); #endif } lua_State* __cdecl lua_t::luaGetOrCreateState(int idx) { if (idx > 1) return nullptr; auto LuaState = (lua_State**)(GLOBAL::exedit_base + 0x1baca8); auto& L = LuaState[idx]; if (L == nullptr) { auto loadLua = (BOOL(__cdecl*)())(GLOBAL::exedit_base + OFS::ExEdit::LoadLua); if (loadLua() != TRUE) return nullptr; auto mod = load_i32(GLOBAL::exedit_base + OFS::ExEdit::hmodule_lua); #define def(name) name=reinterpret_cast(GetProcAddress(mod, #name)) def(lua_isstring); def(lua_pushcclosure); def(lua_remove); def(lua_setmetatable); def(luaL_newmetatable); def(lua_pushvalue); #undef def L = luaL_newstate(); if (L == nullptr)return nullptr; luaL_openlibs(L); luaL_register(L, "_G", (luaL_Reg*)(GLOBAL::exedit_base + OFS::ExEdit::luaL_Reg_global_table)); luaL_register(L, "obj", (luaL_Reg*)(GLOBAL::exedit_base + OFS::ExEdit::luaL_Reg_obj_table)); assign_to_luastate(L); lua_pop(L, 2); } return L; } lua_State* __cdecl lua_t::luaGetOrCreateState_envpatch(int idx) { if(lua_t::state == nullptr) { auto loadLua = (BOOL(__cdecl*)())(GLOBAL::exedit_base + OFS::ExEdit::LoadLua); if(loadLua() != TRUE) return nullptr; auto mod = load_i32(GLOBAL::exedit_base + OFS::ExEdit::hmodule_lua); #define def(name) name=reinterpret_cast(GetProcAddress(mod, #name)) def(lua_isstring); def(lua_pushcclosure); def(lua_remove); def(lua_setmetatable); def(luaL_newmetatable); def(lua_pushvalue); #undef def auto state = luaL_newstate(); if(state == nullptr) return nullptr; lua_t::state = state; luaL_openlibs(state); luaL_register(state, "_G", (luaL_Reg*)(GLOBAL::exedit_base + OFS::ExEdit::luaL_Reg_global_table)); luaL_register(state, "obj", (luaL_Reg*)(GLOBAL::exedit_base + OFS::ExEdit::luaL_Reg_obj_table)); assign_to_luastate(state); lua_pop(state, 2); //inject_viewer(); return state; } return lua_t::state; } void __cdecl lua_t::luaUnload() { if(state) { lua_close(state); state = nullptr; } auto& hmod_lua = load_i32(GLOBAL::exedit_base + OFS::ExEdit::hmodule_lua); if(hmod_lua != NULL) { FreeLibrary(hmod_lua); hmod_lua = NULL; } } BOOL __cdecl lua_t::luaUpdatePath(lua_State* L) { //debug_log("luaUpdatePath()"); lua_getglobal(L, "package"); const auto exedit_dir = load_i32(GLOBAL::exedit_base + OFS::ExEdit::exeditdir); if(auto folder_name = load_i32(GLOBAL::exedit_base + OFS::ExEdit::sScriptFolderName); folder_name == nullptr || folder_name[0] == '\0') { lua_pushstring(L, "{0}?.lua;{0}script\\?.lua;{0}module\\?.lua;{0}module\\?\\init.lua"_fmt(exedit_dir).c_str()); lua_setfield(L, -2, "path"); lua_pushstring(L, "{0}?.dll;{0}script\\?.dll;{0}module\\?.dll"_fmt(exedit_dir).c_str()); lua_setfield(L, -2, "cpath"); } else { lua_pushstring(L, "{0}?.lua;{0}script\\?.lua;{0}script\\{1}\\?.lua;{0}module\\?.lua;{0}module\\?\\init.lua"_fmt(exedit_dir, folder_name).c_str()); lua_setfield(L, -2, "path"); lua_pushstring(L, "{0}?.dll;{0}script\\?.dll;{0}script\\{1}\\?.dll;{0}module\\?.dll"_fmt(exedit_dir, folder_name).c_str()); lua_setfield(L, -2, "cpath"); } lua_pop(L, 1); return TRUE; } double __cdecl lua_t::lua_tonumber_remove_stack(lua_State* L, int idx) { //view_stack(L, "hoge"); auto ret = lua_tonumber(L, idx); lua_remove(L, idx); //view_stack(L, "hoge"); return ret; } const char* __cdecl lua_t::lua_tolstring_remove_stack(lua_State* L, int idx, size_t* len) { auto ret = lua_tolstring(L, idx, len); lua_remove(L, idx); return ret; } static int luastateidx_internal = 0; BOOL __cdecl lua_t::DoScriptInit() { env::store(); luastateidx_internal++; store_i32(GLOBAL::exedit_base + OFS::ExEdit::luastateidx, (std::min)(luastateidx_internal, 1)); return TRUE; } BOOL __cdecl lua_t::DoScriptExit() { env::load(); luastateidx_internal--; store_i32(GLOBAL::exedit_base + OFS::ExEdit::luastateidx, (std::min)(luastateidx_internal, 1)); ((BOOL(__cdecl*)(lua_State*))(GLOBAL::exedit_base + OFS::ExEdit::SetLuaPathAndCpath))(luaGetOrCreateState_envpatch(0)); return TRUE; } } // namespace patch #endif // ifdef PATCH_SWITCH_LUA ================================================ FILE: patch/patch_lua.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_LUA #include #include #include #include #include "util.hpp" #include "global.hpp" #include "offset_address.hpp" #include "mylua.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // Luaの環境を一つにまとめる inline class lua_t { struct env { inline static constexpr std::ptrdiff_t target[] = { 0x1b2b4c, // sScriptFolderName 0x1b28d4, // obj_layer_ptr 0x1baca4, // script_objectp 0x1b2b20, // efpip_g 0x1b2368, // textbuffer_pointer 0x1b28b4, // textbuffer_max 0x1b2204, // textbuffer_current 0x1b28d0, // draw_state 0x1b249c, // something_drawstate1 0x1b24a0, // something_drawstate2 0x1b21e4, // draw_target 0x1b28dc, // some_flag 0x1b21f0, // obj_setanchor_called_count }; inline static constexpr std::ptrdiff_t target_tmp[] = { 0x1b24b4, // sScriptFolderName 0x1bac94, // obj_layer_ptr 0x1b2b08, // script_objectp 0x1b24b8, // efpip_g 0x1b28bc, // textbuffer_pointer 0x1b29f4, // textbuffer_max 0x1b21e0, // textbuffer_current 0x1bacb8, // draw_state 0x1b2494, // something_drawstate1 0x1b2498, // something_drawstate2 0x1b23bc, // draw_target 0x1b2b40, // some_flag 0x1b2b2c, // obj_setanchor_called_count }; std::array tmp; std::optional folder_name; inline static std::vector vec; static void load() { auto& e = vec.back(); for(size_t i = 0; i < std::size(target); i++) { store_i32(GLOBAL::exedit_base + target[i], e.tmp[i]); } if (vec.size()) { for (size_t i = 0; i < std::size(target); i++) { store_i32(GLOBAL::exedit_base + target_tmp[i], vec.back().tmp[i]); } } vec.pop_back(); } static void store() { vec.push_back({}); auto& e = vec.back(); for(size_t i = 0; i < std::size(target); i++) { auto val = load_i32(GLOBAL::exedit_base + target[i]); e.tmp[i] = val; store_i32(GLOBAL::exedit_base + target_tmp[i], val); } } }; inline static lua_State* state = nullptr; static lua_State* __cdecl luaGetOrCreateState(int idx); static lua_State* __cdecl luaGetOrCreateState_envpatch(int idx); static void __cdecl luaUnload(); static BOOL __cdecl luaUpdatePath(lua_State* L); static BOOL __cdecl DoScriptInit(); static BOOL __cdecl DoScriptExit(); static double __cdecl lua_tonumber_remove_stack(lua_State* L, int idx); inline static auto lua_tonumber_remove_stack_ptr = &lua_tonumber_remove_stack; static const char* __cdecl lua_tolstring_remove_stack(lua_State* L, int idx, size_t* len); inline static auto lua_tolstring_remove_stack_ptr = &lua_tolstring_remove_stack; bool enabled = true; bool enabled_i; inline static const char key[] = "lua"; bool env = false; bool env_i; inline static const char key_env[] = "lua.env"; bool path = false; bool path_i; inline static const char key_path[] = "lua.path"; public: void init() { enabled_i = enabled; env_i = env; path_i = path; if (!enabled_i)return; if (env_i) { ReplaceFunction(GLOBAL::exedit_base + OFS::ExEdit::GetOrCreateLuaState, &luaGetOrCreateState_envpatch); ReplaceFunction(GLOBAL::exedit_base + OFS::ExEdit::LuaUnload, &luaUnload); ReplaceFunction(GLOBAL::exedit_base + OFS::ExEdit::DoScriptInit, &DoScriptInit); ReplaceFunction(GLOBAL::exedit_base + OFS::ExEdit::DoScriptExit, &DoScriptExit); } else { ReplaceFunction(GLOBAL::exedit_base + OFS::ExEdit::GetOrCreateLuaState, &luaGetOrCreateState); } if (path_i) { ReplaceFunction(GLOBAL::exedit_base + OFS::ExEdit::SetLuaPathAndCpath, &luaUpdatePath); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::lua_pop_nop, 6); memset((void*)(GLOBAL::exedit_base + OFS::ExEdit::lua_pop_nop), '\x90', 6); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::lua_set_nop, 6); memset((void*)(GLOBAL::exedit_base + OFS::ExEdit::lua_set_nop), '\x90', 6); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::lua_tonumber_arg, 8); h.store_i8(0, 0xff); // (push) 0xff h.store_i32(4, &lua_tonumber_remove_stack_ptr); } OverWriteOnProtectHelper(GLOBAL::exedit_base + OFS::ExEdit::lua_tostring_calling1, 4).store_i32(0, &lua_tolstring_remove_stack_ptr); OverWriteOnProtectHelper(GLOBAL::exedit_base + OFS::ExEdit::lua_tostring_calling2, 4).store_i32(0, &lua_tolstring_remove_stack_ptr); OverWriteOnProtectHelper(GLOBAL::exedit_base + OFS::ExEdit::lua_tostring_calling3, 4).store_i32(0, &lua_tolstring_remove_stack_ptr); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } bool get_env() { return env; } bool get_env_i() { return env_i; } void set_env(bool x) { env = x; } bool get_path() { return path; } bool get_path_i() { return path_i; } void set_path(bool x) { path = x; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); cr.regist(key_env, [this](json_value_s* value) { ConfigReader::load_variable(value, env); }); cr.regist(key_path, [this](json_value_s* value) { ConfigReader::load_variable(value, path); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); cw.append(key_env, env); cw.append(key_path, path); } } lua; } // namespace patch #endif // ifdef PATCH_SWITCH_LUA ================================================ FILE: patch/patch_lua_getvalueex.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_lua_getvalueex.hpp" #ifdef PATCH_SWITCH_LUA_GETVALUE #include "offset_address.hpp" namespace patch { int __cdecl lua_getvalueex_t::lua_getvalue_override(lua_State* L) { //lua_t::states.push_back(L); int layer_idx = 0; int target_i = 0; auto efpip = load_i32(GLOBAL::exedit_base + OFS::ExEdit::efpip_g); auto ScriptProcessingFilter = load_i32(GLOBAL::exedit_base + OFS::ExEdit::ScriptProcessingFilter); int n = lua_gettop(L); int frame; int subframe; if (n < 2) { frame = efpip->frame_num; subframe = efpip->subframe; } else { double time = luaL_checknumber(L, 2); double frame_before_round = time * efpip->framerate_nu / efpip->framerate_de; frame = static_cast(floor(frame_before_round)); subframe = static_cast(floor((frame_before_round - frame) * 100.0)); if (n < 3) { frame += ScriptProcessingFilter->frame_start_chain; } else { int section = luaL_checkinteger(L, 3); if (section < 0) { frame += ScriptProcessingFilter->frame_end_chain; } else { //exfunc_10; auto ps = reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::exfunc_10)(ScriptProcessingFilter->processing); while (section) { //exfunc_08 ps = reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::exfunc_08)(ps); section--; } if (is_valid(ps)) { // func_0x047ad0 frame += reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::func_0x047ad0)(ps, 0)->frame_begin; } else { frame += ScriptProcessingFilter->frame_end_chain; } } } } int track_idx; int result_nu, result_de; if (lua_isnumber(L, 1)) { int target = luaL_checkinteger(L, 1); if (target < 0)return 0; if (ScriptProcessingFilter->track_n <= target)return 0; reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::exfunc_64)(ScriptProcessingFilter->processing, frame, subframe, &result_nu, target + 1); result_de = 100; } else { const char* target = luaL_checkstring(L, 1); if (lstrcmpiA(target, "scenechange") == 0) { lua_pushnumber(L, load_i32(GLOBAL::exedit_base + OFS::ExEdit::scenechange_progress_times4096) / 4096.0); return 1; } ExEdit::ObjectFilterIndex ps; if (strncmp(target, "layer", 5) == 0) { target += 5; int layer_idx = 0; while (*target != '.') { uint8_t i = (uint8_t)*target - (uint8_t)'0'; if (i > 9) { layer_idx = -1; break; } layer_idx = layer_idx * 10 + i; target++; } if (layer_idx < 1 && 100 < layer_idx) return 0; target++; // ef0x1c ps = reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::exfunc_1c)(frame, layer_idx - 1, ScriptProcessingFilter->scene_set, 0, 0x10); } else { // GetCurrentProcessing ps = reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::GetCurrentProcessing)(efpip); } if (!is_valid(ps))return 0; int a; // FUN_10047ad0 auto eop = reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::func_0x047ad0)(ps, &a); auto efp = reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::LoadedFilterTable)[eop->filter_param[a].id]; if (efp->track_gui == nullptr)return 0; #if 1 char target2[7]; { int i = 0; do{ if(target[i] == '\0') { target2[i] = '\0'; goto BREAK; } target2[i] = target[i] | 0b10'0000; // to lower i++; } while(i < 7); return 0; BREAK: ; } switch(target2[0]) { case 'a': // alpha aspect if(*(int*)(target2 + 1) == 'ahpl') { if(target2[5] != '\0') return 0; // alpha result_de = 100; track_idx = efp->track_gui->alpha; if (track_idx < 0) return lua_pushnumber(L, 0), 1; //exfunc_64 reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::exfunc_64)(ps, frame, subframe, &result_nu, track_idx + 1); lua_pushnumber(L, 1. - result_nu * 0.001); return 1; } if(*(int*)(target2 + 1) == 'ceps') { if(*(short*)(target2 + 5) != '\0t') return 0; // aspect result_de = 1000; track_idx = efp->track_gui->aspect; if (track_idx < 0) return lua_pushnumber(L, 0), 1; break; } return 0; case 'c': // cx cy cz switch(*(short*)(target2 + 1)) { case '\0x': result_de = 10; track_idx = efp->track_gui->cx; if (track_idx < 0) return lua_pushnumber(L, 0), 1; break; case '\0y': result_de = 10; track_idx = efp->track_gui->cy; if (track_idx < 0) return lua_pushnumber(L, 0), 1; break; case '\0z': result_de = 10; track_idx = efp->track_gui->cz; if (track_idx < 0) return lua_pushnumber(L, 0), 1; break; default: return 0; } break; case 't': // time if(*(int*)(target2 + 1) != '\0emi') return 0; if (auto leader = eop->index_midpt_leader; leader >= 0) { eop = load_i32(GLOBAL::exedit_base + OFS::ExEdit::ObjectArrayPointer) + leader; } lua_pushnumber(L, (subframe * 0.01 + (double)(frame - eop->frame_begin))* (double)efpip->framerate_de / (double)efpip->framerate_nu); //lua_pushnumber(L, (subframe * 0.01 + (double)(frame - ScriptProcessingFilter->frame_start_chain)) * (double)efpip->framerate_de / (double)efpip->framerate_nu); return 1; case 'r': // rx ry rz switch(*(short*)(target2 + 1)) { case '\0x': result_de = 100; track_idx = efp->track_gui->rx; if (track_idx < 0) return lua_pushnumber(L, 0), 1; break; case '\0y': result_de = 100; track_idx = efp->track_gui->ry; if (track_idx < 0) return lua_pushnumber(L, 0), 1; break; case '\0z': result_de = 100; track_idx = efp->track_gui->rz; if (track_idx < 0) return lua_pushnumber(L, 0), 1; break; default: return 0; } break; case 'x': if(target2[1] != '\0') return 0; result_de = 10; track_idx = efp->track_gui->bx; if (track_idx < 0) return lua_pushnumber(L, 0), 1; break; case 'y': if(target2[1] != '\0') return 0; result_de = 10; track_idx = efp->track_gui->by; if (track_idx < 0) return lua_pushnumber(L, 0), 1; break; case 'z': // z zoom if(target2[1] == '\0') { // z result_de = 10; track_idx = efp->track_gui->bz; if (track_idx < 0) return lua_pushnumber(L, 0), 1; break; } else if(*(int*)(target2 + 1) == '\0moo') { //zoom result_de = 100; track_idx = efp->track_gui->zoom; if (track_idx < 0) return lua_pushnumber(L, 0), 1; break; } return 0; default: return 0; } #else if (lstrcmpiA(target, "x") == 0) { result_de = 10; track_idx = efp->track_gui->bx; if (track_idx < 0) return lua_pushnumber(L, 0), 1; } else if (lstrcmpiA(target, "y") == 0) { result_de = 10; track_idx = efp->track_gui->by; if (track_idx < 0) return lua_pushnumber(L, 0), 1; } else if (lstrcmpiA(target, "z") == 0) { result_de = 10; track_idx = efp->track_gui->bz; if (track_idx < 0) return lua_pushnumber(L, 0), 1; } else if (lstrcmpiA(target, "zoom") == 0) { result_de = 100; track_idx = efp->track_gui->zoom; if (track_idx < 0) return lua_pushnumber(L, 0), 1; } else if (lstrcmpiA(target, "rx") == 0) { result_de = 100; track_idx = efp->track_gui->rx; if (track_idx < 0) return lua_pushnumber(L, 0), 1; } else if (lstrcmpiA(target, "ry") == 0) { result_de = 100; track_idx = efp->track_gui->ry; if (track_idx < 0) return lua_pushnumber(L, 0), 1; } else if (lstrcmpiA(target, "rz") == 0) { result_de = 100; track_idx = efp->track_gui->rz; if (track_idx < 0) return lua_pushnumber(L, 0), 1; } else if (lstrcmpiA(target, "cx") == 0) { result_de = 10; track_idx = efp->track_gui->cx; if (track_idx < 0) return lua_pushnumber(L, 0), 1; } else if (lstrcmpiA(target, "cy") == 0) { result_de = 10; track_idx = efp->track_gui->cy; if (track_idx < 0) return lua_pushnumber(L, 0), 1; } else if (lstrcmpiA(target, "cz") == 0) { result_de = 10; track_idx = efp->track_gui->cz; if (track_idx < 0) return lua_pushnumber(L, 0), 1; } else if (lstrcmpiA(target, "alpha") == 0) { result_de = 100; track_idx = efp->track_gui->alpha; if (track_idx < 0) return lua_pushnumber(L, 0), 1; //exfunc_64 reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::exfunc_64)(ps, frame, subframe, &result_nu, track_idx + 1); lua_pushnumber(L, 1. - result_nu * 0.001); return 1; } else if (lstrcmpiA(target, "aspect") == 0) { result_de = 1000; track_idx = efp->track_gui->aspect; if (track_idx < 0) return lua_pushnumber(L, 0), 1; } else if (lstrcmpiA(target, "time") == 0) { lua_pushnumber(L, (subframe * 0.01 + (double)(frame - ScriptProcessingFilter->frame_start_chain)) * (double)efpip->framerate_de / (double)efpip->framerate_nu); return 1; } else return 0; #endif reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::exfunc_64)(ps, frame, subframe, &result_nu, track_idx + 1); } lua_pushnumber(L, static_cast(result_nu) / static_cast(result_de)); return 1; } int __cdecl lua_getvalueex_t::lua_getvalueex_main(lua_State* L) { return 1; } } // namespace patch #endif // #ifdef PATCH_SWITCH_GETVALUEEX ================================================ FILE: patch/patch_lua_getvalueex.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_LUA_GETVALUE #include #include "global.hpp" #include "util.hpp" #include "config_rw.hpp" #include "mylua.hpp" namespace patch { // obj.getvalue で中心座標をもらえるようにする inline class lua_getvalueex_t { static int __cdecl lua_getvalue_override(lua_State* L); // index static int __cdecl lua_getvalueex_main(lua_State* L); bool enabled = true; bool enabled_i; inline static const char key[] = "lua.getvalue"; public: void init() { enabled_i = enabled; } inline static void require(lua_State* L) { lua_pushcfunction(L, &lua_getvalue_override); lua_setfield(L, -2, "getvalue"); lua_pushcfunction(L, &lua_getvalueex_main); lua_setfield(L, -2, "getvalueex"); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } lua_getvalueex; } // namespace patch #endif // ifdef PATCH_SWITCH_LUA_GETVALUE ================================================ FILE: patch/patch_lua_rand.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_lua_rand.hpp" #ifdef PATCH_SWITCH_LUA_RAND #include #include "global.hpp" #include "offset_address.hpp" namespace patch { int lua_rand_t::l_rand_overwrite(lua_State* L) { int s = luaL_checkinteger(L, 1); int e = luaL_checkinteger(L, 2); if (s > e) std::swap(s, e); int seed, time; if (auto efpip = load_i32(GLOBAL::exedit_base + OFS::ExEdit::efpip_g); efpip != nullptr) { seed = efpip->obj_layerp->layer_set * 1913 ^ efpip->obj_index * 757; time = efpip->frame - efpip->object_start_frame; }else { seed = load_i32(GLOBAL::exedit_base + OFS::ExEdit::TraScript_ProcessingObjectIndex) * 1913 ^ load_i32(GLOBAL::exedit_base + OFS::ExEdit::TraScript_ProcessingTrackBarIndex) * 757; time = static_cast(load_i64(GLOBAL::exedit_base + OFS::ExEdit::TraScript_Time)); } auto n = lua_gettop(L); if(n > 2) { auto seed_a = luaL_checkinteger(L, 3); if(seed_a < 0) seed = -seed_a; else seed += seed_a; if(n > 3) time = luaL_checkinteger(L, 4); } auto a = seed + (time << 7 ^ time >> 2 ^ time); auto b = (a * 73 ^ 326881591) + a % 7213 + a; auto c = b ^ b * 128 ^ (int)b >> 2; auto d = (int)((int)c >> 0x10 ^ c); if (s == (std::numeric_limits::min)() && e == (std::numeric_limits::max)()) lua_pushinteger(L, d); else lua_pushinteger(L, s + d % (e - s + 1)); return 1; } } // namespace patch #endif // ifdef PATCH_SWITCH_LUA_RAND ================================================ FILE: patch/patch_lua_rand.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_LUA_RAND #include "config_rw.hpp" #include "mylua.hpp" namespace patch { // rand関数が0除算例外になるパターンを潰す inline class lua_rand_t { static int l_rand_overwrite(lua_State* L); bool enabled = true; bool enabled_i; inline static const char key[] = "lua.rand"; public: void init() { enabled_i = enabled; } static void require(lua_State* L) { lua_pushcfunction(L, &l_rand_overwrite); lua_setfield(L, -3, "rand"); lua_pushcfunction(L, &l_rand_overwrite); lua_setfield(L, -2, "rand"); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } lua_rand; } // namespace patch #endif // ifdef PATCH_SWITCH_LUA_RAND ================================================ FILE: patch/patch_lua_randex.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_lua_randex.hpp" #ifdef PATCH_SWITCH_LUA_RANDEX #include #include "util_magic.hpp" #include "offset_address.hpp" namespace patch { int lua_randex_t::l_randex(lua_State* L) { int seed, time; if (auto efpip = *(ExEdit::FilterProcInfo**)(GLOBAL::exedit_base + OFS::ExEdit::efpip_g); efpip != nullptr) { seed = efpip->obj_layerp->layer_set * 1913 ^ efpip->obj_index * 757; time = efpip->frame - efpip->object_start_frame; } else { seed = load_i32(GLOBAL::exedit_base + OFS::ExEdit::TraScript_ProcessingObjectIndex) * 1913 ^ load_i32(GLOBAL::exedit_base + OFS::ExEdit::TraScript_ProcessingTrackBarIndex) * 757; time = static_cast(load_i64(GLOBAL::exedit_base + OFS::ExEdit::TraScript_Time)); } auto n = lua_gettop(L); if (n > 0) { auto seed_a = luaL_checkinteger(L, 1); if (seed_a < 0) seed = -seed_a; else seed += seed_a; if (n > 1) time = luaL_checkinteger(L, 2); } create_object(L, seed, time); return 1; } #endif } ================================================ FILE: patch/patch_lua_randex.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_LUA_RANDEX #include #include "config_rw.hpp" #include "mylua.hpp" namespace patch { // 正しい乱数分布になるようなrandexクラスを追加 inline class lua_randex_t { struct Xoshiro128pp { uint32_t s[4]; Xoshiro128pp(unsigned int seed1, unsigned int seed2) : s{ seed1,seed2,1000000007,998244353 } { for (int i = 0; i < 32; i++) calc(); } uint32_t calc() { auto ret = std::rotl(s[0] + s[3], 7) + s[0]; auto t = s[1] << 9; s[2] ^= s[0]; s[3] ^= s[1]; s[1] ^= s[2]; s[0] ^= s[3]; s[2] ^= t; s[3] = std::rotl(s[3], 11); return ret; } int calc(int s, int e) { auto r = calc(); if (s > e) std::swap(s, e); if (s == (std::numeric_limits::min)() && e == (std::numeric_limits::max)()) return std::bit_cast(r); return s + r % (e - s + 1); } }; static int l_randex(lua_State* L); static void setmetatable(lua_State* L, int index) { luaL_getmetatable(L, "randex"); lua_setmetatable(L, index > 0 ? index : index - 1); } static Xoshiro128pp* create_object(lua_State* L, int seed, int time) { auto udata = lua_newuserdata(L, sizeof(Xoshiro128pp)); auto rnd = new(udata) Xoshiro128pp(seed, time); setmetatable(L, -1); return rnd; } bool enabled = true; bool enabled_i; inline static const char key[] = "lua.randex"; public: void init() { enabled_i = enabled; } static void require(lua_State* L) { luaL_newmetatable(L, "randex"); lua_pushcclosure(L, [](lua_State* L) { auto rnd = static_cast(lua_touserdata(L, 1)); int s = luaL_checkinteger(L, 2); int e = luaL_checkinteger(L, 3); lua_pushinteger(L, rnd->calc(s, e)); return 1; }, 0); lua_setfield(L, -2, "__call"); lua_pop(L, 1); lua_pushcfunction(L, l_randex); lua_setfield(L, -3, "randex"); lua_pushcfunction(L, l_randex); lua_setfield(L, -2, "randex"); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } lua_randex; } #endif ================================================ FILE: patch/patch_obj_colorcorrection.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_obj_colorcorrection.hpp" #include #ifdef PATCH_SWITCH_OBJ_COLORCORRECTION namespace patch { /**/ void rgb2hsv_12(int r, int g, int b, int* h, int* s, int* v) { int rgbmax = (std::max)({ r, g, b }); int rgbsub = rgbmax - (std::min)({ r, g, b }); if (rgbsub) { if (rgbmax == r) { *h = 600 * (g - b) / rgbsub; } else if (rgbmax == g) { *h = 600 * (b - r) / rgbsub + 1200; } else { *h = 600 * (r - g) / rgbsub + 2400; } if (rgbmax) { *s = 4096 * rgbsub / rgbmax; } else { *s = 0; } } else { *h = 0; *s = 0; } *v = rgbmax; } /*/ void rgb2hsv_12(int r, int g, int b, int* h, int* s, int* v) { constexpr auto half_sqrt3 = 0.86602540378443864676372317075294; const auto vx = (r * 2 - (g + b)) * .5; const auto vy = (g - b) * half_sqrt3; const auto ht = static_cast(std::round(std::atan2(vy, vx) * (3600 / (std::numbers::pi * 2)))); if (ht < 0) *h = ht + 3600; else *h = ht; const auto mx = (std::max)({ r,g,b }); const auto mn = (std::min)({ r,g,b }); if (mx) { *s = (mx - mn) * 4096 / mx; } else { *s = 0; } *v = mx; } //*/ void yc2rgb_12(int y, int cb, int cr, int* r, int* g, int* b) { *r = y + (cr * 11485 >> 13); *g = y - ((cb * 2818 + cr * 5849) >> 13); *b = y + (cb * 14516 >> 13); } void yc2hsv_12(int y, int cb, int cr, int* h, int* s, int* v) { int r, g, b; yc2rgb_12(y, cb, cr, &r, &g, &b); rgb2hsv_12(r, g, b, h, s, v); } /**/ void hsv2rgb_12(int h, int s, int v, int* r, int* g, int* b) { h %= 3600; if (h < 0) { h += 3600; } int tmp = v * s; int rgbmin = v - (tmp >> 12); switch (h / 600) { case 0: *r = v; *g = v - (tmp / 75 * (600 - h) >> 15); *b = rgbmin; break; case 1: *r = v - (tmp / 75 * (h - 600) >> 15); *g = v; *b = rgbmin; break; case 2: *r = rgbmin; *g = v; *b = v - (tmp / 75 * (1800 - h) >> 15); break; case 3: *r = rgbmin; *g = v - (tmp / 75 * (h - 1800) >> 15); *b = v; break; case 4: *r = v - (tmp / 75 * (3000 - h) >> 15); *g = rgbmin; *b = v; break; case 5: *r = v; *g = rgbmin; *b = v - (tmp / 75 * (h - 3000) >> 15); break; } } /*/ void hsv2rgb_12(int h, int s, int v, int* r, int* g, int* b) { h %= 3600; const auto mx = v; const auto mn = v * (4096 - s) / 4096; const auto mxf = mx / 4096.; const auto mnf = mn / 4096.; constexpr auto pi = std::numbers::pi; const auto h_rad = h * (pi * 2 / 3600.); const auto sinh = std::sin(h_rad); const auto cosh = std::cos(h_rad); constexpr auto sqrt3_d2 = .86602540378443864676372317075294; const auto ar = sinh; const auto ag = cosh * sqrt3_d2 + sinh * .5; const auto ab = cosh * sqrt3_d2 - sinh * .5; double rf, gf, bf; if (h_rad < pi / 3) { *r = mx; *b = mn; rf = mxf; bf = mnf; gf = (ar * rf + ab * bf) / ag; *g = static_cast(std::round(gf * 4096)); } else if (h_rad < pi * 2 / 3) { *g = mx; *b = mn; gf = mxf; bf = mnf; rf = (ag * gf - ab * bf) / ar; *r = static_cast(std::round(rf * 4096)); } else if (h_rad < pi) { *g = mx; *r = mn; gf = mxf; rf = mnf; bf = (ag * gf - ar * rf) / ab; *b = static_cast(std::round(bf * 4096)); } else if (h_rad < pi * 4 / 3) { *b = mx; *r = mn; bf = mxf; rf = mnf; gf = (ar * rf + ab * bf) / ag; *g = static_cast(std::round(gf * 4096)); } else if (h_rad < pi * 5 / 3) { *b = mx; *g = mn; bf = mxf; gf = mnf; rf = (ag * gf - ab * bf) / ar; *r = static_cast(std::round(rf * 4096)); } else { *r = mx; *g = mn; rf = mxf; gf = mnf; bf = (ag * gf - ar * rf) / ab; *b = static_cast(std::round(bf * 4096)); } } //*/ void rgb2yc_12(int r, int g, int b, int* y, int* cb, int* cr) { *y = (r * 4898 + g * 9617 + b * 1867) >> 14; *cb = (r * -2768 + g * -5423 + b * 8192) >> 14; *cr = (r * 8192 + g * -6864 + b * -1327) >> 14; } void hsv2yc_12(int h, int s, int v, int* y, int* cb, int* cr) { int r, g, b; hsv2rgb_12(h, s, v, &r, &g, &b); rgb2yc_12(r, g, b, y, cb, cr); } void __cdecl obj_ColorCorrection_t::rot_hue(ExEdit::PixelYC* pix, int angle10, int luminance, int brightness, int saturation) { int h, s, v; yc2hsv_12(pix->y, pix->cb, pix->cr, &h, &s, &v); h += angle10; int y, cb, cr; hsv2yc_12(h, s, v, &y, &cb, &cr); pix->y = (y * luminance >> 8) + brightness; pix->cb = cb * saturation >> 8; pix->cr = cr * saturation >> 8; } void __cdecl obj_ColorCorrection_t::rot_hue_sat(ExEdit::PixelYC* pix, int angle10, int luminance, int brightness, int saturation) { rot_hue(pix, angle10, luminance, brightness, saturation); if (pix->y < 0) { int ysub = pix->y + 0x400; if (0 < ysub) { pix->cb = ysub * pix->cb >> 10; pix->cr = ysub * pix->cr >> 10; } else { pix->cb = pix->cr = 0; } pix->y = 0; } else if (0x2000 < pix->y) { int ysub = 0x3000 - pix->y; if (0 < ysub) { pix->cb = ysub * pix->cb >> 12; pix->cr = ysub * pix->cr >> 12; } else { pix->cb = pix->cr = 0; } pix->y = 0x2000; } } } // namespace patch #endif // ifdef PATCH_SWITCH_OBJ_COLORCORRECTION ================================================ FILE: patch/patch_obj_colorcorrection.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_OBJ_COLORCORRECTION #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // 色調補正の色相計算が正しくないのを修正 inline class obj_ColorCorrection_t { static void rot_hue(ExEdit::PixelYC* pix, int angle10, int luminance, int brightness, int saturation); static void rot_hue_sat(ExEdit::PixelYC* pix, int angle10, int luminance, int brightness, int saturation); bool enabled = true; bool enabled_i; inline static const char key[] = "obj_colorcorrection"; public: void init() { enabled_i = enabled; if (!enabled_i)return; { // メディアオブジェクト char code_effect[] = "\x8b\x44\x24\x2c" // mov eax,dword ptr [esp+2c] ; efp "\x8b\x48\x44" // mov ecx,dword ptr [eax+44] ; efp->track "\x8b\x41\x08" // mov eax,dword ptr [ecx+08] ; efp->track[2] "\x53" // push ebx "\x57" // push edi "\xff\x74\x24\x38" // push dword ptr [esp+38] "\x50" // push eax "\x56" // push esi "\xe8XXXX" // call rot_hue() "\x83\xc4\x14" // add esp,+14 "\xe9\x8d\x00\x00\x00" // jmp 10014996 ; OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x148ea, sizeof(code_effect) - 1); memcpy(reinterpret_cast(h.address()), code_effect, sizeof(code_effect) - 1); h.replaceNearJmp(19, rot_hue); } { // メディアオブジェクト // 飽和する { char code_effect_sat[] = "\x8b\x44\x24\x34" // mov eax,dword ptr [esp+34] ; efp "\x8b\x48\x44" // mov ecx,dword ptr [eax+44] ; efp->track "\x8b\x41\x08" // mov eax,dword ptr [ecx+08] ; efp->track[2] "\xff\x74\x24\x2c" // push dword ptr [esp+2c] "\xff\x74\x24\x28" // push dword ptr [esp+28] "\xff\x74\x24\x18" // push dword ptr [esp+18] "\x50" // push eax "\x53" // push ebx "\xe8XXXX" // call rot_hue_sat() "\x83\xc4\x14" // add esp,+14 "\x8b\x44\x24\x38" // mov eax,dword ptr [esp+38] ; efpip "\xe9\xea\x00\x00\x00" // jmp 10014f8c ; OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x14e79, sizeof(code_effect_sat) - 1); memcpy(reinterpret_cast(h.address()), code_effect_sat, sizeof(code_effect_sat) - 1); h.replaceNearJmp(25, rot_hue_sat); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x14e3b, 1); h.store_i8(0, 0x1c); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x14fa9, 1); h.store_i8(0, 0x1c); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x14fb4, 1); h.store_i8(0, 0x1c); } } { // フィルタオブジェクト char code_filter[] = "\x8b\x44\x24\x2c" // mov eax,dword ptr [esp+2c] ; efp "\x8b\x48\x44" // mov ecx,dword ptr [eax+44] ; efp->track "\x8b\x41\x08" // mov eax,dword ptr [ecx+08] ; efp->track[2] "\x57" // push edi "\x55" // push ebp "\xff\x74\x24\x38" // push dword ptr [esp+38] "\x50" // push eax "\x56" // push esi "\xe8XXXX" // call rot_hue() "\x83\xc4\x14" // add esp,+14 "\x8b\x4c\x24\x18" // mov ecx,dword ptr [esp+18] ; x "\x83\xc6\x06" // add esi,+06 "\xe9\x8e\x00\x00\x00" // jmp 10014c67 ; OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x14bb3, sizeof(code_filter) - 1); memcpy(reinterpret_cast(h.address()), code_filter, sizeof(code_filter) - 1); h.replaceNearJmp(19, rot_hue); } { // フィルタオブジェクト 飽和する { char code_filter_sat[] = "\x8b\x44\x24\x34" // mov eax,dword ptr [esp+34] ; efp "\x8b\x48\x44" // mov ecx,dword ptr [eax+44] ; efp->track "\x8b\x41\x08" // mov eax,dword ptr [ecx+08] ; efp->track[2] "\xff\x74\x24\x10" // push dword ptr [esp+10] "\xff\x74\x24\x28" // push dword ptr [esp+28] "\xff\x74\x24\x34" // push dword ptr [esp+34] "\x50" // push eax "\x53" // push ebx "\xe8XXXX" // call rot_hue_sat() "\x83\xc4\x14" // add esp,+14 "\x8b\x4c\x24\x30" // mov ecx,dword ptr [esp+30] "\x8b\x44\x24\x38" // mov eax,dword ptr [esp+38] ; efpip "\xe9\xea\x00\x00\x00" // jmp 10015354 ; OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x1523d, sizeof(code_filter_sat) - 1); memcpy(reinterpret_cast(h.address()), code_filter_sat, sizeof(code_filter_sat) - 1); h.replaceNearJmp(25, rot_hue_sat); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x15210, 1); h.store_i8(0, 0x1c); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x1536e, 1); h.store_i8(0, 0x1c); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x1537b, 1); h.store_i8(0, 0x1c); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x1545e, 1); h.store_i8(0, 0x1c); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x15469, 1); h.store_i8(0, 0x1c); } } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } ColorCorrection; } // namespace patch #endif // ifdef PATCH_SWITCH_OBJ_COLORCORRECTION ================================================ FILE: patch/patch_obj_glow.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_OBJ_GLOW #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // グローのバグ修正 /* オフセットアドレス exedit + 55625 の修正 曲線移動などで しきい値 が負の数になった時にエラーが出る */ /* 小さいオブジェクトに効果が無いのを修正 スレッド数より小さいオブジェクトに効果が乗らない */ inline class obj_Glow_t { bool enabled = true; bool enabled_i; inline static const char key[] = "obj_glow"; public: void init() { enabled_i = enabled; if (!enabled_i)return; { // オフセットアドレス exedit + 55625 の修正 auto& cursor = GLOBAL::executable_memory_cursor; OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x054ed5, 6); h.store_i16(0, '\x90\xe8'); h.replaceNearJmp(2, cursor); /* 10054ed5 8b4908 mov ecx,dword ptr [ecx+08] 10054ed8 c1e10c shl ecx,0c ↓ 10054ed5 90 nop 10054ed6 e8xXxXxXxX call &executable_memory_cursor ; しきい値 track[2] が0未満の時に0にする */ static const char code_put[] = "\x8b\x49\x08" // mov ecx,dword ptr [ecx+08] "\x85\xc9" // test ecx,ecx "\x7c\x04" // jl skip,4 "\xc1\xe1\x0c" // shl ecx,0c "\xc3" // ret "\x33\xc9" // xor ecx,ecx "\xc3" // ret ; memcpy(cursor, code_put, sizeof(code_put) - 1); cursor += sizeof(code_put) - 1; } { // 小さいオブジェクトに効果が無いのを修正 { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x055572, 2); h.store_i16(0, '\xeb\x0a'); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x0556c0, 2); h.store_i16(0, '\xeb\x0a'); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x0557d0, 2); h.store_i16(0, '\xeb\x0a'); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x055910, 2); h.store_i16(0, '\xeb\x0a'); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x055a54, 1); h.store_i8(0, '\xeb'); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x055cb6, 1); h.store_i8(0, '\xeb'); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x055f0e, 2); h.store_i16(0, '\xeb\x0a'); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x056258, 1); h.store_i8(0, '\xeb'); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x056a18, 1); h.store_i8(0, '\xeb'); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x05710c, 1); h.store_i8(0, '\xeb'); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x05776d, 1); h.store_i8(0, '\xeb'); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x057dcc, 1); h.store_i8(0, '\xeb'); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x05846c, 1); h.store_i8(0, '\xeb'); } } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } Glow; } // namespace patch #endif // ifdef PATCH_SWITCH_OBJ_GLOW ================================================ FILE: patch/patch_obj_lensblur.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_obj_lensblur.hpp" #ifdef PATCH_SWITCH_OBJ_LENSBLUR namespace patch { void* __cdecl obj_LensBlur_t::lbResize_709a0_wrap_12809(void* pix_edit, int w0, int h0, int w1, int h1, void* pix_temp) { if (w0 && h0 && w1 && h1) { return reinterpret_cast(GLOBAL::exedit_base + 0x0709a0)(pix_edit, w0, h0, w1, h1, pix_temp); } return pix_edit; } void* __cdecl obj_LensBlur_t::lbResize_71420_wrap_126a6(void* pix_edit, int w0, int h0, int w1, int h1, void* pix_temp) { if (w0 && h0 && w1 && h1) { return reinterpret_cast(GLOBAL::exedit_base + 0x071420)(pix_edit, w0, h0, w1, h1, pix_temp); } return pix_edit; } void __cdecl obj_LensBlur_t::lbResize_set_w_end(void* dst, void* src, int w, int h, int back) { lbResize_wh_end = w - 1; } void __cdecl obj_LensBlur_t::lbResize_set_h_end(void* dst, void* src, int w, int h, int back) { lbResize_wh_end = h - 1; } struct PixelYC_fbb { float y; byte cb; byte cr; }; void obj_LensBlur_t::lbResize_media(int thread_id, int thread_num, int loop1, int forstep1, int loop2, int forstep2, int flag) { forstep1 *= sizeof(struct ExEdit::PixelYCA); forstep2 *= sizeof(struct ExEdit::PixelYCA); int i_end = (thread_id + 1) * loop1 / thread_num; for (int i = thread_id * loop1 / thread_num; i < i_end; i++) { int ii = lbresize->resize_step * i + (lbresize->resize_step - 0x10000) / 2; int fraction = ii & 0xffff; int inv_fraction = 0x10000 - fraction; ii >>= 16; auto dst = (ExEdit::PixelYCA*)((int)lbresize->resize_temp + i * forstep1); auto src0 = (ExEdit::PixelYCA*)((int)lbresize->resize_edit + max(0, ii) * forstep1); auto src1 = (ExEdit::PixelYCA*)((int)lbresize->resize_edit + min(ii + 1, lbResize_wh_end) * forstep1); for (int j = 0; j < loop2; j++) { int src0_a = (src0->a * inv_fraction + 0x800) >> 12; int src1_a = (src1->a * fraction + 0x800) >> 12; int a = src0_a + src1_a; if (a <= 0) { dst->y = dst->cb = dst->cr = dst->a = 0; } else { if (flag) { ((PixelYC_fbb*)dst)->y = (((PixelYC_fbb*)src0)->y * (float)src0_a + ((PixelYC_fbb*)src1)->y * (float)src1_a) / (float)a; ((PixelYC_fbb*)dst)->cb = (byte)((((PixelYC_fbb*)src0)->cb * src0_a + ((PixelYC_fbb*)src1)->cb * src1_a) / a); ((PixelYC_fbb*)dst)->cr = (byte)((((PixelYC_fbb*)src0)->cr * src0_a + ((PixelYC_fbb*)src1)->cr * src1_a) / a); } else { dst->y = (short)((src0->y * src0_a + src1->y * src1_a) / a); dst->cb = (short)((src0->cb * src0_a + src1->cb * src1_a) / a); dst->cr = (short)((src0->cr * src0_a + src1->cr * src1_a) / a); } dst->a = (short)((a + 8) >> 4); } dst = (ExEdit::PixelYCA*)((int)dst + forstep2); src0 = (ExEdit::PixelYCA*)((int)src0 + forstep2); src1 = (ExEdit::PixelYCA*)((int)src1 + forstep2); } } } void obj_LensBlur_t::lbResize_filter(int thread_id, int thread_num, int loop1, int forstep1, int loop2, int forstep2, int flag) { forstep1 *= sizeof(struct AviUtl::PixelYC); forstep2 *= sizeof(struct AviUtl::PixelYC); int i_end = (thread_id + 1) * loop1 / thread_num; for (int i = thread_id * loop1 / thread_num; i < i_end; i++) { int ii = lbresize->resize_step * i + (lbresize->resize_step - 0x10000) / 2; int fraction = ii & 0xffff; int inv_fraction = 0x10000 - fraction; ii >>= 16; auto dst = (AviUtl::PixelYC*)((int)lbresize->resize_temp + i * forstep1); auto src0 = (AviUtl::PixelYC*)((int)lbresize->resize_edit + max(0, ii) * forstep1); auto src1 = (AviUtl::PixelYC*)((int)lbresize->resize_edit + min(ii + 1, lbResize_wh_end) * forstep1); for (int j = 0; j < loop2; j++) { if (flag) { ((PixelYC_fbb*)dst)->y = (((PixelYC_fbb*)src0)->y * (float)inv_fraction + ((PixelYC_fbb*)src1)->y * (float)fraction) / 65536.0f; ((PixelYC_fbb*)dst)->cb = (byte)((((PixelYC_fbb*)src0)->cb * inv_fraction + ((PixelYC_fbb*)src1)->cb * fraction + 0x8000) >> 16); ((PixelYC_fbb*)dst)->cr = (byte)((((PixelYC_fbb*)src0)->cr * inv_fraction + ((PixelYC_fbb*)src1)->cr * fraction + 0x8000) >> 16); } else { dst->y = (short)((src0->y * inv_fraction + src1->y * fraction + 0x8000) >> 16); dst->cb = (short)((src0->cb * inv_fraction + src1->cb * fraction + 0x8000) >> 16); dst->cr = (short)((src0->cr * inv_fraction + src1->cr * fraction + 0x8000) >> 16); } dst = (AviUtl::PixelYC*)((int)dst + forstep2); src0 = (AviUtl::PixelYC*)((int)src0 + forstep2); src1 = (AviUtl::PixelYC*)((int)src1 + forstep2); } } } void __cdecl obj_LensBlur_t::lbResize_media_interpolation_y(int thread_id, int thread_num, void* n1, void* n2) { // exedit + 70df0 相当 int exedit_buffer_line = *(int*)(GLOBAL::exedit_base + OFS::ExEdit::exedit_buffer_line); lbResize_media(thread_id, thread_num, lbresize->resize_h, exedit_buffer_line, lbresize->resize_w, 1, 0); } void __cdecl obj_LensBlur_t::lbResize_media_interpolation_x(int thread_id, int thread_num, void* n1, void* n2) { // exedit + 71270 相当 int exedit_buffer_line = *(int*)(GLOBAL::exedit_base + OFS::ExEdit::exedit_buffer_line); lbResize_media(thread_id, thread_num, lbresize->resize_w, 1, lbresize->resize_h, exedit_buffer_line, 0); } void __cdecl obj_LensBlur_t::lbResize_media_interpolation_y_fbb(int thread_id, int thread_num, void* n1, void* n2) { // exedit + 71870 相当 int exedit_buffer_line = *(int*)(GLOBAL::exedit_base + OFS::ExEdit::exedit_buffer_line); lbResize_media(thread_id, thread_num, lbresize->resize_h, exedit_buffer_line, lbresize->resize_w, 1, 1); } void __cdecl obj_LensBlur_t::lbResize_media_interpolation_x_fbb(int thread_id, int thread_num, void* n1, void* n2) { // exedit + 71ce0 相当 int exedit_buffer_line = *(int*)(GLOBAL::exedit_base + OFS::ExEdit::exedit_buffer_line); lbResize_media(thread_id, thread_num, lbresize->resize_w, 1, lbresize->resize_h, exedit_buffer_line, 1); } void __cdecl obj_LensBlur_t::lbResize_filter_interpolation_y(int thread_id, int thread_num, void* n1, void* n2) { // exedit + 72390 相当 int si_vram_w = *(int*)(GLOBAL::exedit_base + OFS::ExEdit::exedit_YC_vram_w); lbResize_filter(thread_id, thread_num, lbresize->resize_h, si_vram_w, lbresize->resize_w, 1, 0); } void __cdecl obj_LensBlur_t::lbResize_filter_interpolation_x(int thread_id, int thread_num, void* n1, void* n2) { // exedit + 72720 相当 int si_vram_w = *(int*)(GLOBAL::exedit_base + OFS::ExEdit::exedit_YC_vram_w); lbResize_filter(thread_id, thread_num, lbresize->resize_w, 1, lbresize->resize_h, si_vram_w, 0); } void __cdecl obj_LensBlur_t::lbResize_filter_interpolation_y_fbb(int thread_id, int thread_num, void* n1, void* n2) { // exedit + 72c20 相当 int si_vram_w = *(int*)(GLOBAL::exedit_base + OFS::ExEdit::exedit_YC_vram_w); lbResize_filter(thread_id, thread_num, lbresize->resize_h, si_vram_w, lbresize->resize_w, 1, 1); } void __cdecl obj_LensBlur_t::lbResize_filter_interpolation_x_fbb(int thread_id, int thread_num, void* n1, void* n2) { // exedit + 72f90 相当 int si_vram_w = *(int*)(GLOBAL::exedit_base + OFS::ExEdit::exedit_YC_vram_w); lbResize_filter(thread_id, thread_num, lbresize->resize_w, 1, lbresize->resize_h, si_vram_w, 1); } } // namespace patch #endif // ifdef PATCH_SWITCH_OBJ_LENSBLUR ================================================ FILE: patch/patch_obj_lensblur.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_OBJ_LENSBLUR #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // レンズブラーのエラー修正 /* オフセットアドレス exedit + 71449 の修正 サイズ2~3の図形にレンズブラーを付けて サイズ固定にチェックが入った状態でレンズブラー範囲を広げる */ /* オフセットアドレス exedit + 71f95 の修正 フィルタオブジェクトのレンズブラー(範囲を広げたもの)をシーンオブジェクトで読み込む シーンオブジェクト以外でエラーはあまり見られないけど他データを破壊していそうなのでそちらもまとめて修正 */ inline class obj_LensBlur_t { static void* __cdecl lbResize_709a0_wrap_12809(void* pix_edit, int w0, int h0, int w1, int h1, void* pix_temp); static void* __cdecl lbResize_71420_wrap_126a6(void* pix_edit, int w0, int h0, int w1, int h1, void* pix_temp); inline static struct lbResize_var { // 1e42c0 void* resize_edit; int _others1[8]; void* resize_temp; // 1e42e4 int _others2[14]; int resize_step; // 1e4320 int resize_h; // 1e4324 int _bufcpy_h; // 1e4328 int resize_w; // 1e432c }*lbresize; inline static int lbResize_wh_end; static void __cdecl lbResize_set_w_end(void* dst, void* src, int w, int h, int back); static void __cdecl lbResize_set_h_end(void* dst, void* src, int w, int h, int back); static void lbResize_media(int thread_id, int thread_num, int loop1, int forstep1, int loop2, int forstep2, int flag); static void lbResize_filter(int thread_id, int thread_num, int loop1, int forstep1, int loop2, int forstep2, int flag); static void __cdecl lbResize_media_interpolation_y(int thread_id, int thread_num, void* n1, void* n2); static void __cdecl lbResize_media_interpolation_x(int thread_id, int thread_num, void* n1, void* n2); static void __cdecl lbResize_media_interpolation_y_fbb(int thread_id, int thread_num, void* n1, void* n2); static void __cdecl lbResize_media_interpolation_x_fbb(int thread_id, int thread_num, void* n1, void* n2); static void __cdecl lbResize_filter_interpolation_y(int thread_id, int thread_num, void* n1, void* n2); static void __cdecl lbResize_filter_interpolation_x(int thread_id, int thread_num, void* n1, void* n2); static void __cdecl lbResize_filter_interpolation_y_fbb(int thread_id, int thread_num, void* n1, void* n2); static void __cdecl lbResize_filter_interpolation_x_fbb(int thread_id, int thread_num, void* n1, void* n2); bool enabled = true; bool enabled_i; inline static const char key[] = "obj_lensblur"; public: void init() { enabled_i = enabled; if (!enabled_i)return; { // オフセットアドレス exedit + 71449 の修正 ReplaceNearJmp(GLOBAL::exedit_base + 0x01280a, &lbResize_709a0_wrap_12809); ReplaceNearJmp(GLOBAL::exedit_base + 0x0126a7, &lbResize_71420_wrap_126a6); } { // オフセットアドレス exedit + 71f95 の修正、なんかやヴぁそうなバグの修正 /* 以下の関数にて行われる危険な処理:memcpy( &ycp_edit[-line_size-1], &ycp_edit[-1], (line_size+2) * sizeof(PIXEL_YC)); おそらく補間処理を行うための前処理として行われている 危険なのでその前処理は全て削除し、ついでにリサイズ前のw,hを取得したいので置き換える */ ReplaceNearJmp(GLOBAL::exedit_base + 0x070a08, &lbResize_set_h_end); ReplaceNearJmp(GLOBAL::exedit_base + 0x070aab, &lbResize_set_w_end); ReplaceNearJmp(GLOBAL::exedit_base + 0x071488, &lbResize_set_h_end); ReplaceNearJmp(GLOBAL::exedit_base + 0x07152b, &lbResize_set_w_end); ReplaceNearJmp(GLOBAL::exedit_base + 0x072068, &lbResize_set_h_end); ReplaceNearJmp(GLOBAL::exedit_base + 0x07210b, &lbResize_set_w_end); ReplaceNearJmp(GLOBAL::exedit_base + 0x0728d8, &lbResize_set_h_end); ReplaceNearJmp(GLOBAL::exedit_base + 0x07297b, &lbResize_set_w_end); lbresize = (lbResize_var*)(GLOBAL::exedit_base + 0x1e42c0); /* 前処理が無くても同じように動くように書いたものに置き換える リソースのことを考えて関数はできるだけ纏めた x方向の処理が従来より効率が良いのでそんなに速度が落ちることは無いはず */ { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x070a3f, 4); h.store_i32(0, &lbResize_media_interpolation_y); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x070ac5, 4); h.store_i32(0, &lbResize_media_interpolation_x); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x0714bf, 4); h.store_i32(0, &lbResize_media_interpolation_y_fbb); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x071545, 4); h.store_i32(0, &lbResize_media_interpolation_x_fbb); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x07209f, 4); h.store_i32(0, &lbResize_filter_interpolation_y); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x072125, 4); h.store_i32(0, &lbResize_filter_interpolation_x); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x07290f, 4); h.store_i32(0, &lbResize_filter_interpolation_y_fbb); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x072995, 4); h.store_i32(0, &lbResize_filter_interpolation_x_fbb); } } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } LensBlur; } // namespace patch #endif // ifdef PATCH_SWITCH_OBJ_LENSBLUR ================================================ FILE: patch/patch_obj_noise.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_OBJ_NOISE #include #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" namespace patch { // init at exedit load // ノイズの 速度X 変化速度 を移動無し以外に設定している時、速度Y の値をもとに計算されるバグの修正 inline class obj_Noise_t { bool enabled = true; bool enabled_i; inline static const char key[] = "obj_noise"; public: void init() { enabled_i = enabled; if (!enabled_i)return; auto& cursor = GLOBAL::executable_memory_cursor; OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x04d8e7, 5); h.store_i8(0, '\xe8'); h.store_i32(1, cursor - (GLOBAL::exedit_base + 0x04d8ec)); /* 1004d8e7 2bf0 sub esi,eax 1004d8e9 8b4a08 mov ecx,dword ptr [edx+8] ↓ 1004d8e7 e8xXxXxXxX call &executable_memory_cursor ecx,dword ptr [edx+8]を ecx,dword ptr [edx+ track_id*4]にする */ static const char code_put[] = "\x2b\xf0" // sub esi, eax "\x8b\x4c\x24\x4c" // mov ecx, dword ptr[esp + 0x4c] "\x8b\x0c\x8a" // mov ecx, dword ptr[edx + ecx * 4] "\xc3" // ret exedit_base + 0x4d8ec ; memcpy(cursor, code_put, sizeof(code_put) - 1); cursor += sizeof(code_put) - 1; } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } Noise; } // namespace patch #endif // ifdef PATCH_SWITCH_OBJ_NOISE ================================================ FILE: patch/patch_obj_specialcolorconv.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_OBJ_SPECIALCOLORCONV #include #include "util.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // 特定色域変換で変換前色に黒色を指定すると0除算が起こることがあるのを修正 /* 問題のコード if (pix_y < before_y) { after_y = (after_y * pix_y) / before_y; } 今回行った修正は以下を追加 (Yが負の値を取らない前提で作られていたようなので) if (pix_y < 0) { pix_y = 0; } */ inline class obj_specialcolorconv_t { bool enabled = true; bool enabled_i; inline static const char key[] = "obj_specialcolorconv"; public: void init() { enabled_i = enabled; if (!enabled_i)return; auto& cursor = GLOBAL::executable_memory_cursor; { { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x015cca, 7); h.store_i32(0, '\x90\x90\xe8\x00'); h.replaceNearJmp(3, cursor); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x015e25, 7); h.store_i32(0, '\x90\x90\xe8\x00'); h.replaceNearJmp(3, cursor); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x015f77, 7); h.store_i32(0, '\x90\x90\xe8\x00'); h.replaceNearJmp(3, cursor); } { /* 10015f77 0fbf31 movsx esi,dword ptr [ecx] 10015f7a 0fbf5d00 movsx ebx,dword ptr [ebp+00] ↓ 10015f77 9090 nop 10015f79 e8XxXxXxXx call executable_memory_cursor ; esi(pix->y)が0未満の場合、0にする */ static const char code_put[] = "\x0f\xbf\x31" // movsx esi,dword ptr [ecx] "\x0f\xbf\x5d\x00" // movsx ebx,dword ptr [ebp+00] "\x85\xf6" // test esi,esi "\x7f\x02" // jg skip,+02 "\x33\xf6" // xor esi,esi "\xc3" // ret ; memcpy(cursor, code_put, sizeof(code_put) - 1); cursor += sizeof(code_put) - 1; } } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x0156f5, 6); h.store_i16(0, '\x90\xe8'); h.replaceNearJmp(2, cursor); /* 100156f5 0fbf1f movsx ebx,dword ptr [edi] 100156f8 0fbf2e movsx ebp,dword ptr [esi] ↓ 100156f5 90 nop 100156f6 e8XxXxXxXx call executable_memory_cursor ; ebx(pix->y)が0未満の場合、0にする */ static const char code_put[] = "\x0f\xbf\x1f" // movsx ebx,dword ptr [edi] "\x0f\xbf\x2e" // movsx ebp,dword ptr [esi] "\x85\xdb" // test ebx,ebx "\x7f\x02" // jg skip,+02 "\x33\xdb" // xor ebx,ebx "\xc3" // ret ; memcpy(cursor, code_put, sizeof(code_put) - 1); cursor += sizeof(code_put) - 1; } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } obj_specialcolorconv; } // namespace patch #endif // ifdef PATCH_SWITCH_OBJ_SPECIALCOLORCONV ================================================ FILE: patch/patch_playback_speed.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_PLAYBACK_SPEED #include #include "config_rw.hpp" #include "global.hpp" namespace patch { // init at exedit load // n番目の中間点で再生速度を変化させるとnフレーム遅れて反映されるのを修正 inline class playback_speed_t { bool enabled = true; bool enabled_i; inline static const char key[] = "playback_speed"; public: void init() { enabled_i = enabled; if (!enabled_i)return; { // movie_file OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x005fd9, 1); h.store_i8(0, '\x90'); } { // audio_file OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x08faab, 1); h.store_i8(0, '\x90'); } { // scene OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x0836b3, 1); h.store_i8(0, '\x90'); } { // scene_audio OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x084297, 1); h.store_i8(0, '\x90'); } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } playback_speed; } // namespace patch #endif // ifdef PATCH_SWITCH_PLAYBACK_SPEED ================================================ FILE: patch/patch_rclickmenu_delete.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_rclickmenu_delete.hpp" #ifdef PATCH_SWITCH_RCLICKMENU_DELETE namespace patch { void __cdecl rclickmenu_delete_t::disp_near_settingdialog_wrap3fef6() { if (0 <= *settingdialog_object_idx_ptr) { int object_idx = *settingdialog_object_idx_ptr; if (*selecting_obj_num_ptr) { object_idx = selecting_obj_list[0]; } last_id = reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::get_near_object_idx)(object_idx, 1); } } void __cdecl rclickmenu_delete_t::DrawTimelineMask_wrap3ff68(int* to_draw) { if (0 <= last_id) { reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::disp_settingdialog)(last_id); last_id = -1; } reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::DrawTimelineMask)(to_draw); } } // namespace patch #endif // ifdef PATCH_SWITCH_RCLICKMENU_DELETE ================================================ FILE: patch/patch_rclickmenu_delete.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_RCLICKMENU_DELETE #include #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "restorable_patch.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // 右クリックメニューの削除でテキストの字間・行間が変わることがあるのを修正 // 設定ダイアログの更新タイミングを変えることで修正 inline class rclickmenu_delete_t { static void __cdecl disp_near_settingdialog_wrap3fef6(); static void __cdecl DrawTimelineMask_wrap3ff68(int* to_draw); bool enabled = true; bool enabled_i; inline static const char key[] = "r_click_menu_delete"; inline static int last_id = -1; public: inline static int* settingdialog_object_idx_ptr; inline static int* selecting_obj_num_ptr; inline static int* selecting_obj_list; void init() { enabled_i = enabled; if (!enabled_i)return; settingdialog_object_idx_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x177a10); selecting_obj_num_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x167d88); selecting_obj_list = reinterpret_cast(GLOBAL::exedit_base + 0x179230); ReplaceNearJmp(GLOBAL::exedit_base + 0x03fef6, &disp_near_settingdialog_wrap3fef6); ReplaceNearJmp(GLOBAL::exedit_base + 0x03ff68, &DrawTimelineMask_wrap3ff68); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } rclickmenu_delete; } // namespace patch #endif // ifdef PATCH_SWITCH_RCLICKMENU_DELETE ================================================ FILE: patch/patch_rclickmenu_split.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_rclickmenu_split.hpp" #ifdef PATCH_SWITCH_RCLICKMENU_SPLIT namespace patch { int __cdecl rclickmenu_split_t::filter_sendmessage_wrap3fd46(int object_idx, int wparam, int flag) { if (last_id < 0) { last_id = object_idx; } return reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::filter_sendmessage)(object_idx, wparam, flag); } void __cdecl rclickmenu_split_t::splitted_object_new_group_belong_wrap3fd5c() { if (0 <= last_id) { reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::disp_settingdialog)(last_id); last_id = -1; } reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::splitted_object_new_group_belong)(); } } // namespace patch #endif // ifdef PATCH_SWITCH_RCLICKMENU_SPLIT ================================================ FILE: patch/patch_rclickmenu_split.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_RCLICKMENU_SPLIT #include #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "restorable_patch.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // 右クリックメニューの分割で設定ダイアログの更新が行われないのを修正 inline class rclickmenu_split_t { static int __cdecl filter_sendmessage_wrap3fd46(int object_idx, int wparam, int flag); static void __cdecl splitted_object_new_group_belong_wrap3fd5c(); bool enabled = true; bool enabled_i; inline static const char key[] = "r_click_menu_split"; inline static int last_id = -1; public: void init() { enabled_i = enabled; if (!enabled_i)return; ReplaceNearJmp(GLOBAL::exedit_base + 0x03fd46, &filter_sendmessage_wrap3fd46); ReplaceNearJmp(GLOBAL::exedit_base + 0x03fd5c, &splitted_object_new_group_belong_wrap3fd5c); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } rclickmenu_split; } // namespace patch #endif // ifdef PATCH_SWITCH_RCLICKMENU_SPLIT ================================================ FILE: patch/patch_redo.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_redo.hpp" #ifdef PATCH_SWITCH_UNDO_REDO namespace patch { void __cdecl redo_t::init_undo_patch() { *UndoInfo_object_num_ptr = -1; *UndoInfo_write_offset_ptr = -1; *UndoInfo_current_id_ptr = 0; UndoInfo_max_id = 0; UndoInfo_object_new = 0; UndoInfo_pre_id = 0; new_object = true; running_undo = false; pre_scene_idx = *SceneDisplaying_ptr; } int __cdecl redo_t::f8d290(void* ret, int object_idx, int flag) { int& UndoInfo_object_num = *UndoInfo_object_num_ptr; int& UndoInfo_write_offset = *UndoInfo_write_offset_ptr; int& UndoInfo_limit_mode = *UndoInfo_limit_mode_ptr; // データが生成されない条件をそのまま追加 if ((UndoInfo_limit_mode && (flag & 2) == 0) || UndoInfo_write_offset < 0 || UndoInfo_object_num < 0) { return UndoInfo_limit_mode; } if ((flag & 0x10) == 0) { auto ObjectArrayPointer = *ObjectArrayPointer_ptr; if (!has_flag(ObjectArrayPointer[object_idx].flag, ExEdit::Object::Flag::Exist) && ((flag & 2) == 0)) { return UndoInfo_limit_mode; } if ((flag & 1) && 0 <= ObjectArrayPointer[object_idx].index_midpt_leader) { return UndoInfo_limit_mode; } } // ---------------------------------- if (running_undo) { move_redo_data(); } else { optimize_undo_data(); } return UndoInfo_limit_mode; } int __cdecl redo_t::pre_run_undo() { // shift + ctrl + zでredoを実行させるためのコード(元に戻せない状態からでも使えます) #ifdef PATCH_SWITCH_UNDO_REDO_SHIFT if (redo.enabled_i && redo.c_shift) { if (!running_undo) { if (GetKeyState(VK_SHIFT) < 0) { run_redo(); return 0; } } } #endif int& UndoInfo_write_offset = *UndoInfo_write_offset_ptr; int& UndoInfo_current_id = *UndoInfo_current_id_ptr; int& UndoInfo_object_num = *UndoInfo_object_num_ptr; int& selecting_obj_num = *selecting_obj_num_ptr; // optimize_undo_data()で処理していない最新のデータを処理する(元に戻す操作をしているため状態は確定しているはず) optimize_newer_undo_data(); if (UndoInfo_current_id <= 0 || UndoInfo_write_offset <= 0 || UndoInfo_object_num <= 0)return 0; // Ctrlを押しながら複数選択した状態で元に戻すをしてオブジェクトが消えると幽霊オブジェクトが出現するのを修正 (選択状態を強制解除) selecting_obj_num = 0; running_undo = true; int i; // 元々はobject_numを返す。redoデータが残ることでobject_numではなくdata_id > current_idとなるタイミングのnumを返すことでrun_undo内の処理との辻褄が合う for (i = 1; i < UndoInfo_object_num; i++) { if (UndoDataPtrArray[i]->data_id > UndoInfo_current_id) { break; } } // 必要であればシーン切り替えを行う if (UndoDataPtrArray[i - 1]->data_id == UndoInfo_current_id) { int scene_idx = get_scene_idx_UndoData(i - 1); if (scene_idx != *SceneDisplaying_ptr) { //void*& editpm = *(void**)uintptr_t(gp_editp); change_disp_scene(scene_idx, *fp_g_ptr, *editp_ptr); } } return i; } void __cdecl redo_t::end_run_undo() { int& UndoInfo_current_id = *UndoInfo_current_id_ptr; move_redo_data(); running_undo = false; UndoInfo_current_id--; UndoInfo_pre_id = UndoInfo_current_id; } void __cdecl redo_t::undo_change_disp_scene() { optimize_newer_undo_data(); pre_scene_idx = *SceneDisplaying_ptr; } } // namespace patch #endif ================================================ FILE: patch/patch_redo.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_UNDO_REDO #include #include "patch_undo.hpp" namespace patch { inline class redo_t { inline static ExEdit::Object** ObjectArrayPointer_ptr; inline static ExEdit::LayerSetting** layer_setting_ofsptr_ptr; inline static void** exdata_buffer_ptr; struct UndoData { int data_id; int object_id; // layer | 0x1000000; int data_size; DWORD object_flag; int object_layer_disp; int object_frame_begin; int object_frame_end; DWORD* data; }; inline static int* UndoInfo_object_num_ptr; inline static int* UndoInfo_write_offset_ptr; inline static int* UndoInfo_current_id_ptr; inline static int* SceneDisplaying_ptr; inline static DWORD* UndoInfo_buffer_ptr_ptr; inline static int* UndoInfo_buffer_size_ptr; inline static int* UndoInfo_limit_mode_ptr; inline static int* selecting_obj_num_ptr; inline static AviUtl::EditHandle** editp_ptr; inline static AviUtl::FilterPlugin** fp_g_ptr; inline static UndoData** UndoDataPtrArray; inline static void* (__cdecl* exedit_memmove)(void*, void*, size_t); inline static void(__cdecl* run_undo)(); inline static void(__cdecl* change_disp_scene)(int, AviUtl::FilterPlugin*, AviUtl::EditHandle*); inline static int pre_scene_idx = 0; inline static int UndoInfo_max_id = 0; inline static int UndoInfo_object_new = 0; inline static int UndoInfo_pre_id = 0; inline static bool new_object = true; inline static bool running_undo = false; static void __cdecl init_undo_patch(); // レイヤーUndo情報そのままではシーンが分からないため、UndoData.object_layer_dispにscene_idxを入れておくようにする static void add_scene_idx() { for (int i = UndoInfo_object_new; i < *UndoInfo_object_num_ptr; i++) { UndoData* undodata = UndoDataPtrArray[i]; if (undodata->object_id & 0x1000000) { // レイヤー undodata->object_layer_disp = pre_scene_idx; } } } static int get_scene_idx_UndoData(int undo_id) { UndoData* undodata = UndoDataPtrArray[undo_id]; if (undodata->object_id & 0x1000000) { return undodata->object_layer_disp; } else { return (*ObjectArrayPointer_ptr)[undodata->object_id].scene_set; } } // undo_bufferから指定idのデータを削除(空白が出来ないようにずらす) static void shift_undo_buffer(int id) { DWORD UndoInfo_buffer_ptr = *UndoInfo_buffer_ptr_ptr; int& UndoInfo_object_num = *UndoInfo_object_num_ptr; int& UndoInfo_write_offset = *UndoInfo_write_offset_ptr; int size = UndoDataPtrArray[id]->data_size; DWORD delptr = (DWORD)UndoDataPtrArray[id]; DWORD nextptr = delptr + size; if (UndoInfo_buffer_ptr + (DWORD)UndoInfo_write_offset > nextptr) { exedit_memmove((void*)delptr, (void*)nextptr, UndoInfo_buffer_ptr + (DWORD)UndoInfo_write_offset - nextptr); } UndoInfo_write_offset -= size; for (int i = 0; i < UndoInfo_object_num; i++) { if (delptr < (DWORD)UndoDataPtrArray[i]) { UndoDataPtrArray[i] = (UndoData*)((DWORD)UndoDataPtrArray[i] - size); } } UndoInfo_object_num--; } // 指定idのデータを削除・整理 static void remove_UndoData(int id) { shift_undo_buffer(id); for (int i = id; i < *UndoInfo_object_num_ptr; i++) { UndoDataPtrArray[i] = UndoDataPtrArray[i + 1]; } } // 指定id以上のデータを削除(新しく追加されるデータを除く) static void remove_old_UndoData(int id) { for (int i = UndoInfo_object_new - 1; i >= 0; i--) { if (id <= UndoDataPtrArray[i]->data_id) { remove_UndoData(i); } } } // id1のデータを削除し、id2のデータを置き換える static void move_UndoData(int id1, int id2) { shift_undo_buffer(id1); UndoDataPtrArray[id1] = UndoDataPtrArray[id2]; } // id1とid2の統合(重複部分はid1が優先) static void integrate_undodata(int id1, int id2) { int& UndoInfo_write_offset = *UndoInfo_write_offset_ptr; UndoData* undodata1 = UndoDataPtrArray[id1]; UndoData* undodata2 = UndoDataPtrArray[id2]; if (undodata1->object_flag == 0) { remove_UndoData(id2); return; } if (undodata2->object_flag == 0) { remove_UndoData(id1); return; } if (undodata1->data_size < undodata2->data_size) { memcpy((void*)((DWORD)undodata2 + 0xc), (void*)((DWORD)undodata1 + 0xc), undodata1->data_size - 0xc); if (undodata1->data_size == 0x1c) { auto undoobj = reinterpret_cast(&undodata2->data); undoobj->flag = static_cast(undodata1->object_flag); if (undodata1->object_flag) { undoobj->layer_set = undoobj->layer_disp = undodata1->object_layer_disp; undoobj->frame_begin = undodata1->object_frame_begin; undoobj->frame_end = undodata1->object_frame_end; } } remove_UndoData(id1); } else { remove_UndoData(id2); } } // 新しく追加されたデータに対して、重複があれば統合する static void optimize_new_undo_buffer() { int& UndoInfo_object_num = *UndoInfo_object_num_ptr; UndoData* newdata = UndoDataPtrArray[UndoInfo_object_num - 1]; UndoData* undodata; for (int i = UndoInfo_object_new; i < UndoInfo_object_num - 1; i++) { undodata = UndoDataPtrArray[i]; if (undodata->object_id == newdata->object_id && undodata->data_id == newdata->data_id) { integrate_undodata(i, UndoInfo_object_num - 1); break; } } } // 現在のオブジェクトデータと比べて変更が無ければ削除する static void remove_emptiness_UndoData() { // 指定idのデータと現在のオブジェクト状態を比較 (TRUE:相違点あり FALSE:同じ) auto cmp_obj_undo = [](int id) { auto& ObjectArrayPointer = *ObjectArrayPointer_ptr; auto& layer_setting_ofsptr = *layer_setting_ofsptr_ptr; auto& exdata_buffer = *exdata_buffer_ptr; auto& UndoInfo_object_num = *UndoInfo_object_num_ptr; auto& UndoInfo_write_offset = *UndoInfo_write_offset_ptr; UndoData* undodata = UndoDataPtrArray[id]; void* ptr1; void* ptr2; int cmpsize; if (undodata->object_id & 0x1000000) { // レイヤー ptr1 = (void*)&layer_setting_ofsptr[undodata->object_id & 0xffffff]; ptr2 = &undodata->data; cmpsize = 8; } else { ptr1 = (void*)&ObjectArrayPointer[undodata->object_id]; if (undodata->data_size > 0x1c) { ptr2 = &undodata->data; cmpsize = sizeof(ExEdit::Object); auto fix_track_right = [](ExEdit::Object* obj) { int track_num = obj->track_n; for (int i = 0; i < track_num; i++) { if (obj->track_mode[i].num == 0) { obj->track_value_right[i] = obj->track_value_left[i]; } } }; fix_track_right(static_cast(ptr1)); // 処理順の関係かトラック右の値が変わってしまっていることがあるので直す fix_track_right(static_cast(ptr2)); void* ptr3 = reinterpret_cast(reinterpret_cast(exdata_buffer) + ObjectArrayPointer[undodata->object_id].exdata_offset + 4); void* ptr4 = reinterpret_cast(reinterpret_cast(&undodata->data) + cmpsize); int excmpsize = undodata->data_size - 0x1c - cmpsize; if (memcmp(ptr3, ptr4, excmpsize))return true; } else { ptr2 = &undodata->object_flag; if (undodata->object_flag == 0) { cmpsize = 4; } else { cmpsize = 0x10; } } } if (memcmp(ptr1, ptr2, cmpsize))return true; return false; }; for (int i = UndoInfo_object_new; i < *UndoInfo_object_num_ptr; i++) { if (!cmp_obj_undo(i)) { // 変更なし remove_UndoData(i); i--; } } } // run_undo内で生成されたredo用データを置き換える static void move_redo_data() { int& UndoInfo_object_num = *UndoInfo_object_num_ptr; if (UndoInfo_object_new < UndoInfo_object_num) { int dataid = UndoDataPtrArray[UndoInfo_object_new]->data_id; int objid = UndoDataPtrArray[UndoInfo_object_new]->object_id; // 元のUndoデータを削除、UndoDataPtrArrayの置換 BOOL movef = FALSE; for (int i = 0; i < UndoInfo_object_new; i++) { if (UndoDataPtrArray[i]->object_id == objid && UndoDataPtrArray[i]->data_id == dataid) { add_scene_idx(); move_UndoData(i, UndoInfo_object_new); movef = TRUE; break; } } if (!movef) { remove_UndoData(UndoInfo_object_new); } } UndoInfo_object_new = UndoInfo_object_num; } static void __stdcall AllocUndoBuffer_patch(int num) { for (int i = num - 1; i >= 0; i--) { UndoInfo_object_new--; remove_UndoData(i); } } // 一つ前の操作で作られたundoデータの最適化(状態が確定してから最適化を行う必要があるため一つ前のデータに対して行う) static void optimize_undo_data() { int& UndoInfo_current_id = *UndoInfo_current_id_ptr; int& UndoInfo_object_num = *UndoInfo_object_num_ptr; int& UndoInfo_write_offset = *UndoInfo_write_offset_ptr; if (new_object) { new_object = FALSE; UndoInfo_pre_id = UndoInfo_current_id; UndoInfo_object_new = UndoInfo_object_num; } if (UndoInfo_object_new < UndoInfo_object_num) { optimize_new_undo_buffer(); if (UndoInfo_pre_id < UndoInfo_current_id) { remove_emptiness_UndoData(); if (UndoInfo_object_new < UndoInfo_object_num) { // 変更があった add_scene_idx(); remove_old_UndoData(UndoInfo_pre_id); UndoInfo_pre_id = UndoInfo_current_id; UndoInfo_max_id = UndoInfo_current_id - 1; UndoInfo_object_new = UndoInfo_object_num; } else { UndoInfo_current_id--; } } } } // 最新のundoデータの最適化(undo処理を行う直前に、まだの部分の最適化を行う) static void optimize_newer_undo_data() { int& UndoInfo_current_id = *UndoInfo_current_id_ptr; int& UndoInfo_object_num = *UndoInfo_object_num_ptr; if (!new_object) { if (UndoInfo_object_new < UndoInfo_object_num) { optimize_new_undo_buffer(); remove_emptiness_UndoData(); if (UndoInfo_object_new < UndoInfo_object_num) { // 変更があった add_scene_idx(); remove_old_UndoData(UndoInfo_current_id); UndoInfo_max_id = UndoInfo_current_id; } else { UndoInfo_current_id--; } } } UndoInfo_pre_id = UndoInfo_current_id; UndoInfo_object_new = UndoInfo_object_num; new_object = TRUE; } // set_undoの先頭に追加する処理 static int __cdecl f8d290(void* ret, int object_idx, int flag); // run_undoの始めの方に追加する処理 static int __cdecl pre_run_undo(); // run_undoの後処理 static void __cdecl end_run_undo(); static void __cdecl undo_change_disp_scene(); // undoと同じ処理でredoをするためには並び順を逆にする必要がある static void reverse_UndoDataPtrArray() { int& UndoInfo_current_id = *UndoInfo_current_id_ptr; int& UndoInfo_object_num = *UndoInfo_object_num_ptr; int begin = 0; int end = 0; for (int i = 0; i < UndoInfo_object_num; i++) { if (UndoDataPtrArray[i]->data_id == UndoInfo_current_id) { begin = i; break; } } for (int i = begin; i < UndoInfo_object_num; i++) { if (UndoDataPtrArray[i]->data_id == UndoInfo_current_id) { end = i; } } UndoData* tmp; while (begin < end) { tmp = UndoDataPtrArray[begin]; UndoDataPtrArray[begin] = UndoDataPtrArray[end]; UndoDataPtrArray[end] = tmp; begin++; end--; } } bool enabled = true; bool enabled_i; inline static const char key[] = "undo.redo"; inline static const char c_shift_name[] = "shift"; bool c_shift = true; public: void init() { enabled_i = enabled; if (!enabled_i)return; ObjectArrayPointer_ptr = reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::ObjectArrayPointer); layer_setting_ofsptr_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x0a4058); exdata_buffer_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x1e0fa8); UndoInfo_object_num_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x244e08); UndoInfo_write_offset_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x244e10); UndoInfo_current_id_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x244e14); SceneDisplaying_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x1a5310); UndoInfo_buffer_ptr_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x244e0c); UndoInfo_buffer_size_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x244e18); UndoInfo_limit_mode_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x244e1c); selecting_obj_num_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x167d88); editp_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x1a532c); fp_g_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x14d4b4); UndoDataPtrArray = reinterpret_cast(GLOBAL::exedit_base + 0x2363a8); exedit_memmove = reinterpret_cast(GLOBAL::exedit_base + 0x091f60); run_undo = reinterpret_cast(GLOBAL::exedit_base + 0x08d490); change_disp_scene = reinterpret_cast(GLOBAL::exedit_base + 0x02ba60); /* initに内容を追加する void __cdecl InitUndo(void) { // 8d140 UndoInfo_object_num = -1; UndoInfo_write_offset = -1; } */ ReplaceFunction(GLOBAL::exedit_base + 0x08d140, &init_undo_patch); /* AddUndoCount 8d150 の処理を少し変更した方が良いように見えるけど、今回の実装では変えなくても影響なさそう if ((UndoInfo_write_offset <= 0) || (UndoInfo_object_num <= 0)) { UndoInfo_write_offset = 0; UndoInfo_object_num = 0; } ↓ if ((UndoInfo_write_offset <= 0) || (UndoInfo_object_num < 0)) { UndoInfo_write_offset = 0; UndoInfo_object_num = 0; } 1008d15a 7e 08 JLE 1008d162 7f 0a JG byte jle2jl[1] = { 0x7c }; exedit_ReplaceData(0x8d15a, jle2jl, 1); byte jg2jge[1] = { 0x7d }; exedit_ReplaceData(0x8d162, jg2jge, 1); */ /* bufferの最適化処理を行う 1008d290 a11c4e2410 MOV EAX, [UndoInfo_limit_mode] → e8-------- CALL f8d290 */ { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x08d290, 5); h.store_i8(0, '\xe8'); // call (rel32) h.replaceNearJmp(1, &f8d290); } /* undoの前処理 1008d4a9 a1084e2410 EAX = UndoInfo_object_num → e8-------- pre_run_undo(); */ { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x08d4a9, 5); h.store_i8(0, '\xe8'); // call (rel32) h.replaceNearJmp(1, &pre_run_undo); } /* redoデータ生成を無効にする処理を消す 1008d4c5 89151c4e2410 Undoinfo_limit_mode = 1 1008d4cb ↓ 1008d4c5 660f1f440000 nop word ptr [eax+eax+00H] 1008d4cb */ { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x08d4c5, 6); char patch[] = { 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 }; memcpy(reinterpret_cast(h.address()), patch, 6); } /* 後処理 1008d723 8b0d144e2410 mov ecx,UndoInfo_current_id 1008d729 40 inc eax++ 1008d72a a3084e2410 mov UndoInfo_object_num = eax 1008d72f 8b442428 mov eax = pre_limit_mode 1008d733 49 dec ecx-- 1008d734 a31c4e2410 mov UndoInfo_limit_mode = eax 1008d739 890d144e2410 mov UndoInfo_current_id = ecx ↓ 1008d723 eb15 jmp 1008d73a 1008d725 144e2410 err 1008d729 40 inc eax++ 1008d72a a3084e2410 mov UndoInfo_object_num = eax 1008d72f 8b442428 mov eax = pre_limit_mode 1008d733 49 dec ecx-- 1008d734 a31c4e2410 mov UndoInfo_limit_mode = eax 1008d739 89 err 1008d73a e8-------- call end_run_undo() */ { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x08d723, 2); h.store_i16(0, '\xeb\x15'); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x08d73a, 5); h.store_i8(0, '\xe8'); // call (rel32) h.replaceNearJmp(1, &end_run_undo); } /* AllocUndoBufferにて削除が行われる場合にUndoInfo_object_newを再計算する必要あり 1008d22a e8 31 4d 00 00 CALL exedit_memmove() exedit_ReplaceCall(0x8d22b, &redo_8d22b_patch); */ /* AllocUndoBufferで行われる削除処理がそのままではまずそうなので書きかえ while (true) { if (object_num < 15000 && write_offset + data_size < UndoInfo_buffer_size) { return TRUE; } if (object_num < 1) break; for (i = 1; i < object_num; i++) { if (UndoDataPtrArray[i]->data_id != UndoDataPtrArray[0]->data_id) break; } if (i == object_num) break; // -------------- ここから下を関数に置き換える --------------------- buffer_size = (DWORD)UndoDataPtrArray[i] - (DWORD)buffer_ptr; FUN_10091f60(buffer_ptr, (void)UndoDataPtrArray[i], write_offset - buffer_size); // memmove相当の関数 buffer_ptr = UndoInfo_buffer_ptr; object_num = UndoInfo_object_num - i; write_offset = UndoInfo_write_offset - buffer_size; UndoInfo_object_num = object_num; UndoInfo_write_offset = write_offset; offset = 0; for (i = 0; i < object_num; i++) { // UndoDataPtrArray[i] = (UndoData*)((DWORD)buffer_ptr + offset); offset += ((UndoData*)((DWORD)buffer_ptr + offset))->data_size; } } 1008d21a 8b04bda8632310 MOV EAX,dword ptr [EDI*0x4 + 0x102363a8] 1008d221 .. 1008d22f 8b15084e2410 MOV EDX,dword ptr [UndoInfo_object_num] 1008d235 8b2d104e2410 MOV EBP,dword ptr [UndoInfo_write_offset] .. 1008d274 e95dffffff JMP 1008d1d6 ↓ 1008d21a 57 PUSH EDI ; == i 1008d21b e8-------- CALL AllocUndoBuffer_patch(i) 1008d220 eb0d JMP 1008d22f 1008d222 .. 1008d22f 8b15084e2410 MOV EDX,dword ptr [UndoInfo_object_num] 1008d235 8b2d104e2410 MOV EBP,dword ptr [UndoInfo_write_offset] 1008d23b eb99 JMP 1008d1d6 1008d23d */ { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x08d21a, 6); h.store_i16(0, '\x57\xe8'); h.replaceNearJmp(2, &AllocUndoBuffer_patch); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x08d220, 2); h.store_i16(0, '\xeb\x0d'); // jmp +0dh } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x08d23b, 2); h.store_i16(0, '\xeb\x99'); // jmp +99h } // シーン切り替えてもUndoが継続できるようにする /* change_disp_scene内のundo初期化を削除し、別の処理を入れる 1002ba84 e8b7160600 CALL InitUndo() ↓ 1002ba84 e8-------- CALL new_function() */ ReplaceNearJmp(GLOBAL::exedit_base + 0x02ba85, &undo_change_disp_scene); } static void run_redo() { int& UndoInfo_current_id = *UndoInfo_current_id_ptr; // この後呼ばれるrun_undo()でも同じ処理が行われることになるが、ここで先に処理してredoが可能かどうかを判定する必要がある optimize_newer_undo_data(); // 上記処理にて新しい操作が行われていたとしたら、現在が最新状態という事になるのでredoはできない if (UndoInfo_current_id >= UndoInfo_max_id)return; // idを増やしてUndoDataPtrArrayの並びを逆にしてrun_undoを動かせばredoになる UndoInfo_current_id++; reverse_UndoDataPtrArray(); running_undo = true; run_undo(); UndoInfo_current_id++; UndoInfo_pre_id = UndoInfo_current_id; reverse_UndoDataPtrArray(); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } void config_load(ConfigReader& cr) { cr.regist(c_shift_name, [this](json_value_s* value) { ConfigReader::load_variable(value, c_shift); }); } void config_store(ConfigWriter& cw) { cw.append(c_shift_name, c_shift); } } redo; } #endif ================================================ FILE: patch/patch_scroll_objdlg.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_SCROLL_OBJDLG #include #include "offset_address.hpp" #include "util.hpp" namespace patch { // init at exedit load // 設定ダイアログサイズ固定化 inline class scroll_objdlg_t { static void movewindow(HWND hwnd, int x, int y) { SetWindowPos(hwnd, NULL, x, y, NULL, NULL, SWP_NOZORDER | SWP_NOSIZE); } static LRESULT CALLBACK a(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { switch(message) { case WM_CREATE: { RECT rc; GetClientRect(hwnd, &rc); SCROLLINFO si = { .cbSize = sizeof(SCROLLINFO), .fMask = SIF_DISABLENOSCROLL | SIF_ALL, .nMin = 0, .nMax = rc.bottom - rc.top, .nPage = 12, .nPos = 0 }; SetScrollInfo(hwnd, SB_VERT, &si, TRUE); break; } case WM_SIZE: { RECT rc; GetClientRect(hwnd, &rc); SCROLLINFO si = { .cbSize = sizeof(SCROLLINFO) }; GetScrollInfo(hwnd, SB_VERT, &si); SetScrollInfo(hwnd, SB_VERT, &si, TRUE); break; } case WM_SIZING: { auto& rect = *(RECT*)lparam; switch(wparam) { case WMSZ_RIGHT: { rect.right = rect.left + 0x1f0; } } break; } case WM_VSCROLL:{ switch(LOWORD(wparam)) { case SB_TOP: case SB_BOTTOM: case SB_LINEUP: case SB_LINEDOWN: case SB_PAGEUP: case SB_PAGEDOWN: case SB_THUMBPOSITION: break; } break; } } return 0; } bool enabled = true; bool enabled_i; inline static const char key[] = "scroll_objdlg"; public: void init() { enabled_i = enabled; if (!enabled_i)return; OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::ExtendedFilter_wndcls, 4); store_i32(GLOBAL::exedit_base + OFS::ExEdit::ExtendedFilter_wndcls, WS_SYSMENU | WS_VSCROLL); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } }scroll_objdlg; } // namespace patch #endif // ifdef PATCH_SWITCH_SCROLL_OBJDLG ================================================ FILE: patch/patch_setting_dialog_excolorconfig.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_setting_dialog_excolorconfig.hpp" #ifdef PATCH_SWITCH_SETTINGDIALOG_EXCOLORCONFIG namespace patch { void __cdecl excolorconfig_t::efExColorConfig_setButtonStr_wrap_17083(ExEdit::Filter* efp) { HWND ctrl_hwnd = efp->exfunc->get_hwnd(efp->processing, 7, 2); if (ctrl_hwnd) { SetWindowPos(ctrl_hwnd, (HWND)0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW); } ctrl_hwnd = efp->exfunc->get_hwnd(efp->processing, 7, 1); if (ctrl_hwnd) { SetWindowPos(ctrl_hwnd, (HWND)0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW); } efExColorConfig_setButtonStr(efp); } } // namespace patch #endif // ifdef PATCH_SWITCH_SETTINGDIALOG_EXCOLORCONFIG ================================================ FILE: patch/patch_setting_dialog_excolorconfig.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_SETTINGDIALOG_EXCOLORCONFIG #include #include "global.hpp" #include "util_magic.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // 設定ダイアログで拡張色設定の下のフィルタにウィンドウが被る inline class excolorconfig_t { static void __cdecl efExColorConfig_setButtonStr_wrap_17083(ExEdit::Filter* efp); bool enabled = true; bool enabled_i; inline static const char key[] = "settingdialog_excolorconfig"; public: inline static void(__cdecl* efExColorConfig_setButtonStr)(ExEdit::Filter* efp); void init() { enabled_i = enabled; if (!enabled_i) return; efExColorConfig_setButtonStr = reinterpret_cast(GLOBAL::exedit_base + 0x016e90); ReplaceNearJmp(GLOBAL::exedit_base + 0x017084, &efExColorConfig_setButtonStr_wrap_17083); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } excolorconfig; } // namespace patch #endif // ifdef PATCH_SWITCH_SETTINGDIALOG_EXCOLORCONFIG ================================================ FILE: patch/patch_setting_dialog_move.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_SETTINGDIALOG_MOVE #include #include #include #include "config_rw.hpp" namespace patch { inline class setting_dialog_move_t { inline static std::jthread th; inline static std::atomic_bool waiting; bool enabled = true; inline static const char key[] = "settingdialog_move"; public: void operator()(HWND hwnd) { if (!enabled)return; std::this_thread::sleep_for(std::chrono::milliseconds{ 10 }); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } setting_dialog_move; } #endif ================================================ FILE: patch/patch_setting_dialog_wndproc_override.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_setting_dialog_wndproc_override.hpp" #include "patch_setting_dialog_move.hpp" namespace patch { LRESULT CALLBACK setting_dialog_t::wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { switch (message) { case WM_MOVE: #ifdef PATCH_SWITCH_SETTINGDIALOG_MOVE setting_dialog_move(hwnd); #endif break; } return wndproc_orig(hwnd, message, wparam, lparam); } } ================================================ FILE: patch/patch_setting_dialog_wndproc_override.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #include "global.hpp" #include "util_magic.hpp" namespace patch { inline class setting_dialog_t { inline static WNDPROC wndproc_orig; static LRESULT CALLBACK wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); public: void operator()() { wndproc_orig = reinterpret_cast(GLOBAL::exedit_base + 0x02cde0); OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x02e804, 4); h.store_i32(0, &wndproc); } } setting_dialog; } ================================================ FILE: patch/patch_setting_gui.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "macro.h" #ifdef PATCH_SWITCH_SETTING_GUI namespace patch { // patch.aul の設定用ダイアログ inline class setting_gui_t { public: void operator()() { } } setting_gui; } // namespace patch #endif // ifdef PATCH_SWITCH_SETTING_GUI ================================================ FILE: patch/patch_setting_new_project.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_setting_new_project.hpp" #ifdef PATCH_SWITCH_SETTING_NEW_PROJECT namespace patch { BOOL __cdecl setting_new_project_t::exedit_edit_open_wrap(int w, int h, int video_rate, int video_scale, int audio_rate, HWND hwnd, AviUtl::EditHandle* editp, AviUtl::FilterPlugin* fp) { if (reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::exedit_edit_open)(w, h, video_rate, video_scale, audio_rate, hwnd, editp, fp)) { HWND* aviutl_hwnd = (HWND*)(GLOBAL::exedit_base + OFS::ExEdit::aviutl_hwnd); if (*(byte*)(GLOBAL::aviutl_base + 0x7ad58) & 1) { // クリッピング&リサイズが有効 SendMessageA(*aviutl_hwnd, WM_COMMAND, 10008, 0); // フィルタ>クリッピング&リサイズ } SendMessageA(*aviutl_hwnd, WM_COMMAND, 12100, 0); // 設定>サイズの変更>なし SendMessageA(*aviutl_hwnd, WM_COMMAND, 12107, 0); // 設定>フレームレートの変更>なし return TRUE; } return FALSE; } } // namespace patch #endif // ifdef PATCH_SWITCH_SETTING_NEW_PROJECT ================================================ FILE: patch/patch_setting_new_project.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_SETTING_NEW_PROJECT #include #include "global.hpp" #include "util.hpp" #include "restorable_patch.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // プロジェクト作成時、サイズの変更>なし フレームレートの変更>なし クリッピング&リサイズOFF にする inline class setting_new_project_t { static BOOL __cdecl exedit_edit_open_wrap(int w, int h, int video_rate, int video_scale, int audio_rate, HWND hwnd, AviUtl::EditHandle* editp, AviUtl::FilterPlugin* fp); bool enabled = true; bool enabled_i; inline static const char key[] = "setting_new_project"; public: void init() { enabled_i = enabled; if (!enabled_i)return; { // ReplaceNearJmp(GLOBAL::exedit_base + 0x004d4a, &exedit_edit_open_wrap); // バックアップファイルから新規作成 ReplaceNearJmp(GLOBAL::exedit_base + 0x03c0d0, &exedit_edit_open_wrap); // プロジェクト作成前のD&D ReplaceNearJmp(GLOBAL::exedit_base + 0x04392f, &exedit_edit_open_wrap); // オブジェクトファイルから新規作成 ReplaceNearJmp(GLOBAL::exedit_base + 0x043aea, &exedit_edit_open_wrap); // 新規プロジェクトの作成 } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } setting_new_project; } // namespace patch #endif // ifdef PATCH_SWITCH_SETTING_NEW_PROJECT ================================================ FILE: patch/patch_splash.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_splash.hpp" #ifdef PATCH_SWITCH_SPLASH namespace patch { LRESULT CALLBACK splash_t::SplashWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { using namespace Gdiplus; static GdiplusStartupInput gdi_input; static ULONG_PTR gdi_token; static HDC image_dc; static int w, h; switch (message) { case WM_CREATE: { Gdiplus::GdiplusStartup(&gdi_token, &gdi_input, NULL); auto hmod = GLOBAL::patchaul_hinst; auto resource_splash = FindResourceA(hmod, "SPLASH", RT_RCDATA); auto resource_splash_size = SizeofResource(hmod, resource_splash); auto resource_splash_data = LoadResource(hmod, resource_splash); auto resource_splash_ptr = LockResource(resource_splash_data); auto hglobal = GlobalAlloc(0, resource_splash_size); if (hglobal == NULL) return -1; auto ptr = GlobalLock(hglobal); if (ptr == nullptr) { GlobalFree(hglobal); return -1; } memcpy(ptr, resource_splash_ptr, resource_splash_size); GlobalUnlock(ptr); UnlockResource(resource_splash_ptr); IStream* is; CreateStreamOnHGlobal(hglobal, FALSE, &is); Gdiplus::Image image_plus(is); is->Release(); GlobalFree(hglobal); w = image_plus.GetWidth(); h = image_plus.GetHeight(); auto hdc = GetDC(hwnd); image_dc = CreateCompatibleDC(hdc); auto image_bmp = CreateCompatibleBitmap(hdc, w, h); SelectObject(image_dc, image_bmp); Graphics graphics(image_dc); graphics.DrawImage(&image_plus, 0, 0); ReleaseDC(hwnd, hdc); RECT window_rect; GetWindowRect(GetDesktopWindow(), &window_rect); SetWindowLongA(hwnd, GWL_STYLE, 0); SetWindowPos(hwnd, HWND_TOPMOST, (window_rect.right - w) / 2, (window_rect.bottom - h) / 2, w, h, SWP_FRAMECHANGED); return 0; } case WM_DESTROY: DeleteDC(image_dc); GdiplusShutdown(gdi_token); PostQuitMessage(0); return 0; case WM_CLOSE: DestroyWindow(hwnd); return DefWindowProcA(hwnd, message, wparam, lparam); case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); BitBlt(hdc, 0, 0, w, h, image_dc, 0, 0, SRCCOPY); //SetTextAlign(hdc, TA_CENTER | TA_BOTTOM); { std::lock_guard lock(mutex); TextOutW(hdc, 2, h - 40, state.phase.c_str(), state.phase.length()); TextOutW(hdc, 2, h - 20, state.detail.c_str(), state.detail.length()); } EndPaint(hwnd, &ps); return 0; } case WM_ERASEBKGND: return 1; default: return DefWindowProcA(hwnd, message, wparam, lparam); } } void __cdecl InitEnd() { patch::splash.finish(); } } // namespace patch #endif // ifdef PATCH_SWITCH_SPLASH ================================================ FILE: patch/patch_splash.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_SPLASH #include #include #include #include #include #include #include #include #pragma comment(lib, "Shlwapi.lib") #include #pragma comment(lib, "gdiplus.lib") #include "global.hpp" #include "util.hpp" #include "debug_log.hpp" #include "config_rw.hpp" namespace patch { void __cdecl InitEnd(); // init at dllload // スプラッシュウィンドウ inline class splash_t { inline static std::thread thread; inline static std::mutex mutex; inline static struct { std::wstring phase; std::wstring detail; } state; __declspec(align(4)) inline static std::atomic load_finished{false}; __declspec(align(4)) inline static std::atomic update_state{false}; inline static const char classname[] = "patchaul_splash"; static LRESULT CALLBACK SplashWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); inline static const char key[] = "splash"; bool enabled = false; bool enabled_i; public: void init() { enabled_i = enabled; WNDCLASSA winc{ .style = 0, .lpfnWndProc = SplashWndProc, .cbClsExtra = 0, .cbWndExtra = 0, .hInstance = GLOBAL::patchaul_hinst, .hIcon = LoadIconA(NULL, IDI_APPLICATION), .hCursor = LoadCursorA(NULL, IDC_ARROW), .hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH), .lpszMenuName = NULL, .lpszClassName = classname }; RegisterClassA(&winc); { // 0x02e70 の Init の ret にスプラッシュウィンドウを閉じる処理を仕込む OverWriteOnProtectHelper h(GLOBAL::aviutl_base + 0x041af, 0x21); store_i16(GLOBAL::aviutl_base + 0x041af, '\xeb\x11'); // jmp near +0x11 store_i16(GLOBAL::aviutl_base + 0x041c2, '\x50\xb9'); // push eax | mov ecx, (i32) store_i32(GLOBAL::aviutl_base + 0x041c4, &InitEnd); store_i16(GLOBAL::aviutl_base + 0x041c8, '\xff\xd1'); // call ecx store_i32(GLOBAL::aviutl_base + 0x041ca, '\x58\x8b\xe5\x5d'); // pop eax | mov esp, ebp | pop ebp store_i8(GLOBAL::aviutl_base + 0x041ce, '\xc3'); // ret } } ~splash_t() { finish(); UnregisterClassA(classname, GLOBAL::patchaul_hinst); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } void start() { finish(); thread = std::thread([] { //WS_EX_LAYERED auto hwnd = CreateWindowExA(0, classname, "", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL); MSG message; while (true) { if (PeekMessageA(&message, NULL, 0, 0, PM_NOREMOVE)) { if (message.message == WM_QUIT)break; LRESULT result = GetMessageA(&message, NULL, 0, 0); if (result <= 0)break; DispatchMessageA(&message); } else { Sleep(50); } if (update_state.load()) { update_state.store(false); InvalidateRect(hwnd, NULL, FALSE); auto updated = UpdateWindow(hwnd); //debug_log(updated); } if (load_finished.load()) DestroyWindow(hwnd); } }); } void finish() { if (thread.joinable()) { load_finished.store(true); thread.join(); load_finished.store(false); } } void set_phase(std::wstring_view phase, std::wstring_view detail) { { std::lock_guard lock(mutex); state.phase = phase; state.detail = detail; } update_state.store(true); } void set_detail(std::wstring_view detail) { { std::lock_guard lock(mutex); state.detail = detail; } update_state.store(true); } } splash; } // namespace patch #endif // ifdef PATCH_SWITCH_SPLASH ================================================ FILE: patch/patch_susie_load.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_susie_load.hpp" #ifdef PATCH_SWITCH_SUSIE_LOAD namespace patch { void __cdecl susie_load_t::LoadSpi(LPCSTR dir) { auto loaded_spi_array = reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::loaded_spi_array); ZeroMemory(loaded_spi_array, sizeof(ExEdit::structSPI) * 32); //MyFindFirstFile reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::MyFindFirstFile)(dir); for (int i = 0; i < 32;) { char path[260]; // MyFindNextFile if (reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::MyFindNextFile)(path) != TRUE)return; if (auto hMod = LoadLibraryA(path); hMod != NULL) { auto spi_GetPluginInfo = reinterpret_cast(GetProcAddress(hMod, "GetPluginInfo")); if (!spi_GetPluginInfo) continue; loaded_spi_array[i].GetPicture = reinterpret_cast(GetProcAddress(hMod, "GetPicture")); loaded_spi_array[i].hmodule = hMod; spi_GetPluginInfo(1, loaded_spi_array[i].information, 256); int j = 2; auto ext = loaded_spi_array[i].extension; auto ext_pos = 0; auto ext_size = std::size(loaded_spi_array[i].extension); while (true) { char buf[256]; auto ret = spi_GetPluginInfo(j, buf, sizeof(buf)); if (ret == 0)break; const std::string_view view(buf); size_t pos_a = 0; size_t pos_b; while ((pos_b = view.find_first_of(';', pos_a)) != std::string_view::npos) { auto ext_pos_new = ext_pos + (pos_b - pos_a) + 1; if (ext_pos_new >= ext_size) { if (i == 31) goto BREAK_EXT; ext[ext_pos - 1] = '\0'; LoadLibraryA(path); i++; ext = loaded_spi_array[i].extension; ext_pos = 0; ext_pos_new = (pos_b - pos_a) + 1; loaded_spi_array[i].GetPicture = loaded_spi_array[i - 1].GetPicture; loaded_spi_array[i].hmodule = hMod; strcpy_s(loaded_spi_array[i].information, loaded_spi_array[i - 1].information); } strncpy_s(ext + ext_pos, ext_size - ext_pos, buf + pos_a, pos_b - pos_a); ext_pos = ext_pos_new; ext[ext_pos - 1] = ';'; pos_a = pos_b + 1; } if (ret - pos_a > 0) { auto ext_pos_new = ext_pos + (ret - pos_a) + 1; if (ext_pos_new >= ext_size) { if (i == 31) goto BREAK_EXT; ext[ext_pos - 1] = '\0'; LoadLibraryA(path); i++; ext = loaded_spi_array[i].extension; ext_pos = 0; ext_pos_new = (pos_b - pos_a) + 1; loaded_spi_array[i].GetPicture = loaded_spi_array[i - 1].GetPicture; loaded_spi_array[i].hmodule = hMod; strcpy_s(loaded_spi_array[i].information, loaded_spi_array[i - 1].information); } strncpy_s(ext + ext_pos, ext_size - ext_pos, buf + pos_a, ret - pos_a); ext_pos = ext_pos_new; ext[ext_pos - 1] = ';'; } if (j >= (std::numeric_limits::max)() - 1)break; j += 2; } BREAK_EXT: if (ext_pos != 0) ext[ext_pos - 1] = '\0'; //spi_GetPluginInfo(2, loaded_spi_array[i].extension, 256); i++; } } } } // namespace patch #endif // ifdef PATCH_SWITCH_SUSIE_LOAD ================================================ FILE: patch/patch_susie_load.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_SUSIE_LOAD #include #include "util.hpp" #include "global.hpp" #include "offset_address.hpp" #include "restorable_patch.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // Susieのプラグインで正しく対応拡張子情報を取得できない inline class susie_load_t { static void __cdecl LoadSpi(LPCSTR dir); inline static const char key[] = "susie_load"; bool enabled = true; std::optional rpf; public: bool init() { rpf.emplace(GLOBAL::exedit_base + OFS::ExEdit::LoadSpi, &LoadSpi); rpf->switching(enabled); } void switching(bool flag) { rpf->switching(enabled = flag); } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } }susie_load; } // namespace patch #endif // ifdef PATCH_SWITCH_SUSIE_LOAD ================================================ FILE: patch/patch_sysinfo_write.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_SYSINFO_MODIFY #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "version.hpp" namespace patch { // init at dllload // Sysinfo::versionの書き換え inline class sysinfo_info_write_t { private: inline static const char str[] = "1.10 (patched " PATCH_VERSION_STR ")"; public: void operator()() { OverWriteOnProtectHelper(GLOBAL::aviutl_base + OFS::AviUtl::getsys_versionstr_arg, 4).store_i32(0, &str); } } sysinfo_info_write; } // namespace patch #endif // ifdef PATCH_SWITCH_SYSINFO_MODIFY ================================================ FILE: patch/patch_text_op_size.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_TEXT_OP_SIZE #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" namespace patch { // init at exedit load // 制御文字のサイズのみを変えるとフォントの情報が壊れる inline class text_op_size_t { std::optional rp; bool enabled = true; inline static const char key[] = "text_op_size"; public: void init() { rp.emplace(GLOBAL::exedit_base + OFS::ExEdit::text_op_logfont_size, sizeof(LOGFONTW)); rp->switching(enabled); } void switching(bool flag) { rp->switching(enabled = flag); } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } text_op_size; } // namespace patch #endif // ifdef PATCH_SWITCH_TEXT_OP_SIZE ================================================ FILE: patch/patch_theme_cc.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_THEME_CC #include "global.hpp" #include "util.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // ConstChanger相当のテーマ機能 inline class theme_cc_t { inline static void* LayerLockBorder_mod_jmp_adr; inline static void* LayerLockBorder_mod_jmp_ret_adr; inline static uint32_t* LayerLockBorder_ptr; using ColorBGR = config_type::ColorBGR; using ColorBGR2 = config_type::ColorBGR2; using ColorBGR2_Opt = config_type::ColorBGR2_Opt; using ColorBGR3 = config_type::ColorBGR3; bool enabled = true; bool enabled_i; inline static const char key[] = "theme_cc"; struct { inline static const char name[] = "layer"; std::optional height_large; std::optional height_medium; std::optional height_small; ColorBGR2_Opt link_col; ColorBGR2_Opt clipping_col; ColorBGR2_Opt lock_col; std::optional hide_alpha; //std::optional name_height; inline static const char key_large[] = "height_large"; inline static const char key_medium[] = "height_medium"; inline static const char key_small[] = "height_small"; inline static const char key_link_col[] = "link_col"; inline static const char key_clipping_col[] = "clipping_col"; inline static const char key_lock_col[] = "lock_col"; inline static const char key_hide_alpha[] = "hide_alpha"; //inline static const char key_name_height[] = "name_height"; void load(ConfigReader& cr) { cr.regist(key_large, [this](json_value_s* value) { ConfigReader::load_variable(value, height_large); }); cr.regist(key_medium, [this](json_value_s* value) { ConfigReader::load_variable(value, height_medium); }); cr.regist(key_small, [this](json_value_s* value) { ConfigReader::load_variable(value, height_small); }); cr.regist(key_link_col, [this](json_value_s* value) { ConfigReader::load_variable(value, link_col); }); cr.regist(key_clipping_col, [this](json_value_s* value) { ConfigReader::load_variable(value, clipping_col); }); cr.regist(key_lock_col, [this](json_value_s* value) { ConfigReader::load_variable(value, lock_col); }); cr.regist(key_hide_alpha, [this](json_value_s* value) { ConfigReader::load_variable(value, hide_alpha); }); } void store(ConfigWriter& cw) { cw.append(key_large, height_large); cw.append(key_medium, height_medium); cw.append(key_small, height_small); cw.append(key_link_col, link_col); cw.append(key_clipping_col, clipping_col); cw.append(key_lock_col, lock_col); cw.append(key_hide_alpha, hide_alpha); } } layer; struct { inline static const char name[] = "object"; ColorBGR3 media_col; ColorBGR3 mfilter_col; ColorBGR3 audio_col; ColorBGR3 afilter_col; ColorBGR3 control_col; ColorBGR3 inactive_col; ColorBGR clipping_col; std::optional clipping_height; std::optional> midpt_size; ColorBGR2 name_col; inline static const char key_media_col[] = "media_col"; inline static const char key_mfilter_col[] = "mfilter_col"; inline static const char key_audio_col[] = "audio_col"; inline static const char key_afilter_col[] = "afilter_col"; inline static const char key_control_col[] = "control_col"; inline static const char key_inactive_col[] = "inactive_col"; inline static const char key_clipping_col[] = "clipping_col"; inline static const char key_clipping_height[] = "clipping_height"; inline static const char key_midpt_size[] = "midpt_size"; inline static const char key_name_col[] = "name_col"; void load(ConfigReader& cr) { cr.regist(key_media_col, [this](json_value_s* jv) { ConfigReader::load_variable(jv, media_col); }); cr.regist(key_mfilter_col, [this](json_value_s* jv) { ConfigReader::load_variable(jv, mfilter_col); }); cr.regist(key_audio_col, [this](json_value_s* jv) { ConfigReader::load_variable(jv, audio_col); }); cr.regist(key_afilter_col, [this](json_value_s* jv) { ConfigReader::load_variable(jv, afilter_col); }); cr.regist(key_control_col, [this](json_value_s* jv) { ConfigReader::load_variable(jv, control_col); }); cr.regist(key_inactive_col, [this](json_value_s* jv) { ConfigReader::load_variable(jv, inactive_col); }); cr.regist(key_clipping_col, [this](json_value_s* jv) { ConfigReader::load_variable(jv, clipping_col); }); cr.regist(key_clipping_height, [this](json_value_s* jv) { ConfigReader::load_variable(jv, clipping_height); }); cr.regist(key_midpt_size, [this](json_value_s* jv) { ConfigReader::load_variable(jv, midpt_size); }); cr.regist(key_name_col, [this](json_value_s* jv) { ConfigReader::load_variable(jv, name_col); }); } void store(ConfigWriter& cw) { cw.append(key_media_col, media_col); cw.append(key_mfilter_col, mfilter_col); cw.append(key_audio_col, audio_col); cw.append(key_afilter_col, afilter_col); cw.append(key_control_col, control_col); cw.append(key_inactive_col, inactive_col); cw.append(key_clipping_col, clipping_col); cw.append(key_clipping_height, clipping_height); cw.append(key_midpt_size, midpt_size); cw.append(key_name_col, name_col); } } object; struct { inline static const char name[] = "timeline"; ColorBGR2 scale_col; ColorBGR2 bpm_grid_col; inline static const char key_scale_col[] = "scale_col"; inline static const char key_bpm_grid_col[] = "bpm_grid_col"; void load(ConfigReader& cr) { cr.regist(key_scale_col, [this](json_value_s* jv) { ConfigReader::load_variable(jv, scale_col); }); cr.regist(key_bpm_grid_col, [this](json_value_s* jv) { ConfigReader::load_variable(jv, bpm_grid_col); }); } void store(ConfigWriter& cw) { cw.append(key_scale_col, scale_col); cw.append(key_bpm_grid_col, bpm_grid_col); } } timeline; public: void init() { enabled_i = enabled; if (!enabled_i) return; { auto ptr = GLOBAL::executable_memory_cursor; GLOBAL::executable_memory_cursor += 17; const auto adr = GLOBAL::exedit_base + OFS::ExEdit::LayerLockBorder_mod; LayerLockBorder_mod_jmp_ret_adr = reinterpret_cast(adr + 8); LayerLockBorder_mod_jmp_adr = ptr; store_i32(ptr, load_i32(adr)); // CALL SelectObject store_i32(ptr + 4, load_i32(adr + 4)); store_i16(ptr + 6, '\x68'); // PUSH (i32) store_i32(ptr + 7, 0); LayerLockBorder_ptr = reinterpret_cast(ptr + 7); store_i16(ptr + 11, '\xff\x25'); // jmp [i32] store_i32(ptr + 13, &LayerLockBorder_mod_jmp_ret_adr); OverWriteOnProtectHelper h(adr, 6); h.store_i16(0, '\xff\x25'); // jmp [i32] h.store_i32(2, &LayerLockBorder_mod_jmp_adr); } { { OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::layer_height_array, 12); auto store = [&h](size_t adr_ofs, std::optional& val) { auto in_range = [](size_t x) { return 6 <= x && x <= 60; }; if (val && in_range(*val)) { h.store_i32(adr_ofs, *val); } else { val = h.load_i32(adr_ofs); } }; store(0, layer.height_large); store(4, layer.height_medium); store(8, layer.height_small); } { auto store = [](i32 adr_border, i32 adr_center, config_type::ColorBGR2_Opt& val) { OverWriteOnProtectHelper hb(adr_border, 4); OverWriteOnProtectHelper hc(adr_center, 4); if (val.has_value()) { hb.store_i32(0, val.ary[0].to_col_rgb()); if(val.ary[1].is_valid()) hc.store_i32(0, val.ary[1].to_col_rgb()); else hc.store_i32(0, val.ary[0].to_col_rgb()); } else { const auto cb = config_type::ColorBGR::from_rgb(hb.load_i32(0)); const auto cc = config_type::ColorBGR::from_rgb(hc.load_i32(0)); if (cb == cc) val = { cb, {} }; else val = { cb,cc }; } }; store( GLOBAL::exedit_base + OFS::ExEdit::LayerClippingBorder, GLOBAL::exedit_base + OFS::ExEdit::LayerClippingCenter, layer.clipping_col ); store( GLOBAL::exedit_base + OFS::ExEdit::LayerLinkBorder, GLOBAL::exedit_base + OFS::ExEdit::LayerLinkCenter, layer.link_col ); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::LayerLockCenter, 4); if (auto& o = layer.lock_col; o.has_value()) { *LayerLockBorder_ptr = o.ary[0].to_col_rgb(); h.store_i32(0, o.ary[1].to_col_rgb()); } else { o = { config_type::ColorBGR::from_rgb(0), config_type::ColorBGR::from_rgb(h.load_i32(0)) }; } } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::LayerHideAlpha, 8); if (auto& o = layer.hide_alpha) { h.store_i64(0, std::bit_cast(*o)); } else { o = h.load_i64(0); } } /* { OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::LayerNameRectWidth, 1); if (auto& o = layer.name_height) { h.store_i8(0, static_cast(*o)); } else { o = h.load_i8(0); } } */ } { { auto store = [](uint32_t adr, config_type::ColorBGR3& col) { OverWriteOnProtectHelper h(adr, 36); if (col.has_value()) { h.store_i32(0 , col.ary[0].r); h.store_i32(4 , col.ary[0].g); h.store_i32(8 , col.ary[0].b); h.store_i32(12, col.ary[1].r); h.store_i32(16, col.ary[1].g); h.store_i32(20, col.ary[1].b); h.store_i32(24, col.ary[2].r); h.store_i32(28, col.ary[2].g); h.store_i32(32, col.ary[2].b); } else { col = { config_type::ColorBGR{ h.load_i32(8), h.load_i32(4), h.load_i32(0) }, config_type::ColorBGR{ h.load_i32(20), h.load_i32(16), h.load_i32(12) }, config_type::ColorBGR{ h.load_i32(32), h.load_i32(28), h.load_i32(24) } }; } }; store(GLOBAL::exedit_base + OFS::ExEdit::ObjectColorControl, object.control_col); store(GLOBAL::exedit_base + OFS::ExEdit::ObjectColorMedia, object.media_col); store(GLOBAL::exedit_base + OFS::ExEdit::ObjectColorMFilter, object.mfilter_col); store(GLOBAL::exedit_base + OFS::ExEdit::ObjectColorSound, object.audio_col); store(GLOBAL::exedit_base + OFS::ExEdit::ObjectColorSFilter, object.afilter_col); store(GLOBAL::exedit_base + OFS::ExEdit::ObjectColorInactive, object.inactive_col); } { OverWriteOnProtectHelper hb(GLOBAL::exedit_base + OFS::ExEdit::ObjectClippingColorB, 5); //OverWriteOnProtectHelper hg(GLOBAL::exedit_base + OFS::ExEdit::ObjectClippingColorG, 1); //OverWriteOnProtectHelper hr(GLOBAL::exedit_base + OFS::ExEdit::ObjectClippingColorR, 1); if (auto& o = object.clipping_col; o.is_valid()) { hb.store_i8(0, o.b); hb.store_i8(2, o.g); hb.store_i8(4, o.r); } else { o = { hb.load_i8(0), hb.load_i8(2), hb.load_i8(4) }; } } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::ObjectClippingHeight, 1); if (auto& o = object.clipping_height) h.store_i8(0, static_cast(*o)); else o = h.load_i8(0); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::MidPointSize, 12); if (auto& o = object.midpt_size; o) { h.store_i32(0, static_cast(o.value()[0])); h.store_i32(4, static_cast(o.value()[1])); h.store_i32(8, static_cast(o.value()[2])); } else { o.emplace(); o.value()[0] = h.load_i32(0); o.value()[1] = h.load_i32(4); o.value()[2] = h.load_i32(8); } } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + OFS::ExEdit::ObjectNameColor, 8 ); if (auto& o = object.name_col; o.has_value()) { h.store_i32(0, o.ary[0].to_col()); h.store_i32(4, o.ary[1].to_col()); } else { o.ary[0] = h.load_i32(0); o.ary[1] = h.load_i32(4); } } } { { OverWriteOnProtectHelper hf(GLOBAL::exedit_base + OFS::ExEdit::ScaleColorForeGround, 4); OverWriteOnProtectHelper hb(GLOBAL::exedit_base + OFS::ExEdit::ScaleColorBackGround, 4); if (auto& val = timeline.scale_col; val.has_value()) { hf.store_i32(0, val.ary[0].to_col_rgb()); hb.store_i32(0, val.ary[1].to_col_rgb()); } else { val = { config_type::ColorBGR::from_rgb(hf.load_i32(0)), config_type::ColorBGR::from_rgb(hb.load_i32(0)) }; } }; { OverWriteOnProtectHelper hm(GLOBAL::exedit_base + OFS::ExEdit::BPMGridColorMeasure, 4); OverWriteOnProtectHelper hb(GLOBAL::exedit_base + OFS::ExEdit::BPMGridColorBeat, 4); if (auto& val = timeline.bpm_grid_col; val.has_value()) { hm.store_i32(0, val.ary[0].to_col()); hb.store_i32(0, val.ary[1].to_col()); } else { val = { hm.load_i32(0),hb.load_i32(0) }; } } } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } void config_load(ConfigReader& cr) { cr.regist(layer.name, [this](json_value_s* value) { ConfigReader cr(value); layer.load(cr); cr.load(); }); cr.regist(object.name, [this](json_value_s* value) { ConfigReader cr(value); object.load(cr); cr.load(); }); cr.regist(timeline.name, [this](json_value_s* value) { ConfigReader cr(value); timeline.load(cr); cr.load(); }); } void config_store(ConfigWriter& cw) { { ConfigWriter cw_layer(cw.get_level() + 1); layer.store(cw_layer); std::stringstream ss; cw_layer.write(ss); cw.append(layer.name, ss.str()); } { ConfigWriter cw_object(cw.get_level() + 1); object.store(cw_object); std::stringstream ss; cw_object.write(ss); cw.append(object.name, ss.str()); } { ConfigWriter cw_timeline(cw.get_level() + 1); timeline.store(cw_timeline); std::stringstream ss; cw_timeline.write(ss); cw.append(timeline.name, ss.str()); } } } theme_cc; } // namespace patch #endif // ifdef PATCH_SWITCH_THEME_CC ================================================ FILE: patch/patch_tra_aviutlfilter.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_TRA_AVIUTL_FILTER #include #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" namespace patch { // init at exedit load // 拡張編集以外のフィルタのトラックバーにトラックバー変化方法スクリプトを適用していると例外になる inline class tra_aviutlfilter_t { bool enabled = true; bool enabled_i; inline static const char key[] = "tra_aviutlfilter"; public: void init() { enabled_i = enabled; if (!enabled_i)return; auto& cursor = GLOBAL::executable_memory_cursor; OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x06577a, 6); h.store_i16(0, '\x90\xe9'); h.store_i32(2, cursor - (GLOBAL::exedit_base + 0x065780)); /* 1006577a 8b91d0000000 mov edx,dword ptr [ecx+000000d0] ; filter_param_ptr->track_link 10065780 8b89cc000000 mov ecx,dword ptr [ecx+000000cc] ; filter_param_ptr->track_scale 10065786 03c3 add eax,ebx 10065788 50 push eax 10065789 52 push edx 1006578a 8b1481 mov edx,dword ptr [ecx+eax*4] 1006578d 8b4514 mov eax,dword ptr [ebp+14] 1006577a 8b91d0000000 mov edx,dword ptr [ecx+000000d0] ↓ 1006577a 90e9XXXXXXXX jmp executable_memory_cursor ; 拡張編集以外のフィルタの場合は ; filter_param_ptr->track_link の部分を 0 に ; filter_param_ptr->track_scale[eax] の部分を 1 に */ static const char code_put[] = "\x03\xc3" // add eax, ebx "\x50" // push eax "\x8a\x51\x03" // mov dl,[ecx + 03] "\xf6\xc2\x04" // test dl,04 "\x74\x14" // jz +20byte "\x8b\x91\xd0" "\x00\x00\x00" // mov edx, dword ptr[ecx + 000000d0] "\x8b\x89\xcc" "\x00\x00\x00" // mov ecx, dword ptr[ecx + 000000cc] "\x85\xc9" // test ecx "\x0f\x85XXXX" // jnz exedit_base + 65789 "\x33\xd2" // xor edx "\x52" // push edx "\x42" // inc edx "\xe9XXXX" // jmp exedit_base + 6578d ; memcpy(cursor, code_put, sizeof(code_put) - 1); store_i32(cursor + 27, GLOBAL::exedit_base + 0x065789 - (uint32_t)(cursor + 31)); cursor += sizeof(code_put) - 1; store_i32(cursor - 4, GLOBAL::exedit_base + 0x06578d - (uint32_t)cursor); } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } tra_aviutlfilter; } // namespace patch #endif // ifdef PATCH_SWITCH_TRA_AVIUTL_FILTER ================================================ FILE: patch/patch_tra_change_drawfilter.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_tra_change_drawfilter.hpp" #ifdef PATCH_SWITCH_TRA_CHANGE_DRAWFILTER namespace patch { int __cdecl tra_change_drawfilter_t::switch_drawfilter_trackdata_to_mem(int* data, int object_idx, int track_begin, int track_id) { if (0 <= track_id) { auto& eop = (*ObjectArrayPointer_ptr)[object_idx]; int tr = track_begin + track_id; data[0] = eop.track_value_left[tr]; data[1] = eop.track_value_right[tr]; data[2] = *(int*)&eop.track_mode[tr]; data[3] = eop.track_param[tr]; return 4; } return 0; } int __cdecl tra_change_drawfilter_t::switch_drawfilter_mem_to_trackdata(int* data, int object_idx, int track_begin, int pre_track_exists, int track_id) { if (0 <= pre_track_exists) { if (0 <= track_id) { auto& eop = (*ObjectArrayPointer_ptr)[object_idx]; int tr = track_begin + track_id; eop.track_value_left[tr] = data[0]; eop.track_value_right[tr] = data[1]; *(int*)&eop.track_mode[tr] = data[2]; eop.track_param[tr] = data[3]; } return 4; } return 0; } } // namespace patch #endif // ifdef PATCH_SWITCH_TRA_CHANGE_DRAWFILTER ================================================ FILE: patch/patch_tra_change_drawfilter.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_TRA_CHANGE_DRAWFILTER #include #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "restorable_patch.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // 標準描画-拡張描画-パーティクル出力 を切り替えた際にトラックの設定値(移動フレーム間隔)が0になるのを修正 // 値を引き継ぐための関数に足りていなかったので追加した関数を置き換える inline class tra_change_drawfilter_t { static int __cdecl switch_drawfilter_trackdata_to_mem(int* data, int object_idx, int track_begin, int track_id); static int __cdecl switch_drawfilter_mem_to_trackdata(int* data, int object_idx, int track_begin, int pre_track_exists, int track_id); bool enabled = true; bool enabled_i; inline static const char key[] = "tra_change_drawfilter"; inline static ExEdit::Object** ObjectArrayPointer_ptr; public: void init() { enabled_i = enabled; if (!enabled_i)return; ObjectArrayPointer_ptr = reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::ObjectArrayPointer); { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x44280, 5); h.store_i8(0, '\xe9'); // jmp h.replaceNearJmp(1, &switch_drawfilter_trackdata_to_mem); } { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x44530, 5); h.store_i8(0, '\xe9'); // jmp h.replaceNearJmp(1, &switch_drawfilter_mem_to_trackdata); } } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } tra_change_drawfilter; } // namespace patch #endif // ifdef PATCH_SWITCH_TRA_CHANGE_DRAWFILTER ================================================ FILE: patch/patch_tra_specified_speed.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_TRA_SPECIFIED_SPEED #include #include #include "global.hpp" #include "offset_address.hpp" #include "util.hpp" #include "restorable_patch.hpp" #include "config_rw.hpp" namespace patch { // init at exedit load // トラック変化方式の「移動量指定」で計算が足りていなかった(主に時間制御との組み合わせでバグる)のを修正 inline class tra_specified_speed_t { bool enabled = true; bool enabled_i; inline static const char key[] = "tra_specified_speed"; public: void init() { enabled_i = enabled; if (!enabled_i)return; auto& cursor = GLOBAL::executable_memory_cursor; /* 1006821c 8b8cb7f8000000 mov ecx,dword ptr [edi+esi*4+000000f8] ;ecx = obj[object_idx].track_value_left[track_begin] 10068223 0faf442458 imul eax,dword ptr [esp+58] ;eax *= obj_frame ↓ 1006821c e8XxXxXxXx call bin_data 10068221 8b8cb7f8000000 mov ecx,dword ptr [edi+esi*4+000000f8] ;ecx = obj[object_idx].track_value_left[track_begin] ; arg3_subframeが0以外の時はobj_frameが100倍されてarg3_subframeが加算されている ; 移動量指定では100で割るコードを忘れている */ OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x06821c, 12); h.store_i8(0, '\xe8'); h.replaceNearJmp(1, cursor); h.store_i32(5, '\x8b\x8c\xb7\xf8'); h.store_i32(8, '\xf8\x00\x00\x00'); // \xf8は範囲ダブらせてstore_i32 * 2 で行っています static const char code_put[] = "\x0f\xaf\x44\x24\x5c" // imul eax,dword ptr [esp+5c] ;eax *= obj_frame "\x8b\x4d\x10" // mov ecx,dword ptr [ebp+10] ;ecx = arg3_subframe "\x85\xc9" // test ecx,ecx "\x74\x08" // jz skip 8 byte ;if(ecx == 0)return "\xb9\x64\x00\x00\x00" // mov ecx,00000064 ;ecx = 100 "\x99" // cdq "\xf7\xf9" // idiv ecx ;edx = eax % ecx, eax /= ecx "\xc3" // ret ;return ; memcpy(cursor, code_put, sizeof(code_put) - 1); cursor += sizeof(code_put) - 1; } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } tra_specified_speed; } // namespace patch #endif // ifdef PATCH_SWITCH_TRA_SPECIFIED_SPEED ================================================ FILE: patch/patch_undo.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "patch_undo.hpp" namespace patch { #ifdef PATCH_SWITCH_UNDO void __cdecl undo_t::set_undo_wrap_3e037(unsigned int object_idx, unsigned int flag) { auto exists_movable_playback_pos = [](unsigned int object_idx) { auto& exdata_buffer = *exdata_buffer_ptr; auto eop = &(*ObjectArrayPointer_ptr)[object_idx]; for (int i = 0; i < 12; i++) { auto fparam = &eop->filter_param[i]; switch (fparam->id) { case FILTER_ID_MOVIE: if (eop->track_mode[fparam->track_begin].num == 0) { if (eop->check_value[fparam->check_begin] == 0) { auto exdata = reinterpret_cast(reinterpret_cast(exdata_buffer) + 4 + eop->exdata_offset + fparam->exdata_offset); if (exdata->frame_n > 0) { return true; } } } break; case FILTER_ID_MOVIE_MIX: if (eop->track_mode[fparam->track_begin].num == 0) { if (eop->check_value[fparam->check_begin] == 0) { auto exdata = reinterpret_cast(reinterpret_cast(exdata_buffer) + 4 + eop->exdata_offset + fparam->exdata_offset); if (exdata->frame_n > 0) { return true; } } } break; case FILTER_ID_AUDIO: if (eop->track_mode[fparam->track_begin].num == 0) { if (eop->check_value[fparam->check_begin] == 0 && eop->check_value[fparam->check_begin + 1] == 0) { auto exdata = reinterpret_cast(reinterpret_cast(exdata_buffer) + 4 + eop->exdata_offset + fparam->exdata_offset); if (exdata->frame_n > 0) { return true; } } } break; case FILTER_ID_WAVEFORM: if (eop->track_mode[fparam->track_begin].num == 0) { if (eop->check_value[fparam->check_begin + 3] == 0) { auto exdata = reinterpret_cast(reinterpret_cast(exdata_buffer) + 4 + eop->exdata_offset + fparam->exdata_offset); if (exdata->frame_n > 0) { return true; } } } break; case FILTER_ID_SCENE: if (eop->track_mode[fparam->track_begin].num == 0) { if (eop->check_value[fparam->check_begin] == 0) { auto exdata = reinterpret_cast(reinterpret_cast(exdata_buffer) + 4 + eop->exdata_offset + fparam->exdata_offset); if (scene_setting[exdata->scene].max_frame > 0) { return true; } } } break; case FILTER_ID_SCENE_AUDIO: if (eop->track_mode[fparam->track_begin].num == 0) { if (eop->check_value[fparam->check_begin] == 0 && eop->check_value[fparam->check_begin + 1] == 0) { auto exdata = reinterpret_cast(reinterpret_cast(exdata_buffer) + 4 + eop->exdata_offset + fparam->exdata_offset); if (scene_setting[exdata->scene].max_frame > 0) { return true; } } } break; case -1: return false; } } return false; }; if (*timeline_obj_click_mode_ptr == 2 || (*timeline_obj_click_mode_ptr == 3 && (*timeline_edit_both_adjacent_ptr & 1))) { // 左端 || (右端 && 環境設定の隣接するオブジェクトも選択がON ) auto eop = &(*ObjectArrayPointer_ptr)[object_idx]; int obj_idx = eop->index_midpt_leader; if (obj_idx == -1) { if (exists_movable_playback_pos(object_idx)) { set_undo(object_idx, 0); return; } } else if (obj_idx == object_idx) { if (exists_movable_playback_pos(obj_idx)) { while (0 <= obj_idx) { set_undo(obj_idx, 0); obj_idx = NextObjectIdxArray[obj_idx]; } return; } } } set_undo(object_idx, flag); } int __cdecl undo_t::efDraw_func_WndProc_wrap_06e2b4(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam, AviUtl::EditHandle* editp, ExEdit::Filter* efp) { auto ret = efDraw_func_WndProc(hwnd, message, wparam, lparam, editp, efp); if (ret) return ret; if (LOWORD(wparam) == 7708) { AddUndoCount(); set_undo(object(efp->processing) - 1, 1); } return ret; } int __stdcall undo_t::f8b97f(HWND hwnd, ExEdit::Filter* efp, WPARAM wparam, LPARAM lparam) { interval_set_undo(object(efp->processing) - 1, 1); return SendMessageA(hwnd, CB_GETLBTEXT, wparam, lparam); } int __stdcall undo_t::f8ba87_8bad5(ExEdit::Filter* efp, HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { int ret = SendMessageA(hwnd, message, wparam, lparam); if (ret != -1) { AddUndoCount(); set_undo(object(efp->processing) - 1, 1); } return ret; } int __stdcall undo_t::f8bb4d_8bbcc(int value, int8_t* exdata, int offset, ExEdit::Filter* efp) { if (value < -100) value = -100; else if (100 < value) value = 100; if (exdata[offset] != value) { AddUndoCount(); set_undo(object(efp->processing) - 1, 1); } return value; } int* __stdcall undo_t::f59e27(WPARAM wparam, LPARAM lparam, ExEdit::Filter* efp, UINT message) { if ((message != 0x702) || (wparam != 0x651e24)) return 0; int* exdata_layer_num = (int*)efp->exdata_ptr; int new_layer_num = *exdata_layer_num - *(int*)(lparam + 0x10); if (new_layer_num < 0) new_layer_num = 0; else if (99 < new_layer_num) new_layer_num = 99; if (new_layer_num != *exdata_layer_num) { AddUndoCount(); set_undo(object(efp->processing) - 1, 1); } return exdata_layer_num; } int __stdcall undo_t::f8b9f0(ExEdit::Filter* efp, HWND hWnd, LPWSTR lpString, int nMaxCount) { interval_set_undo(object(efp->processing) - 1, 1); return GetWindowTextW(hWnd, lpString, nMaxCount); } int __stdcall undo_t::f875ef(ExEdit::Filter* efp, HWND hWnd, LPWSTR lpString) { return f8b9f0(efp, hWnd, lpString, 0x400); } int __cdecl undo_t::NormalizeExeditTimelineY_wrap_3c8fa_42629_42662_42924_42a0a(int timeline_y) { timeline_y = NormalizeExeditTimelineY(timeline_y); AddUndoCount(); set_undo(timeline_y, 0x10); return timeline_y; } int __cdecl undo_t::NormalizeExeditTimelineY_wrap_4253e(int timeline_y) { timeline_y = NormalizeExeditTimelineY(timeline_y); AddUndoCount(); BOOL other_flag = FALSE; for (int i = 0; i < 100; i++) { if (timeline_y != i) { if (has_flag((*layer_setting_ofsptr_ptr)[i].flag, ExEdit::LayerSetting::Flag::UnDisp)) { other_flag = TRUE; break; } } } if (has_flag((*layer_setting_ofsptr_ptr)[timeline_y].flag, ExEdit::LayerSetting::Flag::UnDisp)) { set_undo(timeline_y, 0x10); } if (other_flag) { for (int i = 0; i < 100; i++) { if (timeline_y != i) { if (has_flag((*layer_setting_ofsptr_ptr)[i].flag, ExEdit::LayerSetting::Flag::UnDisp)) { set_undo(i, 0x10); } } } } else { for (int i = 0; i < 100; i++) { if (timeline_y != i) { if (!has_flag((*layer_setting_ofsptr_ptr)[i].flag, ExEdit::LayerSetting::Flag::UnDisp)) { set_undo(i, 0x10); } } } } return timeline_y; } ExEdit::Object* __stdcall undo_t::f42617() { AddUndoCount(); set_undo((*ObjectArrayPointer_ptr)[*ObjDlg_ObjectIndex_ptr].layer_disp, 0x10); return *ObjectArrayPointer_ptr; } void __stdcall undo_t::f4355c(ExEdit::Object* obj) { AddUndoCount(); set_undo(obj - *ObjectArrayPointer_ptr, 0); *(int*)&obj->flag ^= 0x200; } void __stdcall undo_t::f435bd(ExEdit::Object* obj) { AddUndoCount(); set_undo(obj - *ObjectArrayPointer_ptr, 0); *(int*)&obj->flag ^= 0x100; } void __cdecl undo_t::add_track_value_wrap(ExEdit::Filter* efp, int track_id, int add_value) { interval_set_undo(object(efp->processing) - 1, 1); add_track_value(efp, track_id, add_value); } #endif } ================================================ FILE: patch/patch_undo.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "macro.h" #ifdef PATCH_SWITCH_UNDO #include #include "util_magic.hpp" #include "global.hpp" #include "offset_address.hpp" #include "config_rw.hpp" // ty saunazo namespace patch { // init at exedit load inline class undo_t { inline static ExEdit::Object** ObjectArrayPointer_ptr; inline static int* NextObjectIdxArray; inline static ExEdit::LayerSetting** layer_setting_ofsptr_ptr; inline static void** exdata_buffer_ptr; inline static int* timeline_obj_click_mode_ptr; inline static int* ObjDlg_ObjectIndex_ptr; inline static int* timeline_edit_both_adjacent_ptr; inline static int* UndoInfo_current_id_ptr; inline static ExEdit::SceneSetting* scene_setting; inline static void(__cdecl*set_undo)(unsigned int, unsigned int); inline static void(__cdecl*AddUndoCount)(); inline static int(__cdecl*efDraw_func_WndProc)(HWND, UINT, WPARAM, LPARAM, AviUtl::EditHandle*, ExEdit::Filter*); inline static int(__cdecl*NormalizeExeditTimelineY)(int); inline static void(__cdecl *add_track_value)(ExEdit::Filter*, int, int); inline constexpr static int UNDO_INTERVAL = 1000; static void __cdecl set_undo_wrap_42878(unsigned int object_idx, int layer_id) { if (layer_id < (*ObjectArrayPointer_ptr)[object_idx].layer_disp) { set_undo(object_idx, 8); } } static void __cdecl set_undo_wrap_40e5c(unsigned int object_idx, unsigned int flag) { // select_idx_list set_undo(reinterpret_cast(GLOBAL::exedit_base + 0x179230)[object_idx], flag); } inline constexpr static int FILTER_ID_MOVIE = 0; // track 0 check 0 exdata 268 = maxframe inline constexpr static int FILTER_ID_AUDIO = 2; // track 0 check 0,1 exdata 268 = maxframe inline constexpr static int FILTER_ID_WAVEFORM = 6; // track 0 check 3 exdata 268 = maxframe inline constexpr static int FILTER_ID_SCENE = 7; // track 0 check 0 exdata 0 = sceneid inline constexpr static int FILTER_ID_SCENE_AUDIO = 8; // track 0 check 0,1 exdata 0 = sceneid inline constexpr static int FILTER_ID_MOVIE_MIX = 82; // track 0 check 0 exdata 268 = maxframe static void __cdecl set_undo_wrap_3e037(unsigned int object_idx, unsigned int flag); static int __cdecl efDraw_func_WndProc_wrap_06e2b4(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam, AviUtl::EditHandle* editp, ExEdit::Filter* efp); static int __stdcall f8b97f(HWND hwnd, ExEdit::Filter* efp, WPARAM wparam, LPARAM lparam); static int __stdcall f8ba87_8bad5(ExEdit::Filter* efp, HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); static int __stdcall f8bb4d_8bbcc(int value, int8_t* exdata, int offset, ExEdit::Filter* efp); static int* __stdcall f59e27(WPARAM wparam, LPARAM lparam, ExEdit::Filter* efp, UINT message); static int __stdcall f8b9f0(ExEdit::Filter* efp, HWND hWnd, LPWSTR lpString, int nMaxCount); static int __stdcall f875ef(ExEdit::Filter* efp, HWND hWnd, LPWSTR lpString); static int __cdecl NormalizeExeditTimelineY_wrap_3c8fa_42629_42662_42924_42a0a(int timeline_y); static int __cdecl NormalizeExeditTimelineY_wrap_4253e(int timeline_y); static ExEdit::Object* __stdcall f42617(); static void __stdcall f4355c(ExEdit::Object* obj); static void __stdcall f435bd(ExEdit::Object* obj); static void __cdecl add_track_value_wrap(ExEdit::Filter* efp, int track_id, int add_value); static void interval_set_undo(int object_idx, int flag) { static ULONGLONG pretime = 0; static int pre_undo_id = 0; int& UndoInfo_current_id = *UndoInfo_current_id_ptr; ULONGLONG time = GetTickCount64(); if (pretime < time - UNDO_INTERVAL || pre_undo_id != UndoInfo_current_id) { AddUndoCount(); set_undo(object_idx, flag); } pretime = time; pre_undo_id = UndoInfo_current_id; } bool enabled = true; bool enabled_i; inline static const char key[] = "undo"; public: void init() { enabled_i = enabled; if (!enabled_i) return; ObjectArrayPointer_ptr = reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::ObjectArrayPointer); NextObjectIdxArray = reinterpret_cast(GLOBAL::exedit_base + OFS::ExEdit::NextObjectIdxArray); layer_setting_ofsptr_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x0a4058); exdata_buffer_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x1e0fa8); timeline_obj_click_mode_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x177a24); ObjDlg_ObjectIndex_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x177a10); timeline_edit_both_adjacent_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x14ea00); scene_setting = reinterpret_cast(GLOBAL::exedit_base + 0x177a50); UndoInfo_current_id_ptr = reinterpret_cast(GLOBAL::exedit_base + 0x244e14); set_undo = reinterpret_cast(GLOBAL::exedit_base + 0x08d290); AddUndoCount = reinterpret_cast(GLOBAL::exedit_base + 0x08d150); efDraw_func_WndProc = reinterpret_cast(GLOBAL::exedit_base + 0x01b550); NormalizeExeditTimelineY = reinterpret_cast(GLOBAL::exedit_base + 0x032c10); add_track_value = reinterpret_cast(GLOBAL::exedit_base + 0x01c0f0); // レイヤー削除→元に戻すで他シーンのオブジェクトが消える { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x042875, 2); h.store_i8(0, '\x56'); // push esi=layer_id h.store_i8(1, '\x90'); // nop ReplaceNearJmp(GLOBAL::exedit_base + 0x042879, &set_undo_wrap_42878); } // Ctrlで複数オブジェクトを選択しながら設定ダイアログのトラックバーを動かすと一部オブジェクトが正常に戻らない ReplaceNearJmp(GLOBAL::exedit_base + 0x040e5d, &set_undo_wrap_40e5c); // オブジェクトの左端をつまんで動かすと再生位置パラメータが変わるが、それが元に戻らない ReplaceNearJmp(GLOBAL::exedit_base + 0x03e038, &set_undo_wrap_3e037); // 一部フィルタのファイル参照を変更→元に戻すで設定ダイアログが更新されない(音声波形など) OverWriteOnProtectHelper(GLOBAL::exedit_base + 0x08d50e, 4).store_i32(0, '\x0f\x1f\x40\x00'); // nop // 部分フィルタのマスクの種類を変更してもUndoデータが生成されない ReplaceNearJmp(GLOBAL::exedit_base + 0x06e2b5, &efDraw_func_WndProc_wrap_06e2b4); // テキストオブジェクトのフォントを変更してもUndoデータが生成されない { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x08b97c, 8); h.store_i32(0, '\x90\x57\x51\xe8'); // nop; push edi=efp; push ecx; call (rel32) h.replaceNearJmp(4, &f8b97f); } // テキストオブジェクトの影付き・縁付きを変更してもUndoデータが生成されない { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x08ba86, 2); h.store_i16(0, '\x57\xe8'); // push edi=efp; call (rel32) ReplaceNearJmp(GLOBAL::exedit_base + 0x08ba88, &f8ba87_8bad5); } // テキストオブジェクトの文字配置(左寄せ[上]など)を変更してもUndoデータが生成されない { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x08bad4, 6); h.store_i16(0, '\x57\xe8'); // push edi=efp; call (rel32) h.replaceNearJmp(2, &f8ba87_8bad5); } // テキストオブジェクトの字間を変更してもUndoデータが生成されない { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x08bb48, 10); h.store_i32(0, '\x57\x6a\x05\x56'); // push edi=efp; push 5; push esi=exdata h.store_i16(4, '\x50\xe8'); // push eax=value; call rel32 h.replaceNearJmp(6, &f8bb4d_8bbcc); } // テキストオブジェクトの行間を変更してもUndoデータが生成されない { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x08bbc7, 10); h.store_i32(0, '\x57\x6a\x06\x56'); // push edi=efp; push 6; push esi=exdata h.store_i16(4, '\x50\xe8'); // push eax=value; call rel32 h.replaceNearJmp(6, &f8bb4d_8bbcc); } // グループ制御とかの対象レイヤー数を変更してもUndoデータが生成されない { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x059e1b, 20); const char patch[] = { "\x51" // push ecx=message "\x50" // push eax=efp "\x8b\x4c\x24\x28" // mov ecx, dword ptr[esp + 0x28]=lparam "\x51" // push ecx "\x8b\x4c\x24\x28" // mov ecx, dword ptr[esp + 0x28]=wparam "\x51" // push ecx "\xe8XXXX" // call rel32 "\x85\xc0" // test eax, eax "\x74" /* 0x6e */ // JZ +0x6e }; memcpy(reinterpret_cast(h.address()), patch, sizeof(patch) - 1); h.replaceNearJmp(13, &f59e27); } // テキストを変更してもUndoデータが生成されない { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x08b9ef, 6); h.store_i16(0, '\x57\xe8'); // push edi; call (rel32) h.replaceNearJmp(2, &f8b9f0); } // スクリプト制御・カメラスクリプトを変更してもUndoデータが生成されない { // 100875e7 68 00 04 00 00 PUSH 0x400 // 100875ec 56 PUSH ESI // 100875ed 51 PUSH ECX // 100875ee ff 15 54 a2 09 10 CALL dword ptr [->USER32.DLL::GetWindowTextW] = 0009bc30 // ↓ // 100875e7 8b 54 24 38 MOV EDX, DWORD PTR [ESP+38H] // 100875eb 90 NOP // 100875ec 56 PUSH ESI // 100875ed 51 PUSH ECX // 100875ee 52 PUSH EDX // 100875ef e8 XXXX CALL rel32 OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x0875e7, 13); h.store_i32(0, '\x8b\x54\x24\x38'); h.store_i32(4, '\x90\x56\x51\x52'); h.store_i8(8, '\xe8'); h.replaceNearJmp(9, &f875ef); } // 左クリックよりレイヤーの表示状態を変更してもUndoデータが生成されない ReplaceNearJmp(GLOBAL::exedit_base + 0x03c8fb, &NormalizeExeditTimelineY_wrap_3c8fa_42629_42662_42924_42a0a); // 右クリックメニューよりレイヤーの表示状態を変更してもUndoデータが生成されない ReplaceNearJmp(GLOBAL::exedit_base + 0x04262a, &NormalizeExeditTimelineY_wrap_3c8fa_42629_42662_42924_42a0a); // 右クリックメニューよりレイヤーのロック状態を変更してもUndoデータが生成されない ReplaceNearJmp(GLOBAL::exedit_base + 0x042663, &NormalizeExeditTimelineY_wrap_3c8fa_42629_42662_42924_42a0a); // 右クリックメニューよりレイヤーの座標のリンク状態を変更してもUndoデータが生成されない ReplaceNearJmp(GLOBAL::exedit_base + 0x042925, &NormalizeExeditTimelineY_wrap_3c8fa_42629_42662_42924_42a0a); // 右クリックメニューより上クリッピング状態を変更してもUndoデータが生成されない ReplaceNearJmp(GLOBAL::exedit_base + 0x042a0b, &NormalizeExeditTimelineY_wrap_3c8fa_42629_42662_42924_42a0a); // 右クリックメニューより他のレイヤーを全表示/非表示を押してもUndoデータが生成されない ReplaceNearJmp(GLOBAL::exedit_base + 0x04253f, &NormalizeExeditTimelineY_wrap_4253e); // ショートカットよりレイヤーの表示状態を変更してもUndoデータが生成されない { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x042617, 5); h.store_i8(0, '\xe8'); h.replaceNearJmp(1, &f42617); } // カメラ制御の対象 を切り替えてもUndoデータが生成されない { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x04355b, 6); h.store_i16(0, '\x51\xe8'); // push ecx, call (rel32) h.replaceNearJmp(2, &f4355c); } // 上のオブジェクトでクリッピング を切り替えてもUndoデータが生成されない { OverWriteOnProtectHelper h(GLOBAL::exedit_base + 0x0435ba, 8); h.store_i32(0, '\x90\x90\x50\xe8'); // nop, push eax, call (rel32) h.replaceNearJmp(4, &f435bd); } // テンキー2468+-*/ Ctrl+テンキー2468 で(座標XY 回転 拡大率 中心XY)トラックバーを変えてもUndoデータが生成されない ReplaceNearJmp(GLOBAL::exedit_base + 0x01b611, &add_track_value_wrap); // テンキー4座標X- ReplaceNearJmp(GLOBAL::exedit_base + 0x01b646, &add_track_value_wrap); // Ctrl+テンキー6中心X+ ReplaceNearJmp(GLOBAL::exedit_base + 0x01b674, &add_track_value_wrap); // テンキー6座標X+ ReplaceNearJmp(GLOBAL::exedit_base + 0x01b6ab, &add_track_value_wrap); // Ctrl+テンキー8中心Y- ReplaceNearJmp(GLOBAL::exedit_base + 0x01b6db, &add_track_value_wrap); // テンキー8座標Y- ReplaceNearJmp(GLOBAL::exedit_base + 0x01b710, &add_track_value_wrap); // Ctrl+テンキー2中心Y+, Ctrl+テンキー4中心X- ReplaceNearJmp(GLOBAL::exedit_base + 0x01b73e, &add_track_value_wrap); // テンキー2座標Y+ ReplaceNearJmp(GLOBAL::exedit_base + 0x01b765, &add_track_value_wrap); // テンキー-拡大率- ReplaceNearJmp(GLOBAL::exedit_base + 0x01b78c, &add_track_value_wrap); // テンキー+拡大率+ ReplaceNearJmp(GLOBAL::exedit_base + 0x01b7b0, &add_track_value_wrap); // テンキー/回転- ReplaceNearJmp(GLOBAL::exedit_base + 0x01b7d4, &add_track_value_wrap); // テンキー*回転+ } void switching(bool flag) { enabled = flag; } bool is_enabled() { return enabled; } bool is_enabled_i() { return enabled_i; } void switch_load(ConfigReader& cr) { cr.regist(key, [this](json_value_s* value) { ConfigReader::load_variable(value, enabled); }); } void switch_store(ConfigWriter& cw) { cw.append(key, enabled); } } undo; } #endif ================================================ FILE: patch/resource.h ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #define PATCH_MENU_INFO 20001 #define PATCH_MENU_CONSOLE 20002 #define PATCH_EXEDITMENU_REDO 2000 #define PATCH_RS_PATCH_FAILED_TO_SAVE_SETTING 9000 #define PATCH_RS_PATCH_FAILED_TO_LOAD_SETTING 9001 #define PATCH_RS_PATCH_FAILED_TO_INIT_CONSOLE 9002 #define PATCH_RS_PATCH_CONSOLE_IS_DIABLED 9003 #define PATCH_RS_PATCH_INVALID_SETTING_JSON 9004 #define PATCH_RS_PATCH_FAILED_TO_CREATE_EXCEPTION_DIALOG 9005 #define PATCH_RS_PATCH_CONFLICT_PLUGIN 9006 #define PATCH_RS_PATCH_OLD_LSW 9007 #define PATCH_RS_PATCH_CANT_USE_CL 9010 #define PATCH_RS_PATCH_WEB_CONFIRM 9011 #define PATCH_RS_PATCH_WEB_CONFIRM_BUTTON_OPEN 9012 #define PATCH_RS_PATCH_WEB_CONFIRM_BUTTON_COPY 9013 #define PATCH_RS_PATCH_WEB_CONFIRM_BUTTON_CANCEL 9014 #define PATCH_RS_EXEDIT_INFORMATION 10000 #define PATCH_ID_EXCEPTION_OK 101 #define PATCH_ID_EXCEPTION_DETAIL_BUTTON 102 #define PATCH_ID_EXCEPTION_SAVE_PROJECT 103 #define PATCH_ID_EXCEPTION_DETAIL_TEXT 111 #define PATCH_ID_EXCEPTION_LABEL1 121 #define PATCH_ID_EXCEPTION_LABEL2 122 #define PATCH_ID_EXCEPTION_LINK 131 #define PATCH_ID_EXCEPTION_STOPMES 141 #define PATCH_ID_EXCEPTION_THREADID_COMBO 151 ================================================ FILE: patch/restorable_patch.hpp ================================================ #pragma once #include #include #include "util_magic.hpp" class restorable_patch { protected: std::vector data; std::uintptr_t address; bool state; restorable_patch(std::uintptr_t address, std::vector&& data) : data(std::move(data)), address(address), state(false) {} public: restorable_patch(std::uintptr_t address, void* data, size_t length) : data(static_cast(data), static_cast(data) + length), address(address), state(false) {} void swap_data() { OverWriteOnProtectHelper h(address, data.size()); for (size_t i = 0; i < data.size(); i++) { auto tmp = load_i8(address + i); store_i8(address + i, data[i]); data[i] = tmp; } } void switch_true_to_false() { swap_data(); } void switch_false_to_true() { swap_data(); } void switching(bool flag) { if (flag) { if (!state) { switch_false_to_true(); state = flag; } } else { if (state) { switch_true_to_false(); state = flag; } } } }; class restorable_patch_function : public restorable_patch { static std::vector make_data(std::uintptr_t address, void* newfunc) { static std::vector ret; ret.resize(5); ret[0] = std::byte{ 0xe9 }; store_i32(&ret[1], CalcNearJmp(address + 1, reinterpret_cast(newfunc))); return ret; } public: restorable_patch_function(std::uintptr_t address, void* newfunc) : restorable_patch(address, std::move(make_data(address, newfunc))) {} }; class restorable_patch_i8 : public restorable_patch { static std::vector make_data(i8 value) { static std::vector ret; ret.resize(1); store_i8(&ret[0], value); return ret; } public: template restorable_patch_i8(std::uintptr_t address, T value) : restorable_patch(address, std::move(make_data((i8)value))) {} }; class restorable_patch_i16 : public restorable_patch { static std::vector make_data(i16 value) { static std::vector ret; ret.resize(2); store_i16(&ret[0], value); return ret; } public: template restorable_patch_i16(std::uintptr_t address, T value) : restorable_patch(address, std::move(make_data((i16)value))) {} }; class restorable_patch_i32 : public restorable_patch { static std::vector make_data(i32 value) { static std::vector ret; ret.resize(4); store_i32(&ret[0], value); return ret; } public: template restorable_patch_i32(std::uintptr_t address, T value) : restorable_patch(address, std::move(make_data((i32)value))) {} }; ================================================ FILE: patch/stopwatch.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include #include "debug_log.hpp" class stopwatch { #ifdef PATCH_STOPWATCH std::chrono::system_clock::time_point start; public: stopwatch() noexcept : start(std::chrono::system_clock::now()) {} ~stopwatch() { print(); } long long now() const noexcept { auto end = std::chrono::system_clock::now(); return std::chrono::duration_cast(end - start).count(); } void print() const noexcept { debug_log("{} us", now()); } #else public: long long now() const noexcept { return 0; } void print() const noexcept {} #endif }; class stopwatch_mem { #ifdef PATCH_STOPWATCH std::chrono::system_clock::time_point start_tp; long long sum; long long cnt; long long now() const noexcept { auto end = std::chrono::system_clock::now(); return std::chrono::duration_cast(end - start_tp).count(); } public: stopwatch_mem() noexcept : start_tp{}, sum{}, cnt{} {} ~stopwatch_mem() {} void start() noexcept { start_tp = std::chrono::system_clock::now(); } void stop() noexcept { auto time = now(); cnt++; sum += time; debug_log("{} us ave : {} us", time, sum / cnt); } #else public: void start() noexcept {} void stop() noexcept {} #endif }; ================================================ FILE: patch/timer.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include class Timer; extern Timer timer; inline class Timer { using timer_func = std::function; std::unordered_map list; static VOID CALLBACK timerproc(HWND, UINT, UINT_PTR nIDEvent, DWORD) { const auto& list = timer.list; if (auto func = list.find(nIDEvent); func != list.end()) func->second(); } public: ~Timer() { for (auto [id, _] : list) { KillTimer(NULL, id); } } void set(timer_func f, UINT elapse) { UINT_PTR try_id = 1; UINT_PTR timer_id; while ((timer_id = SetTimer(NULL, try_id, elapse, timerproc)) == 0) { try_id++; } list.try_emplace(timer_id, f); } } timer; ================================================ FILE: patch/util.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "util_int.hpp" #include "util_pe.hpp" #include "util_magic.hpp" #include "util_others.hpp" #include "util_resource.hpp" ================================================ FILE: patch/util_int.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include #include using i8 = uint8_t; using i16 = uint16_t; using i32 = uint32_t; using i64 = uint64_t; inline void store_i8(auto address, auto value) { *std::bit_cast(address) = (i8)value; } inline void store_i16(auto address, auto value) { *std::bit_cast(address) = (i16)value; } inline void store_i32(auto address, auto value) { *std::bit_cast(address) = (i32)value; } inline void store_i64(auto address, auto value) { *std::bit_cast(address) = (i64)value; } template inline T0 load_i8(T1 address) { static_assert(sizeof(T0) == sizeof(i8)); return *std::bit_cast>(address); } template inline T0 load_i16(T1 address) { static_assert(sizeof(T0) == sizeof(i16)); return *std::bit_cast>(address); } template inline T0 load_i32(T1 address) { static_assert(sizeof(T0) == sizeof(i32)); return *std::bit_cast>(address); } template inline T0 load_i64(T1 address) { static_assert(sizeof(T0) == sizeof(i64)); return *std::bit_cast>(address); } template inline T1 exchange_i8(T0 address, T1&& value) { return (T1)std::exchange(*std::bit_cast(address), (i8)value); } template inline T1 exchange_i16(T0 address, T1&& value) { return (T1)std::exchange(*std::bit_cast(address), (i16)value); } template inline T1 exchange_i32(T0 address, T1&& value) { return (T1)std::exchange(*std::bit_cast(address), (i32)value); } template inline T1 exchange_i64(T0 address, T1&& value) { return (T1)std::exchange(*std::bit_cast(address), (i64)value); } ================================================ FILE: patch/util_magic.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include #include #include #include "global.hpp" #include "util_int.hpp" #include "util_pe.hpp" inline i32 CalcNearJmp(i32 address, i32 jmp_address) { return jmp_address - (address + 4); } class OverWriteOnProtectHelper { uintptr_t m_address, m_size; DWORD m_oldProtect; public: template OverWriteOnProtectHelper(T address, uintptr_t size) noexcept : m_address((uintptr_t)address), m_size(size) { VirtualProtect(reinterpret_cast(m_address), m_size, PAGE_EXECUTE_READWRITE, &m_oldProtect); } ~OverWriteOnProtectHelper() noexcept { VirtualProtect(reinterpret_cast(m_address), m_size, m_oldProtect, &m_oldProtect); } template void store_i8(T1 address, T2 value) const { ::store_i8(m_address + address, value); } template void store_i16(T1 address, T2 value) const { ::store_i16(m_address + address, value); } template void store_i32(T1 address, T2 value) const { ::store_i32(m_address + address, value); } template void store_i64(T1 address, T2 value) const { ::store_i64(m_address + address, value); } template T0 load_i8(T1 address) const { return ::load_i8(m_address + address); } template T0 load_i16(T1 address) const { return ::load_i16(m_address + address); } template T0 load_i32(T1 address) const { return ::load_i32(m_address + address); } template T0 load_i64(T1 address) const { return ::load_i64(m_address + address); } void replaceNearJmp(i32 offset, void* jmp_address) { store_i32(offset, CalcNearJmp(m_address + offset, reinterpret_cast(jmp_address))); } auto address() const { return m_address; } auto address(uintptr_t ofs) const { return m_address + ofs; } }; /// /// ニアージャンプ・コールを書き換える /// /// 書き換える対象のアドレス /// 代わりに飛ばして欲しいアドレス inline void ReplaceNearJmp(i32 address, void* jmp_address) { OverWriteOnProtectHelper(address, 4).replaceNearJmp(0, jmp_address); } // 既存の関数を破壊して,自分の関数を実行する inline class ReplaceFunction_t { static const int asm_size = 5; public: // 乗っ取りたい関数があるアドレス,ジャンプさせる関数のポインタ,元の関数の内容が返る場所 template= asm_size, std::nullptr_t> = nullptr> void operator()(T address, const void* function, std::byte(&original)[N]) noexcept { auto adr = std::bit_cast(address); OverWriteOnProtectHelper h(adr, asm_size); std::copy(adr, adr + N, original); store_i8(adr, '\xe9'); // jmp rel32 store_i32(adr + 1, CalcNearJmp(address + 1, (i32)function)); } template void operator()(T address, const void* function) noexcept { auto adr = std::bit_cast(address); OverWriteOnProtectHelper h(adr, asm_size); store_i8(adr, '\xe9'); // jmp rel32 store_i32(adr + 1, CalcNearJmp(adr + 1, (i32)function)); } } ReplaceFunction; // 乗っ取りたいモジュール, 乗っ取る関数があるDLLのファイル名, 乗っ取る関数の名前, 新しい関数へのポインタ inline BOOL ExchangeFunction(HMODULE hModule, std::string_view modname, std::string_view funcname, void* function) noexcept { auto ptr = search_import(hModule, modname, funcname); if (!ptr)return FALSE; DWORD flOldProtect; if (VirtualProtect(ptr, 4, PAGE_EXECUTE_READWRITE, &flOldProtect) == FALSE) return FALSE; store_i32(ptr, function); return VirtualProtect(ptr, 4, flOldProtect, &flOldProtect); } /// /// 指定したアドレスの関数の直前に、自分の関数を実行する /// 実行後元の関数に戻る /// __stdcall,__cdecl専用 /// /// 中断したい関数のアドレス /// 挿入する関数 /// 命令単位に合った数(7以上) /// TRUE inline bool InjectFunction_stdcall(uint32_t address, const void* function, size_t asm_word_n) noexcept { std::byte* cursor = GLOBAL::executable_memory_cursor; store_i8(cursor, '\xb8'); // mov eax, (i32) store_i32(cursor + 1, function); store_i16(cursor + 5, '\xff\xd0'); // call eax std::copy((std::byte*)address, (std::byte*)address + asm_word_n, cursor + 7); store_i16(cursor + asm_word_n + 7, '\xff\x25'); // jmp [(i32)] store_i32(cursor + asm_word_n + 9, cursor + asm_word_n + 13); store_i32(cursor + asm_word_n + 13, address + asm_word_n); GLOBAL::executable_memory_cursor += asm_word_n + 17; { OverWriteOnProtectHelper protect(address, 7); store_i8(address, '\xb8'); // mov eax, (i32) store_i32(address + 1, cursor); store_i16(address + 5, '\xff\xe0'); // call eax } return TRUE; } /// /// 指定したアドレスの関数の直前に、自分の関数を実行する /// 実行後元の関数に戻る /// __cdecl専用 (__stdcallと一緒だけど) /// /// 中断したい関数のアドレス /// 挿入する関数 /// 命令単位に合った数(7以上) /// TRUE inline bool InjectFunction_cdecl(uint32_t address, const void* function, size_t asm_word_n) noexcept { InjectFunction_stdcall(address, function, asm_word_n); } /// /// 指定したアドレスの関数の直前に、自分の関数を実行する /// 実行後元の関数に戻る /// __fastcall専用 /// /// 中断したい関数のアドレス /// 挿入する関数 /// 命令単位に合った数(7以上) /// TRUE inline bool InjectFunction_fastcall(uint32_t address, void(*func)(), size_t asm_word_n) { if (asm_word_n < 7)return false; OverWriteOnProtectHelper helper(address, asm_word_n); auto bridge = GLOBAL::executable_memory_cursor; store_i16(bridge, '\x51\x52'); // PUSH ECX; PUSH EDX store_i8(bridge + 2, '\xb8'); // MOV EAX, (i32) store_i32(bridge + 3, func); store_i16(bridge + 7, '\xff\xd0'); // CALL EAX store_i16(bridge + 9, '\x5a\x59'); // POP EDX; POP ECX std::copy((std::byte*)address, (std::byte*)address + asm_word_n, bridge + 11); store_i16(bridge + asm_word_n + 11, '\xff\x25'); // JMP (i32) store_i32(bridge + asm_word_n + 13, bridge + asm_word_n + 17); store_i32(bridge + asm_word_n + 17, address + asm_word_n); GLOBAL::executable_memory_cursor += asm_word_n + 21; store_i8(address, '\xb8'); // MOV EAX, store_i32(address + 1, bridge); store_i16(address + 5, '\xff\xe0'); // JMP EAX return true; } ================================================ FILE: patch/util_others.cpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "util_others.hpp" #include #pragma comment(lib, "shlwapi.lib") #include #include "global.hpp" void save_project(HWND hwnd_owner) { std::string path; path.resize(512); OPENFILENAMEA ofna{ .lStructSize = sizeof(OPENFILENAMEA), .hwndOwner = hwnd_owner, .hInstance = GLOBAL::patchaul_hinst, .lpstrFilter = "ProjectFile (*.aup)\0*.aup\0AllFile (*.*)\0*.*\0", .lpstrCustomFilter = NULL, .nMaxCustFilter = 0, .nFilterIndex = 0, .lpstrFile = path.data(), .nMaxFile = path.size(), .lpstrFileTitle = NULL, .nMaxFileTitle = NULL, .lpstrInitialDir = NULL, .lpstrTitle = NULL, .Flags = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_ENABLESIZING, .lpstrDefExt = "aup", .lCustData = 0, .lpfnHook = NULL, .lpTemplateName = NULL, .pvReserved = NULL, .dwReserved = NULL, .FlagsEx = NULL }; auto editp = load_i32(GLOBAL::aviutl_base + OFS::AviUtl::edit_handle_ptr); std::string dir(editp->project_filename); if (dir.size() > 0) { dir.erase(PathFindFileNameA(dir.data()) - dir.data()); ofna.lpstrInitialDir = dir.c_str(); } if (GetSaveFileNameA(&ofna)) { ((BOOL(__fastcall*)(AviUtl::EditHandle*, LPCSTR))(GLOBAL::aviutl_base + OFS::AviUtl::saveProjectFile))( editp, path.c_str() ); } } ================================================ FILE: patch/util_others.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include #include #include #include #include #include #include #include #include "global.hpp" #include "resource.h" #include "offset_address.hpp" inline HWND pid2hwnd(DWORD pid) { auto hwnd = FindWindow(NULL, NULL); while (hwnd) { if (!GetParent(hwnd) /*&& IsWindowVisible(hwnd)*/) { DWORD pid_tmp; GetWindowThreadProcessId(hwnd, &pid_tmp); if (pid == pid_tmp) return hwnd; } hwnd = GetWindow(hwnd, GW_HWNDNEXT); } return hwnd; } template concept modify_menuitem_check_callback = requires(Func func) { { func(std::declval()) } -> std::convertible_to; }; template void modify_menuitem_check(HMENU menu, UINT item, BOOL position, Func func) { MENUITEMINFOA info = { .cbSize = sizeof(MENUITEMINFO), .fMask = MIIM_STATE }; GetMenuItemInfoA(menu, item, position, &info); info.fState = info.fState & ~MFS_CHECKED | (func(info.fState & MFS_CHECKED) ? MFS_CHECKED : 0); SetMenuItemInfoA(menu, item, position, &info); } struct format_literal_detail_a : private std::string_view { format_literal_detail_a(const char* str, std::size_t size) : std::string_view(str, size) {} template auto operator()(Args&& ...args) { return std::vformat(*this, std::make_format_args(args...)); } }; struct format_literal_detail_w : private std::wstring_view { format_literal_detail_w(const wchar_t* str, std::size_t size) : std::wstring_view(str, size) {} template auto operator()(Args&& ...args) { return std::vformat(*this, std::make_wformat_args(args...)); } }; inline auto operator""_fmt(const char* str, std::size_t size) { return format_literal_detail_a(str, size); } inline auto operator""_fmt(const wchar_t* str, std::size_t size) { return format_literal_detail_w(str, size); } template requires std::is_same_v inline auto format_to_os(OStream& ss, const std::string_view fmt, Args&& ...args) { return std::vformat_to(std::ostreambuf_iterator(ss), fmt, std::make_format_args(args...)); } template requires std::is_same_v inline auto format_to_os(OStream& ss, const std::wstring_view fmt, Args&& ...args) { return std::vformat_to(std::ostreambuf_iterator(ss), fmt, std::make_wformat_args(args...)); } inline auto get_local_time() { TIME_ZONE_INFORMATION tzi; GetTimeZoneInformation(&tzi); SYSTEMTIME st_u; GetSystemTime(&st_u); SYSTEMTIME st_l; SystemTimeToTzSpecificLocalTime(&tzi, &st_u, &st_l); return st_l; } // hh:mm:ss 形式のローカル時刻をもらう inline auto get_local_time_string() { auto st_l = get_local_time(); return "{:02}:{:02}:{:02}"_fmt(st_l.wHour, st_l.wMinute, st_l.wSecond); } // 編集プロジェクトの保存 を行う void save_project(HWND hwnd_owner); // ANSI -> UTF-16 LE inline std::wstring string_convert_A2W(std::string_view str) { auto size = MultiByteToWideChar(CP_ACP, 0, str.data(), str.size(), nullptr, 0); std::wstring ret(size, '\0'); MultiByteToWideChar(CP_ACP, 0, str.data(), str.size(), ret.data(), size); return ret; } // UTF-16 LE -> ANSI inline std::string string_convert_W2A(std::wstring_view str) { auto size = WideCharToMultiByte(CP_ACP, 0, str.data(), str.size(), nullptr, 0, nullptr, nullptr); std::string ret(size, '\0'); WideCharToMultiByte(CP_ACP, 0, str.data(), str.size(), ret.data(), size, nullptr, nullptr); return ret; } // UTF-8 -> UTF-16 LE inline std::wstring string_convert_U2W(std::u8string_view str) { auto size = MultiByteToWideChar(CP_UTF8, 0, reinterpret_cast(str.data()), str.size(), nullptr, 0); std::wstring ret(size, '\0'); MultiByteToWideChar(CP_UTF8, 0, reinterpret_cast(str.data()), str.size(), ret.data(), size); return ret; } // UTF-16 LE -> UTF-8 inline std::u8string string_convert_W2U(std::wstring_view str) { auto size = WideCharToMultiByte(CP_UTF8, 0, str.data(), str.size(), nullptr, 0, nullptr, nullptr); std::u8string ret(size, '\0'); WideCharToMultiByte(CP_UTF8, 0, str.data(), str.size(), reinterpret_cast(ret.data()), size, nullptr, nullptr); return ret; } enum class CPUCmdSet : uint32_t { F_TSC = 1 << 0, F_MMX = 1 << 1, F_SSE = 1 << 2, F_SSE2 = 1 << 3, F_3DNOW = 1 << 4, F_3DNOWEXT = 1 << 5, F_SMT = 1 << 6, F_64BIT = 1 << 7, F_SSE3 = 1 << 8, F_SSSE3 = 1 << 9, F_SSE4A = 1 << 10, F_SSE41 = 1 << 12, F_SSE42 = 1 << 13, F_AESNI = 1 << 14, F_AVX = 1 << 15, F_AVX2 = 1 << 16, F_FMA4 = 1 << 11, F_AVX512F = 1 << 17, F_AVX512DQ = 1 << 18, F_AVX512_IFMA = 1 << 19, F_AVX512PF = 1 << 20, F_AVX512ER = 1 << 21, F_AVX512CD = 1 << 22, F_AVX512BW = 1 << 23, F_AVX512VL = 1 << 24, F_AVX512_VBMI = 1 << 25, F_AVX512_VPOPCNTDQ = 1 << 26, F_AVX512_4VNNIW = 1 << 27, F_AVX512_4FMAPS = 1 << 28, }; template<>struct AviUtl::detail::flag::ops_def:std::true_type{}; /* 参考: https://www.timbreofprogram.info/blog/archives/951 */ inline CPUCmdSet get_CPUCmdSet() { static CPUCmdSet ret = {}; static bool inited = false; if (inited) return ret; int cpuinfo[4]; __cpuid(cpuinfo, 0x00000000); auto basicmax = cpuinfo[0]; __cpuid(cpuinfo, 0x80000000); auto extendmax = cpuinfo[0]; __cpuid(cpuinfo, 0x00000001); if (cpuinfo[3] & (1u << 4)) ret |= CPUCmdSet::F_TSC; if (cpuinfo[3] & (1u << 23)) ret |= CPUCmdSet::F_MMX; if (cpuinfo[3] & (1u << 25)) ret |= CPUCmdSet::F_SSE; if (cpuinfo[3] & (1u << 26)) ret |= CPUCmdSet::F_SSE2; if (cpuinfo[3] & (1u << 28)) ret |= CPUCmdSet::F_SMT; if (cpuinfo[2] & (1u << 0)) ret |= CPUCmdSet::F_SSE3; if (cpuinfo[2] & (1u << 9)) ret |= CPUCmdSet::F_SSSE3; if (cpuinfo[2] & (1u << 19)) ret |= CPUCmdSet::F_SSE41; if (cpuinfo[2] & (1u << 20)) ret |= CPUCmdSet::F_SSE42; if (cpuinfo[2] & (1u << 25)) ret |= CPUCmdSet::F_AESNI; if (cpuinfo[2] & (1u << 28)) ret |= CPUCmdSet::F_AVX; if (static_cast(extendmax) < 0x80000000u) return ret; __cpuid(cpuinfo, 0x80000001); if (cpuinfo[3] & (1u << 31)) ret |= CPUCmdSet::F_3DNOW; if (cpuinfo[3] & (1u << 30)) ret |= CPUCmdSet::F_3DNOWEXT; if (cpuinfo[3] & (1u << 29)) ret |= CPUCmdSet::F_64BIT; if (cpuinfo[2] & (1u << 6)) ret |= CPUCmdSet::F_SSE4A; if (cpuinfo[2] & (1u << 16)) ret |= CPUCmdSet::F_FMA4; if (basicmax < 7) return ret; __cpuidex(cpuinfo, 7, 0); if (cpuinfo[1] & (1u << 5)) ret |= CPUCmdSet::F_AVX2; if (cpuinfo[1] & (1u << 16)) ret |= CPUCmdSet::F_AVX512F; if (cpuinfo[1] & (1u << 17)) ret |= CPUCmdSet::F_AVX512DQ; if (cpuinfo[1] & (1u << 21)) ret |= CPUCmdSet::F_AVX512_IFMA; if (cpuinfo[1] & (1u << 26)) ret |= CPUCmdSet::F_AVX512PF; if (cpuinfo[1] & (1u << 27)) ret |= CPUCmdSet::F_AVX512ER; if (cpuinfo[1] & (1u << 28)) ret |= CPUCmdSet::F_AVX512CD; if (cpuinfo[1] & (1u << 30)) ret |= CPUCmdSet::F_AVX512BW; if (cpuinfo[1] & (1u << 31)) ret |= CPUCmdSet::F_AVX512VL; if (cpuinfo[2] & (1u << 1)) ret |= CPUCmdSet::F_AVX512_VBMI; if (cpuinfo[2] & (1u << 14)) ret |= CPUCmdSet::F_AVX512_VPOPCNTDQ; if (cpuinfo[3] & (1u << 2)) ret |= CPUCmdSet::F_AVX512_4VNNIW; if (cpuinfo[3] & (1u << 3)) ret |= CPUCmdSet::F_AVX512_4FMAPS; inited = true; return ret; } ================================================ FILE: patch/util_pe.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include #include #include #include #include #include #pragma comment(lib, "Dbghelp.lib") #include "util_int.hpp" /// /// reloc領域から指定アドレスが使われているアドレスを探す /// /// モジュール /// 探すアドレスのオフセット /// アドレスが入った配列 順序の保証は特にない inline auto search_reloc(HMODULE hModule, i32 target_ofs) noexcept { std::vector ret; auto base = reinterpret_cast(hModule); auto target = base + target_ofs; ULONG size; auto reloc = static_cast(ImageDirectoryEntryToData(hModule, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &size)); if (!reloc) return ret; auto end_of_directory = reinterpret_cast(reinterpret_cast(reloc) + size); while (reloc < end_of_directory && reloc->SizeOfBlock) { auto end_of_block = reinterpret_cast(reinterpret_cast(reloc) + reloc->SizeOfBlock); auto TypeOffset = reinterpret_cast(reinterpret_cast(reloc) + sizeof(IMAGE_BASE_RELOCATION)); while (TypeOffset < end_of_block) { auto type = (*TypeOffset >> 12) & 0xf; auto offset = *TypeOffset & 0xfff; if (type == IMAGE_REL_BASED_HIGHLOW) { auto adr = reinterpret_cast(base + reloc->VirtualAddress + offset); if (*adr == target) { ret.push_back(adr); } } TypeOffset++; } reloc = reinterpret_cast(end_of_block); } return ret; } /// /// search_reloc(HMODULE, i32) を複数オフセットアドレスで同時に行う /// /// モジュール /// 探すオフセットアドレスのset /// unordered_map[オフセットアドレス] = オフセットアドレスが使われているアドレスの配列 inline auto search_reloc(HMODULE hModule, const std::set& target_ofs) { std::unordered_map> ret; auto base = reinterpret_cast(hModule); ULONG size; auto reloc = static_cast(ImageDirectoryEntryToData(hModule, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &size)); if (!reloc) return ret; auto end_of_directory = reinterpret_cast(reinterpret_cast(reloc) + size); while (reloc < end_of_directory && reloc->SizeOfBlock) { auto end_of_block = reinterpret_cast(reinterpret_cast(reloc) + reloc->SizeOfBlock); auto TypeOffset = reinterpret_cast(reinterpret_cast(reloc) + sizeof(IMAGE_BASE_RELOCATION)); while (TypeOffset < end_of_block) { auto type = (*TypeOffset >> 12) & 0xf; auto offset = *TypeOffset & 0xfff; if (type == IMAGE_REL_BASED_HIGHLOW) { auto adr = reinterpret_cast(base + reloc->VirtualAddress + offset); i32 ofs = *adr - base; if (target_ofs.contains(ofs)) { if (auto itr = ret.find(ofs); itr != ret.end()) { itr->second.push_back(adr); } else { ret.try_emplace(ofs, std::vector{ adr }); } } } TypeOffset++; } reloc = reinterpret_cast(end_of_block); } return ret; } /// /// 序数を関数名に変換する /// /// モジュール /// 序数 /// 関数の名前 見つからなければstd::nullopt inline std::optional ordinal_to_name(HMODULE hMod, DWORD ordinal) noexcept { auto base = reinterpret_cast(hMod); if (!base)return std::nullopt; ULONG size; auto iedp = static_cast(ImageDirectoryEntryToData(hMod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size)); auto names = reinterpret_cast(base + iedp->AddressOfNames); auto ordinals = reinterpret_cast(base + iedp->AddressOfNameOrdinals); for (DWORD i = 0; i < iedp->NumberOfFunctions; i++) { for (DWORD j = 0; j < iedp->NumberOfNames; j++) { if (ordinals[j] != i)continue; if (ordinals[j] == ordinal) { return reinterpret_cast(base + names[j]); } } } return std::nullopt; } /// /// 関数名を序数に変換する /// /// モジュール /// 関数の名前 /// 序数 関数が無ければ-1 inline DWORD name_to_ordinal(HMODULE hMod, std::string_view name) noexcept { if (!hMod)return -1; auto base = reinterpret_cast(hMod); ULONG size; auto iedp = static_cast(ImageDirectoryEntryToData(hMod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size)); auto names = reinterpret_cast(base + iedp->AddressOfNames); auto ordinals = reinterpret_cast(base + iedp->AddressOfNameOrdinals); for (DWORD i = 0; i < iedp->NumberOfFunctions; i++) { for (DWORD j = 0; j < iedp->NumberOfNames; j++) { if (ordinals[j] != i)continue; if (lstrcmpiA(reinterpret_cast(base + names[j]), name.data()) == 0) { return ordinals[j]; } } } return -1; } /// /// 指定モジュールのIATから関数のあるポインタを探し出す /// /// モジュール /// 探す関数のあるDLLの名前 /// 探す関数の名前 /// 見つけたポインタ 見つからなければnullptr inline void* search_import(HMODULE target, std::string_view mod_name, std::string_view func_name) noexcept { auto base = reinterpret_cast(target); ULONG size; auto iidp = static_cast(ImageDirectoryEntryToData(target, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size)); if (!iidp)return nullptr; auto funcidx = name_to_ordinal(GetModuleHandleA(mod_name.data()), func_name); for (; iidp->Name; iidp++) { if (lstrcmpiA(reinterpret_cast(base + iidp->Name), mod_name.data()) != 0) continue; auto itdp = reinterpret_cast(base + iidp->FirstThunk); auto oitdp = reinterpret_cast(base + iidp->OriginalFirstThunk); for (; itdp->u1.Function; itdp++, oitdp++) { if (IMAGE_SNAP_BY_ORDINAL(oitdp->u1.Ordinal)) { if (IMAGE_ORDINAL(oitdp->u1.Ordinal) == funcidx) return &itdp->u1.Function; } else { auto iibnp = reinterpret_cast(base + oitdp->u1.AddressOfData); if (lstrcmpiA(iibnp->Name, func_name.data()) == 0) { return &itdp->u1.Function; } } } } return nullptr; } /// /// 指定モジュールのIATから関数のあるポインタを探し出す /// /// モジュール /// 探す関数のあるDLLの名前 /// 探す関数の名前 /// 探す関数の序数 /// 見つけたポインタ 見つからなければnullptr inline void* search_import(HMODULE hModule, std::string_view mod_name, std::string_view func_name, unsigned int func_ordinal) noexcept { auto base = reinterpret_cast(hModule); ULONG size; auto iidp = static_cast(ImageDirectoryEntryToData(hModule, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size)); if (!iidp)return nullptr; for (; iidp->Name; iidp++) { if (lstrcmpiA(reinterpret_cast(base + iidp->Name), mod_name.data()) != 0) continue; auto itdp = reinterpret_cast(base + iidp->FirstThunk); auto oitdp = reinterpret_cast(base + iidp->OriginalFirstThunk); for (; itdp->u1.Function; itdp++, oitdp++) { if (IMAGE_SNAP_BY_ORDINAL(oitdp->u1.Ordinal)) { if (IMAGE_ORDINAL(oitdp->u1.Ordinal) == func_ordinal) return static_cast(&itdp->u1.Function); } else { auto iibnp = reinterpret_cast(base + oitdp->u1.AddressOfData); if (lstrcmpiA(iibnp->Name, func_name.data()) == 0) { return static_cast(&itdp->u1.Function); } } } } return nullptr; } ================================================ FILE: patch/util_resource.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include #include #include #include #include "global_minimum.hpp" #include "offset_address.hpp" #include "util_others.hpp" inline std::optional resource_string_w(UINT rs_id) { auto hmod = load_i32(GLOBAL::aviutl_base + OFS::AviUtl::current_resource_hmod); struct { const wchar_t* ptr; uint32_t padding = 0; }value; auto size = LoadStringW(hmod, rs_id, (LPWSTR)&value, 0); if (size <= 0) { hmod = GLOBAL::patchaul_hinst; size = LoadStringW(hmod, rs_id, (LPWSTR)&value, 0); if (size <= 0) { return std::nullopt; } } return std::wstring(value.ptr, size); } inline std::optional resource_string_a(UINT rs_id) { auto hmod = load_i32(GLOBAL::aviutl_base + OFS::AviUtl::current_resource_hmod); struct { const wchar_t* ptr; uint32_t padding; }value; auto size = LoadStringW(hmod, rs_id, (LPWSTR)&value, 0); if (size <= 0) { hmod = GLOBAL::patchaul_hinst; size = LoadStringW(hmod, rs_id, (LPWSTR)&value, 0); if (size <= 0) { return std::nullopt; } } auto asize = WideCharToMultiByte(CP_ACP, 0, value.ptr, size, nullptr, 0, nullptr, nullptr); std::string ret(asize, '\0'); WideCharToMultiByte(CP_ACP, 0, value.ptr, size, ret.data(), asize, nullptr, nullptr); return ret; } template inline std::optional resource_format_a(UINT rs_id, Args&& ...args) { auto format_str = resource_string_a(rs_id); if (!format_str.has_value()) return std::nullopt; try { auto ret = std::vformat(format_str.value(), std::make_format_args(args...)); return ret; } catch (const std::format_error&) { return std::nullopt; } } template inline std::optional resource_format_w(UINT rs_id, Args&& ...args) { auto format_str = resource_string_w(rs_id); if (!format_str.has_value()) return std::nullopt; try { auto ret = std::vformat(format_str.value(), std::make_format_args(args...)); return ret; } catch (const std::format_error&) { return std::nullopt; } } inline std::optional patch_resource_message_a(UINT rs_id, UINT uType) { auto str = resource_string_a(rs_id); if (str.has_value()) { return MessageBoxA(NULL, str.value().c_str(), "patch.aul", uType); } else { MessageBoxW(NULL, L"resource error ({})"_fmt(rs_id).c_str(), L"patch.aul", MB_TOPMOST | MB_TASKMODAL | MB_ICONERROR); return std::nullopt; } } inline std::optional patch_resource_message_w(UINT rs_id, UINT uType) { auto str = resource_string_w(rs_id); if (str.has_value()) { return MessageBoxW(NULL, str.value().c_str(), L"patch.aul", uType); } else { MessageBoxW(NULL, L"resource error ({})"_fmt(rs_id).c_str(), L"patch.aul", MB_TOPMOST | MB_TASKMODAL | MB_ICONERROR); return std::nullopt; } } template inline std::optional patch_resource_message_a(UINT rs_id, UINT uType, Args&& ...args) { auto str = resource_string_a(rs_id); if (str.has_value()) { try { return MessageBoxA(NULL, std::vformat(str.value(), std::make_format_args(args...)).c_str(), "patch.aul", uType); } catch (const std::format_error&) { MessageBoxW(NULL, L"format error ({})"_fmt(rs_id).c_str(), L"patch.aul", MB_TOPMOST | MB_TASKMODAL | MB_ICONERROR); return std::nullopt; } } else { MessageBoxW(NULL, L"resource error ({})"_fmt(rs_id).c_str(), L"patch.aul", MB_TOPMOST | MB_TASKMODAL | MB_ICONERROR); return std::nullopt; } } template inline std::optional patch_resource_message_w(UINT rs_id, UINT uType, Args&& ...args) { auto str = resource_string_w(rs_id); if (str.has_value()) { try { return MessageBoxW(NULL, std::vformat(str.value(), std::make_wformat_args(args...)).c_str(), L"patch.aul", uType); } catch (const std::format_error&) { MessageBoxW(NULL, L"format error ({})"_fmt(rs_id).c_str(), L"patch.aul", MB_TOPMOST | MB_TASKMODAL | MB_ICONERROR); return std::nullopt; } } else { MessageBoxW(NULL, L"resource error ({})"_fmt(rs_id).c_str(), L"patch.aul", MB_TOPMOST | MB_TASKMODAL | MB_ICONERROR); return std::nullopt; } } class patch_resource_message_class_base { public: virtual void fire() = 0; virtual ~patch_resource_message_class_base() {} }; template class patch_resource_message_format_class_w : public patch_resource_message_class_base { UINT rs_id, uType; std::tuple args; public: patch_resource_message_format_class_w(UINT rs_id, UINT uType, Args&& ...args) : rs_id(rs_id), uType(uType), args(std::forward(args)...) {} void fire() { auto str = resource_string_w(rs_id); if (str.has_value()) { try { MessageBoxW(NULL, std::vformat(str.value(), std::apply(std::make_format_args, args)).c_str(), L"patch.aul", uType); } catch (const std::format_error&) { MessageBoxW(NULL, L"format error ({})"_fmt(rs_id).c_str(), L"patch.aul", MB_TOPMOST | MB_TASKMODAL | MB_ICONERROR); } } else { MessageBoxW(NULL, L"resource error ({})"_fmt(rs_id).c_str(), L"patch.aul", MB_TOPMOST | MB_TASKMODAL | MB_ICONERROR); } } }; class patch_resource_message_class_w : public patch_resource_message_class_base { UINT rs_id, uType; public: patch_resource_message_class_w(UINT rs_id, UINT uType) : rs_id(rs_id), uType(uType) {} void fire() { auto str = resource_string_w(rs_id); if (str.has_value()) { try { MessageBoxW(NULL, str.value().c_str(), L"patch.aul", uType); } catch (const std::format_error&) { MessageBoxW(NULL, L"format error ({})"_fmt(rs_id).c_str(), L"patch.aul", MB_TOPMOST | MB_TASKMODAL | MB_ICONERROR); } } else { MessageBoxW(NULL, L"resource error ({})"_fmt(rs_id).c_str(), L"patch.aul", MB_TOPMOST | MB_TASKMODAL | MB_ICONERROR); } } }; inline std::vector> patch_resource_message_stack; inline void web_confirm(std::wstring_view url) { enum ID : int { Open, Copy, Cancel }; auto r_main = resource_string_w(PATCH_RS_PATCH_WEB_CONFIRM); auto r_open = resource_string_w(PATCH_RS_PATCH_WEB_CONFIRM_BUTTON_OPEN); auto r_copy = resource_string_w(PATCH_RS_PATCH_WEB_CONFIRM_BUTTON_COPY); auto r_cancel = resource_string_w(PATCH_RS_PATCH_WEB_CONFIRM_BUTTON_CANCEL); TASKDIALOG_BUTTON vtdb[] = { { static_cast(ID::Open), r_open->c_str() }, { static_cast(ID::Copy), r_copy->c_str() }, { static_cast(ID::Cancel), r_cancel->c_str() } }; TASKDIALOGCONFIG tdc{ .cbSize = sizeof(TASKDIALOGCONFIG), .hwndParent = NULL, .hInstance = GLOBAL::patchaul_hinst, .dwFlags = TDF_SIZE_TO_CONTENT, .dwCommonButtons = 0, .pszWindowTitle = L"patch.aul", .pszMainIcon = TD_INFORMATION_ICON, .pszMainInstruction = r_main->c_str(), .pszContent = url.data(), .cButtons = std::size(vtdb), .pButtons = vtdb, .nDefaultButton = static_cast(ID::Open), .cRadioButtons = 0, .pRadioButtons = nullptr, .nDefaultRadioButton = NULL, .pszVerificationText = nullptr, .pszExpandedInformation = nullptr, .pszExpandedControlText = nullptr, .pszCollapsedControlText = nullptr, .pszFooterIcon = NULL, .pszFooter = nullptr, .pfCallback = nullptr, .lpCallbackData = NULL, .cxWidth = 0 }; int nButton; TaskDialogIndirect(&tdc, &nButton, nullptr, nullptr); switch (nButton) { case ID::Open: ShellExecuteW(NULL, L"open", url.data(), nullptr, nullptr, SW_SHOW); break; case ID::Copy: { auto urla = string_convert_W2A(url); HGLOBAL handle = GlobalAlloc(GHND | GMEM_SHARE, urla.size() + 1); auto mem = static_cast(GlobalLock(handle)); urla.copy(mem, urla.size()); GlobalUnlock(handle); OpenClipboard(NULL); EmptyClipboard(); SetClipboardData(CF_TEXT, handle); CloseClipboard(); break; } } } ================================================ FILE: patch/version.hpp ================================================ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #pragma once #include "cryptostring.hpp" #include "macro.h" inline cryptostring patchaul_info( PATCH_VERSION_NAME "\n" "developed by ePi" ); ================================================ FILE: patch.aul.txt ================================================ patch.aul r43 beta1 © 2021-2023 ePi https://scrapbox.io/ePi5131/patch.aul 概要 AviUtlや拡張編集のバグを直したり高速化をしたり新機能を追加したりするプラグインです。 要求環境 AviUtl version 1.10 拡張編集 version 0.92 Visual C++ 再頒布可能パッケージ 2015-2022 X86 推奨環境 OpenCLを使用可能なデバイス AVX2命令を使用可能なCPU 導入 patch.aul は aviutl.exe と同じディレクトリに配置します。 機能 修正 ・オブジェクトファイルの入力で、トラックバーの -1 超 0 未満の値が正になってしまう ・オブジェクトファイルの入力で、トラックバー変化方法スクリプトの名前にASCII以外の文字が含まれているとパラメータを読み込めない ・オブジェクトファイルの入出力で、シーン番号を正しく扱えない ・テキストオブジェクトでUTF-16で34バイト以上のフォント名を指定している時、制御文字でサイズのみを指定していると正しい動作をしない ・クリッピング&リサイズの設定のラベルの脱字 ・メニュー文字列を実態に即したものに変更 ・動画ファイル と 音声ファイル で中間点を打っていないときでもファイルを再参照しても再生位置などの情報を変更しない ・拡張編集以外のフィルタ(例:拡張色調補正)を使ったプロジェクトをオブジェクトファイルに出力できないことがある ・極座標変換/ディスプレイスメントマップ/放射ブラー/閃光/縁取り/方向ブラー/レンズブラー/グローの高速化 OpenCL/AVX2を使用します わずかにオリジナルと結果が変わってしまいます (floatとdoubleの差です) また、アーティファクトなどのバグを解消することもあります ・図形の高速化 円/三角形/五角形/六角形/星形の計算を僅かに最適化 マスクやディスプレイスメントマップのソースとしての図形にも効果がある ・テキストの軽量化 キャッシュをとります ・Luaの環境が分かれてしまうことがある ・package.path,package.cpathはどんなときでもscriptフォルダを含めるように ・obj.randでs=-2^31,e=2^31-1とすると例外になる ・obj.getvalueで中心座標(cx,cy,cz)の情報を取得できるように ・obj.getvalue("layerX.time")が正しい値を取得できるように ・拡張編集ウィンドウと設定ダイアログの描画の最適化 ・拡張編集ウィンドウの上部をドラッグしても正常にリサイズができるように ・元に戻す の多数のバグ修正 ・レイヤー削除→元に戻すで他シーンのオブジェクトが消える ・Ctrlで複数オブジェクトを選択しながら設定ダイアログのトラックバーを動かすと一部オブジェクトが正常に戻らない ・オブジェクトの左端をつまんで動かすと再生位置パラメータが変わるが、それが元に戻らない ・一部フィルタのファイル参照を変更→元に戻すで設定ダイアログが更新されない(音声波形など) ・部分フィルタのマスクの種類を変更してもUndoデータが生成されない ・テキストオブジェクトのフォントを変更してもUndoデータが生成されない ・テキストオブジェクトの影付き・縁付きを変更してもUndoデータが生成されない ・テキストオブジェクトの文字配置(左寄せ[上]など)を変更してもUndoデータが生成されない ・テキストオブジェクトの字間/行間を変更してもUndoデータが生成されない ・グループ制御とかの対象レイヤー数を変更してもUndoデータが生成されない ・テキストを変更してもUndoデータが生成されない ・スクリプト制御・カメラスクリプトを変更してもUndoデータが生成されない ・左クリックよりレイヤーの表示状態を変更してもUndoデータが生成されない ・右クリックメニューよりレイヤーの表示状態を変更してもUndoデータが生成されない ・右クリックメニューよりレイヤーのロック状態を変更してもUndoデータが生成されない ・右クリックメニューよりレイヤーの座標のリンク状態を変更してもUndoデータが生成されない ・右クリックメニューより上クリッピング状態を変更してもUndoデータが生成されない ・右クリックメニューより他のレイヤーを全表示/非表示を押してもUndoデータが生成されない ・ショートカットよりレイヤーの表示状態を変更してもUndoデータが生成されない ・カメラ制御の対象にするかどうかの変更でUndoデータが生成されない ・上のオブジェクトでクリッピングの変更でUndoデータが生成されない ・テンキーによるオブジェクトへの操作でUndoデータが生成されない ・拡張編集以外のフィルタのトラックバーにトラックバー変化方法スクリプトを適用していると例外になる問題 ・小さい画像に対してサイズ固定で範囲の大きいレンズブラーを掛けると例外になるのを修正 ・拡張色変換のウィンドウが下のフィルタに被るのを修正 ・ノイズの速度X、変化速度のトラック変化方法が移動無し以外の時に速度Yの値をもとに計算が行われてしまうのを修正 ・右クリック分割で設定ダイアログが更新されないのを修正 ・右クリック削除でテキストの字間行間が変わることがあるのを修正 ・標準描画-拡張描画-パーティクル出力の切り替え時にトラック変化の設定値(移動フレーム間隔)が0になるのを修正 ・トラックバー変化方法の移動量指定と時間制御の組み合わせでバグるのを修正 ・アルファチャンネル有りシーンで合成モード「通常」以外を使用すると、他シーンで表示した時の結果が正しくないのを修正 ・ファイルパスに使用できない文字が含まれている時に出すエラーメッセージを変更する ・色調補正の色相計算を修正 ・プロジェクトの保存/読み込み時にシーン設定の一部情報(グリッド設定など)が欠けるのを修正 ・exa,exo生成時、設定ダイアログの▼(折り畳み)とマウスマーク(GUI表示)の情報を追加する ・BMP File Readerを使うと、正しくない画像データをキャッシュしてしまうことがあるのを修正 ・動画、音声ファイル参照の時、exedit.iniにある拡張子を追加する ・特定色域変換で変換前色に黒色を指定すると0除算が起こることがあるのを修正 ・範囲の大きいレンズブラーを掛けると危険な処理が行われるのを修正 ・新規プロジェクト作成ダイアログの画像サイズ入力欄の幅を広げる ・パラメータを持つトラックバー変化方法スクリプトを含んだオブジェクトファイルの読み込みが正常に行えないことがあるのを修正 ・ファイルの情報を開くと落ちる/ファイル制御情報が正しくないことがあるのを修正 ・中間点で再生速度を変更した時、そこまでの中間点の数だけ速度変化が遅れて反映されるバグの修正 ・グローのしきい値が負の値になった時にエラーとなる・スレッド数より小さいサイズに正常に効果が反映されないバグの修正 ・新規プロジェクト作成時にサイズ・フレームレートが変わるフィルタをオフにする ・レイヤー情報を保存するかどうかの判定方法を変える(従来:オブジェクトが存在する→変更:レイヤー情報が初期値でない) ・読み込もうとしたファイルパスが長くて失敗するときにメッセージを出す/エラーが発生するのを修正 ・ドロップ処理で最終的に何も行われなかったときにメッセージを出力する 追加 ・コンソールの表示 標準入出力・エラー出力を流します。 「表示」メニューに「コンソールの表示」が追加されています。 Ctrlを押しながら選択すると、表示中でも最前面に表示し直します。 ・拡張編集のOutputDebugStringの内容の表示 console,console.debugstringが有効になっていなければ使えません。コンソールに表示します。 Luaのエラー内容なら赤い文字、debug_printの内容は青い文字で出力します。 ・例外メッセージのリニューアル 間違いが起こらないようにしました。 はいを押して、別のファイルに編集プロジェクトを保存して、それを開いてみるのが正しい作法でしたが、 patch.aulが追加する例外ダイアログからプロジェクトの保存を試みられるようになりました。 正しくプロジェクトの保存ができなければ、自動バックアップから復元します。 ・デバッグ情報出力 より報告/調査を楽にします。 デバッグ情報は \log に出力されます。 これを発生したときの状況と一緒に有識者に投げると、原因がわかったり、patch.aulで直されたりするかもしれません。 ・メニューにアクセスキーを追加 ファイル(F) みたいになるやつです。 Alt+括弧内のキー を押すと飛べます。 ・テーマ機能 ConstChangerでできるのと同じようなことができます。逆に言えばそれ以上はできません。 ・Lua関連の仕様変更/追加関数 ・randexクラスを追加 標準のrand関数の分布がおかしいので ・package.path,package.cpathに新たなディレクトリを追加 ・pathには\module\?.lua;\module\?\init.lua ・cpathには\module\?.dll ・やり直し 機能 元に戻すの逆 設定 patch.aulと同じパスにpatch.aul.jsonが生成されて、これが設定ファイルになります。 設定ファイルはAviUtlの起動時に1度だけ読み込まれて、終了時に1度だけ保存されるため、注意してください。 各キーの説明 ※説明用の型 color : stringで、書式が[0-9a-fA-F]{6}であるもの RRGGBBの順 "console" : { ; コンソール関連 "visible" : boolean, ; コンソールの表示 (既定値: false) "rect" : [number, number, number, number], ; コンソールの位置(left,top,right,bottom) }, "theme_cc" : { ; ConstChangerでできる設定 "layer" : { "height_large" : number, ; レイヤーの高さ (大 既定値: 31) "height_medium" : number, ; レイヤーの高さ (中 既定値: 26) "height_small" : number, ; レイヤーの高さ (小 既定値: 22) "link_col" : [color, color] or color, ; 座標のリンク ([縁色, 塗りつぶし色] または 色 既定値: "4040c0") "clipping_col" : [color, color] or color, ; クリッピング ([縁色, 塗りつぶし色] または 色 既定値: "c04040") "lock_col" : [color, color], ; レイヤーのロックの色 ([縁色, 塗りつぶし色] 既定値: [ "000000", "c04040" ]) "hide_alpha" : number, ; 非表示レイヤーの不透明度 ([0,1] 既定値: 0.85) }, "object" : { "media_col" : [color, color, color], ; 図形 などの青系のオブジェクトの色 ([グラデーション始点, 終点, 選択中] 既定値: [ "10206c", "1830c0", "4080ff" ]) "mfilter_col" : [color, color, color], ; シーンチェンジ などの緑系のオブジェクトの色 (既定値: [ "106c10", "18c018", "40f040" ]) "audio_col" : [color, color, color], ; 音声ファイル などの赤系のオブジェクトの色 (既定値: [ "6c1018", "c01820", "f83040" ]) "afilter_col" : [color, color, color], ; 音量の調整 などの黄系のオブジェクトの色 (既定値: [ "6c6c10", "c0c020", "d8d840" ]) "control_col" : [color, color, color], ; カメラ制御 などの青緑系のオブジェクトの色 (既定値: [ "106c6c", "18c0c0", "40d8d8" ]) "inactive_col" : [color, color, color], ; アルファチャンネル付きシーン中のフィルタオブジェクト などの灰系のオブジェクトの色 (既定値: [ "606060", "808080", "909090" ]) "clipping_col" : color, ; 上のオブジェクトでクリッピング(オブジェクト)の色 (既定値: "c04040") "clipping_height" : number, ; 上のオブジェクトでクリッピング(オブジェクト)の印の高さ (既定値: -3) "midpt_size" : [number, number, number], ; 中間点の大きさ(レイヤーの高さ大,中,小) (既定値: [4, 3, 3]) "name_col" : [color, color], ; オブジェクト名の色 ([有効時,無効時] 既定値: [ "ffffff", "a0a0a0" ]) }, "timeline" : { "scale_col" : [fore, back], ; 拡大率の色 (既定値: [ "60a0ff", "204080" ]) "bpm_grid_col" : [measure, beat], ; BPMグリッドの色 (既定値: [ "646464", "a0a0a0" ]) } }, "redo" : { ; やり直し 機能について "shift" : true ; Ctrl+Shift+Z によるやり直し操作を有効化するか (既定値: true) }, "fast_exeditwindow" : { ; 拡張編集ウィンドウの描画の最適化 について "step" : 0 ; グラデーション描画の方法 (負数でパッチ無効,0でグラデーションのパッチ,正数でその分割数の単色矩形 既定値: 0), }, "fast_text" : { ; テキストの軽量化について "release_time" : 120 ; キャッシュデータの寿命[秒] }, "switch" : { ; どのパッチを有効にするかを選択するものです trueなら有効、falseなら無効 "access_key" : boolean, ; アクセスキーを付加するか (既定値: false) "aup_scene_setting" : boolean, ; プロジェクトの保存/読み込み時にシーン設定の一部情報(グリッド設定など)が欠けるのを修正 (既定値: true) "colorpalette_cache" : boolean, ; bmpのキャッシュが作られる際に、カラーパレット分のデータ容量を取り忘れているのを修正 (既定値: true) "fileinfo" : boolean, ; ファイルの情報を開くと落ちる/ファイル制御情報が正しくないことがあるのを修正 (既定値: true) "aup_layer_setting" : boolean, ; プロジェクトの保存時、レイヤー情報を保存する基準を変える (既定値: true) "exo_aviutl_filter" : boolean, ; 拡張編集以外のフィルタ(例:拡張色調補正)を使ったプロジェクトをオブジェクトファイルに出力できないことがある (既定値: true) "exo_sceneidx" : boolean, ; オブジェクトファイルの入出力で、シーン番号を正しく扱えない (既定値: true) "exo_trackparam" : boolean, ; オブジェクトファイルの入力で、トラックバー変化方法スクリプトの名前にASCII以外の文字が含まれているとパラメータを読み込めない (既定値: true) "exa_fold_gui" : boolean, ; exa,exo生成時、設定ダイアログの▼(折り畳み)とマウスマーク(GUI表示)の情報を追加する (既定値: true) "exo_track_minusval" : boolean, ; オブジェクトファイルの入力で、トラックバーの -1 超 0 未満の値が正になってしまう (既定値: true) "exo_midpt_and_tra" : boolean, ; 中間点有りで.traスクリプト変化方式のあるオブジェクトがあるexoが正常に読み込めないことがあるのを修正 (既定値: true) "exo_specialcolorconv" : boolean, ; オブジェクトファイルの入出力で、特定色域変換のstatusが2つあって正しく入出力できない (既定値: true) "tra_aviutlfilter" : boolean, ; 拡張編集以外のフィルタのトラックバーにトラックバー変化方法スクリプトを適用していると例外になる問題 (既定値: true) "tra_change_drawfilter" : boolean, ; 標準描画-拡張描画-パーティクルの切り替え時にトラックバーの設定値(移動フレーム間隔)が0になるのを修正 (既定値: true) "tra_specified_speed" : boolean, ; トラックバー変化方法の移動量指定と時間制御の組み合わせでバグるのを修正 (既定値: true) "setting_new_project" : boolean, ; 新規プロジェクト作成時にサイズ・フレームレートの変わるフィルタをオフにする (既定値: true) "text_op_size" : boolean, ; テキストオブジェクトでUTF-16で34バイト以上のフォント名を指定している時、制御文字でサイズのみを指定していると正しい動作をしない (既定値: true) "ignore_media_param_reset" : boolean, ; 動画ファイル と 音声ファイル で中間点を打っていないときでもファイルを再参照しても再生位置などの情報を変更しない (既定値: false) "failed_sjis_msgbox" : boolean, ; ファイルパスに使用できない文字が含まれている時に出すエラーメッセージを変更する (既定値: true) "failed_longer_path" : boolean, ; 読み込もうとしたファイルパスが長くて失敗するときにメッセージを出す/エラーが発生するのを修正 (既定値: true) "failed_file_drop" : boolean, ; ドロップ処理で最終的に何も行われなかったときにメッセージを出力する (既定値: true) "theme_cc" : boolean, ; テーマ機能 (既定値: true) "exeditwindow_sizing" : boolean, ; 拡張編集ウィンドウの上部をドラッグして正常にリサイズできるようにする (既定値: true) "settingdialog_move" : boolean, ; 設定ダイアログを高ポーリングレートマウス環境で移動すると重たい の解消 (既定値: true) "obj_colorcorrection" : boolean, ; 色調補正の色相計算を修正 (既定値: true) "obj_lensblur" : boolean, ; レンズブラーのバグ修正 (既定値: true) "obj_glow" : boolean, ; グローのしきい値が負の値になった時にエラーとなる・スレッド数より小さいサイズに正常に効果が反映されないバグを修正 (既定値: true) "obj_lensblur" : boolean, ; 小さい画像に対してサイズ固定で範囲の大きいレンズブラーを掛けると例外になるのを修正 (既定値: true) "obj_noise" : boolean, ; ノイズの速度X、変化速度のトラック変化方法が移動無し以外の時に速度Yの値をもとに計算が行われてしまうのを修正 (既定値: true) "obj_specialcolorconv" : boolean, ; 特定色域変換で変換前色に黒色を指定すると0除算が起こることがあるのを修正 (既定値: true) "settingdialog_excolorconfig" : boolean, ; 拡張色変換のウィンドウが下のフィルタに被るのを修正 (既定値: true) "r_click_menu_split" : boolean, ; 右クリック分割で設定ダイアログが更新されないのを修正 (既定値: true) "r_click_menu_delete" : boolean, ; 右クリック削除でテキストの字間行間が変わることがあるのを修正 (既定値: true) "blend" : boolean, ; アルファチャンネルのあるフレームバッファで合成モード「通常」以外を使用すると誤った結果になるのを修正 (既定値: true) "add_extension" : boolean, ; 動画、音声ファイル参照の時、exedit.iniにある拡張子を追加する (既定値: true) "new_project_editbox" : boolean, ; 新規プロジェクト作成ダイアログの画像サイズ入力欄の幅を広げる (既定値: true) "playback_speed" : boolean, ; 中間点で再生速度を変更した時、そこまでの中間点の数だけ速度変化が遅れて反映されるバグの修正 (既定値: true) "undo" : boolean, ; 元に戻す 関連のバグ修正 (既定値: true) "undo.redo" : boolean, ; やり直す を追加 (既定値: true) "console" : boolean, ; コンソール (既定値: true) "console.escape" : boolean, ; エスケープシーケンス (既定値: true) "console.input" : boolean, ; 標準入力を受け取るか (既定値: false) "console.debug_string" : boolean, ; 拡張編集のOutputDebugStringの内容を表示する (既定値: true) "console.debug_string.time" : boolean, ; 拡張編集のOutputDebugStringの内容の先頭に時刻を表示する (既定値: true) "lua" : boolean, ; lua.*配下のスイッチの主電源 (既定値: true) "lua.env" : boolean, ; Luaの環境を統一する (既定値: false) "lua.path" : boolean, ; package.path,cpathにパスを追加 (既定値: false) "lua.getvalue" : boolean, ; getvalueで中心座標を取得できるように (既定値: true) "lua.rand" : boolean, ; rand関数で例外になるパターンを潰す (既定値: true) "lua.randex" : boolean, ; 正確な乱数を提供するrandexクラスの追加 (既定値: true) "fast" : boolean, ; fast.*配下のスイッチの主電源 (既定値: true) "fast.exeditwindow" : boolean, ; 拡張編集ウィンドウの描画の最適化 (既定値: true) "fast.settingdialog" : boolean, ; 設定ダイアログの描画の最適化 (既定値: true) "fast.text" : boolean, ; テキストの軽量化 (既定値: true) "fast.create_figure" : boolean, ; 図形の高速化 (既定値: true) "fast.border" : boolean, ; 縁取りの高速化/バグ修正 (既定値: true) "fast.glow" : boolean, ; グローの高速化 (既定値: true) "fast.cl" : boolean, ; fast.*でOpenCLが必要なオプションに必要なオプション (既定値: true) "fast.radiationalblur" : boolean, ; fast.clが前提 放射ブラーの高速化 (既定値: true) "fast.polortransform" : boolean, ; fast.clが前提 極座標変換の高速化 (既定値: true) "fast.displacementmap" : boolean, ; fast.clが前提 ディスプレイスメントマップの高速化 (既定値: true) "fast.flash" : true : boolean, ; fast.clが前提 閃光の高速化 (既定値: true) "fast.directionalblur" : boolean, ; fast.clが前提 方向ブラーの高速化 (既定値: true) "fast.lensblur" : boolean ; fast.clが前提 レンズブラーの高速化 (既定値: true) } Lua追加要素詳細 _PATCH patch.aulのバージョン情報 現在は "patch.aul r43 beta1" という文字列が格納されている obj.randex(seed,frame) seed : integer frame : integer obj.randのseed,frameと同じ使い方をする return : userdata 乱数生成オブジェクト userdata(start,end)の形式で呼び出せて、呼び出しの毎に返されるintegerは変わる ライセンス LGPLv3 詳細はLICENSEファイルを見よ その他の注意 デバッグ情報ファイルには、個人情報が含まれる可能性があります。例えば個人情報を扱っているところで例外が発生した場合、レジスタやスタックにその情報が載っているかもしれません。 ファイルを第三者に送信する際には気をつけて下さい。 更新履歴 r2 バージョンが異なっていたときの処理/メッセージ修正 けしからんフックをするプラグインへの対策 r3 デバッグ情報のstackの目盛りがズレてた ConstChanger相当の機能を追加 コンソールのエスケープシーケンスを有効にする設定を追加(デフォルトでは有効) debug_print,Luaのエラーの時に先頭に時刻を付加する設定を追加(デフォルトでは有効) 例外ダイアログをモーダルにした 例外ダイアログの生成に失敗するパターンを潰した 例外ダイアログのXボタンでアプリケーションが終了するのは意図していない挙動だったので修正 その他内部の整理 r4 未成の処理が紛れ込んでいたので削除 r5 SysInfo::info に誤ったポインタを代入していた問題(r3から)を修正 r6 どのパッチを適用するかユーザーが指定できるようにした 例外ダイアログ表示時に音が出るようにした 例外ダイアログが言語拡張リソースに対応した r7 動画ファイル と 音声ファイル で中間点を打っていないときでもファイルを再参照しても再生位置などの情報を変更しない を追加 r8 例外ダイアログから編集プロジェクトの保存を試みられるようにした コンソールウィンドウの位置をAviUtlが再起動しても保持するようにした コンソールウィンドウが標準入力を受け取るかを選択できるようにして、受け取らないときはコンソールの表示がSW_SHOW/SW_HIDEになるようにした Luaで error() としてpatch.aulの例外になるケースを修正 拡張編集以外のフィルタ(例:拡張色調補正)を使ったプロジェクトをオブジェクトファイルに出力できないことがある の修正を追加 不正な設定ファイルであったとき、初期設定で上書きしないようにした patch.aulの出すメッセージが言語拡張リソースに一部対応 中間点のサイズがレイヤー幅中のときのものしか変更できなかった問題を修正 オブジェクトファイルの入出力で、特定色域変換のstatusが2つあって正しく入出力できない の修正を追加 [表示][拡大表示][ウィンドウサイズを自動変更]が欠落していた問題を修正 r9 patch.aulの出すメッセージが言語拡張リソースに全て対応 例外情報のC++ exceptionの詳細情報を追加 極座標変換と放射ブラーの高速化を追加 r10 v_func_WndProcをフックするプログラムにやさしくない書き方をしていたのを修正 r11 Luaの環境を統一 obj.randで例外になるものの修正 randexクラスを追加 obj.getvalueで中心座標の情報を取得できるようにした obj.getvalue("layerX.time")が正しい値を取得できるようにした スクリプトがscriptフォルダの子フォルダにあった時にpackage.path,cpathにscriptを追加 package.path,cpathにmoduleフォルダを追加 OpenCLの要求バージョンを1系に下げた OpenCLのdouble拡張を要求しないようにした r12 Luaに _PATCH 変数を追加 r13 拡張編集ウィンドウと設定ダイアログの描画の最適化 拡張編集ウィンドウの上部をドラッグしても正常にリサイズができるように switch\lua.pathの既定値をfalseに r14 スクリプト並び替えプラグインとの競合を解消 r15 Luaの環境統合をlua.envスイッチに切り出し 起動時に設定ファイルを生成するように その他内部の整理 r17 OSS化 設定ダイアログを高ポーリングレートマウス環境で移動すると重たい の解消 拡張編集の元に戻すのバグ修正 拡張編集にやり直すを追加 r18 設定ダイアログへの操作の修正 r19 競合プラグインがあったら無効化した上で消すか訊くことにした r20 設定ダイアログのサイズが変更されたときの画面外の領域が正しく描画されないのを修正 r21 再修正 というかやり方を変えた settingdialog_moveスイッチが機能してなかったのを修正 r22 閃光の高速化を追加 カメラ制御の対象にするかどうかの変更を元に戻せない問題の修正 上のオブジェクトでクリッピングの変更を元に戻せない問題の修正 テンキーによるオブジェクトへの操作を元に戻せない問題の修正 拡張編集以外のフィルタのトラックバーにトラックバー変化方法スクリプトを適用していると例外になる問題の修正 r23 redoの既定値がfalseになっていたのを修正 r24 アクセスキーの設定を有効にしても機能が有効化されないのを修正 r25 console\visible,lua.getvalue,rand,randex,pathの既定値が逆になってたのを修正 r26 lua.env,pathの設定を正しく扱えなかったのを修正 exo_aviutlfilterが動作しなかったのを修正 switch\redoをfalseにしているときに元に戻すのショートカットを行うと死ぬのを修正 r27 コンソールへのLua関連の出力が動作していなかったのを修正 ランタイムライブラリを不要にした r28 テキストの軽量化を追加 ランタイムライブラリを不要にしたのを取り消し r29 一部条件でテキスト軽量化がエラーになるのを修正 r30 lua.rand,randex,getvalueが機能していなかったのを修正 r31 RePOPnビルドL-SMASH Works r940を導入していると警告を表示する機能を追加 r32 LSWの警告で遷移するサイトをScrapboxに変更 r33 縁取りの高速化/バグ修正を追加 r34 fast.borderのバグを修正 r35 fast.borderのバグを修正2 放射ブラー(フィルタオブジェクト)/方向ブラー(両方)/レンズブラー(両方)の高速化を追加 小さい画像に対してサイズ固定で範囲の大きいレンズブラーを掛けると例外になるのを修正 拡張色変換のウィンドウが下のフィルタに被るのを修正 ビルド環境の変更(submoduleやNuGetを使うように) r36 方向ブラー/放射ブラーの高速化のバグを修正 r37 OpenCLの要求バージョンが上がっていたのを修正 r38 OpenCLの要求バージョンが上がっていたのを修正2 r39 方向ブラーの高速化のバグを修正 r40 レンズブラーの高速化のバグを修正 タイムラインのアイテムが長すぎるときに描画色がおかしくなるのを修正 r41 タイムラインのアイテムが長すぎるときに描画色がおかしくなるのを再修正 r42 ディスプレイスメントマップの高速化を追加 図形の高速化を追加 色調補正の色相の修正を追加 ファイルパスが原因の「対応していないフォーマット~」エラーのメッセージを変更する を追加 極座標変換/放射ブラーの高速化を修正 右クリックの分割で設定ダイアログが更新されないのを修正 右クリックの削除でテキストの字間行間情報が失われるのを修正 標準描画-拡張描画-パーティクルの切り替え時にトラックバーの設定値(移動フレーム間隔)が0になるのを修正 トラックバー変化方法の移動量指定が時間制御で壊れるのを修正 アルファチャンネルのあるフレームバッファで合成モード「通常」以外を使用すると誤った結果になるのを修正 jsonの数値変換がロケール依存だったので修正 theme_ccがない状態でswitch\themc_ccがfalseの時壊れたjsonが生成されていたのを修正 r43 グローの高速化を追加 ファイルパスに使用できない文字が含まれている時に出すエラーメッセージの変更 色調補正の色相計算を修正 プロジェクトの保存/読み込み時にシーン設定の一部情報(グリッド設定など)が欠けるのを修正 exa,exo生成時、設定ダイアログの▼(折り畳み)とマウスマーク(GUI表示)の情報を追加する BMP File Readerを使うと、正しくない画像データをキャッシュしてしまうことがあるのを修正 動画、音声ファイル参照の時、exedit.iniにある拡張子を追加する 特定色域変換で変換前色に黒色を指定すると0除算が起こることがあるのを修正 範囲の大きいレンズブラーを掛けると危険な処理が行われるのを修正 新規プロジェクト作成ダイアログの画像サイズ入力欄の幅を広げる パラメータを持つトラックバー変化方法スクリプトを含んだオブジェクトファイルの読み込みが正常に行えないことがあるのを修正 ファイルの情報を開くと落ちる/ファイル制御情報が正しくないことがあるのを修正 中間点で再生速度を変更した時、そこまでの中間点の数だけ速度変化が遅れて反映されるバグの修正 グローのしきい値が負の値になった時にエラーとなる・スレッド数より小さいサイズに正常に効果が反映されないバグの修正 新規プロジェクト作成時にサイズ・フレームレートが変わるフィルタをオフにする レイヤー情報を保存するかどうかの判定方法を変える(従来:オブジェクトが存在する→変更:レイヤー情報が初期値でない) 読み込もうとしたファイルパスが長くて失敗するときにメッセージを出す/エラーが発生するのを修正 ドロップ処理で最終的に何も行われなかったときにメッセージを出力する ================================================ FILE: patch.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.32112.339 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "patch", "patch\patch.vcxproj", "{20C4ED31-B17F-445A-90FE-77F8119F831B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release_PDB|x86 = Release_PDB|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {20C4ED31-B17F-445A-90FE-77F8119F831B}.Debug|x86.ActiveCfg = Debug|Win32 {20C4ED31-B17F-445A-90FE-77F8119F831B}.Debug|x86.Build.0 = Debug|Win32 {20C4ED31-B17F-445A-90FE-77F8119F831B}.Release_PDB|x86.ActiveCfg = Release_PDB|Win32 {20C4ED31-B17F-445A-90FE-77F8119F831B}.Release_PDB|x86.Build.0 = Release_PDB|Win32 {20C4ED31-B17F-445A-90FE-77F8119F831B}.Release|x86.ActiveCfg = Release|Win32 {20C4ED31-B17F-445A-90FE-77F8119F831B}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {8ECF7614-0562-458B-825B-AADA74AAACDB} EndGlobalSection EndGlobal ================================================ FILE: readme.md ================================================ # patch.aul ## これはなに AviUtlや拡張編集のバグを直したり機能を追加するプラグイン 黒魔術を一手に引き受けるのが目的 詳細はpatch.aul.txtを読むこと ## ビルドについて - [CUDA TOOLKIT](https://developer.nvidia.com/cuda-toolkit)を用意してください これのOpenCLライブラリを使います 環境変数`CUDA_PATH`を使います - `test`フォルダを用意してください これは`aviutl.exe`などを置くフォルダで、デバッグ実行するとこのディレクトリの`aviutl.exe`が実行されます - ビルドすると、`pack`フォルダにリリース用のファイルが集まります