├── .github
└── workflows
│ └── dotnet-desktop.yml
├── .gitignore
├── .paket
├── Paket.Restore.targets
└── paket.bootstrapper.exe
├── BatGuano
├── CopyBlenderToWC.bat
├── delspin.bat
└── makespin.bat
├── BlenderScripts
├── install.py
└── io_scene_mmobj
│ ├── __init__.py
│ ├── export_mmobj.py
│ └── import_mmobj.py
├── DEVNOTES.md
├── Docs
├── binpackage
│ └── README.md
├── devguide
│ └── README.md
└── userguide
│ └── README.md
├── LICENSE.txt
├── MMAppDomain
├── MMAppDomain.cs
├── MMAppDomain.tlb
├── ModelModCLRAppDomain.csproj
└── Properties
│ └── AssemblyInfo.cs
├── MMDotNet.sln
├── MMLaunch
├── App.config
├── App.fs
├── App.xaml
├── AssemblyInfo.fs
├── BlenderUtil.fs
├── BlenderWindow.xaml
├── BlenderWindow.xaml.fs
├── ConfirmDialog.xaml
├── ConfirmDialog.xaml.fs
├── CreateModWindow.xaml
├── CreateModWindow.xaml.fs
├── GameProfileWindow.xaml
├── GameProfileWindow.xaml.fs
├── KnownGames.fs
├── MMLaunch.fsproj
├── MainWindow.xaml
├── MainWindow.xaml.fs
├── ModUtil.fs
├── ModelMod.ico
├── PreferencesWindow.xaml
├── PreferencesWindow.xaml.fs
├── PreviewHost.fs
├── ProcessUtil.fs
├── Resource.rc
├── Resource.res
├── TestFSI.fsx
├── ViewModelUtil.fs
├── WpfInteropSample
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── D3D11Host.cs
│ ├── D3D11Image.cs
│ ├── D3D9.cs
│ ├── MainWindow.xaml
│ ├── MainWindow.xaml.cs
│ ├── Properties
│ │ ├── AssemblyInfo.cs
│ │ ├── Resources.Designer.cs
│ │ ├── Resources.resx
│ │ ├── Settings.Designer.cs
│ │ └── Settings.settings
│ ├── ReadMe.txt
│ ├── WpfInteropSample.csproj
│ └── WpfInteropSample.sln
└── paket.references
├── MMManaged
├── AssemblyInfo.fs
├── CoreTypes.fs
├── DataEncoding.fs
├── Dn5-MMManaged.fsproj
├── Interop.fs
├── InteropTypes.fs
├── LoadInFSI.fsx
├── Logging.fs
├── MMManaged.fsproj
├── MemoryCache.fs
├── MeshRelation.fs
├── MeshTransform.fs
├── MeshUtil.fs
├── ModDB.fs
├── ModDBInterop.fs
├── Program.fs
├── RegConfig.fs
├── Snapshot.fs
├── SnapshotProfile.fs
├── StartConf.fs
├── State.fs
├── Util.fs
├── Yaml.fs
└── paket.references
├── MMView
├── App.config
├── Camera.fs
├── MMView.fsproj
├── Main.fs
├── Program.fs
├── XnaRender.fs
└── paket.references
├── ModelMod.ico
├── Native
├── Cargo.lock
├── Cargo.toml
├── MMCore.code-workspace
├── build_pgo.sh
├── constant_tracking
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ ├── constant_tracking.rs
│ │ └── lib.rs
├── d3dx
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ ├── d3dx.rs
│ │ └── lib.rs
├── device_state
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ ├── device_state.rs
│ │ └── lib.rs
├── dnclr
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ ├── dnclr.rs
│ │ └── lib.rs
├── global_state
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ ├── global_state.rs
│ │ └── lib.rs
├── hook_core
│ ├── .gitignore
│ ├── .ionide
│ │ └── symbolCache.db
│ ├── .vscode
│ │ └── settings.json
│ ├── Cargo.lock
│ ├── Cargo.toml
│ ├── bresh.sh
│ ├── build.rs
│ ├── buildrel.sh
│ ├── d332-sh.sh
│ ├── r2025g1.sh
│ ├── rb.sh
│ ├── rb32.sh
│ ├── rgw1.sh
│ ├── rme2.sh
│ ├── rt.sh
│ ├── rtl.sh
│ ├── shutil.sh
│ └── src
│ │ ├── debugmode.rs
│ │ ├── hook_constants.rs
│ │ ├── hook_device.rs
│ │ ├── hook_device_d3d11.rs
│ │ ├── hook_render.rs
│ │ ├── hook_render_d3d11.rs
│ │ ├── input_commands.rs
│ │ ├── lib.rs
│ │ └── mod_render.rs
├── hook_snapshot
│ ├── Cargo.toml
│ └── src
│ │ ├── hook_snapshot.rs
│ │ ├── lib.rs
│ │ └── snap_extdll.rs
├── input
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ ├── input.rs
│ │ └── lib.rs
├── interop
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ ├── interop.rs
│ │ └── lib.rs
├── mod_load
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ ├── data_encoding.rs
│ │ ├── lib.rs
│ │ ├── mod_load.rs
│ │ └── mod_vector.rs
├── mod_stats
│ ├── Cargo.toml
│ └── src
│ │ ├── lib.rs
│ │ └── mod_stats.rs
├── profiler
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ ├── lib.rs
│ │ └── profile.rs
├── resetlinks.sh
├── setjunc.sh
├── shader_capture
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ ├── lib.rs
│ │ └── shader_capture.rs
├── shared_dx
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ ├── defs_dx11.rs
│ │ ├── defs_dx9.rs
│ │ ├── dx11rs.rs
│ │ ├── error.rs
│ │ ├── lib.rs
│ │ ├── state.rs
│ │ ├── types.rs
│ │ ├── types_dx11.rs
│ │ ├── types_dx9.rs
│ │ └── util.rs
├── snap_plugin
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ ├── lib.rs
│ │ └── snap_plugin.rs
├── snaplib
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ ├── anim_frame.rs
│ │ ├── anim_snap_state.rs
│ │ ├── lib.rs
│ │ └── snap_config.rs
├── test_e2e
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ ├── lib.rs
│ │ └── test_e2e.rs
├── types
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ ├── d3ddata.rs
│ │ ├── d3dx.rs
│ │ ├── interop.rs
│ │ ├── lib.rs
│ │ └── native_mod.rs
└── util
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ ├── lib.rs
│ └── util.rs
├── README.md
├── SnapshotProfiles
└── SnapshotProfiles.yaml
├── StartupApp
├── App.config
├── AssemblyInfo.fs
├── ModelMod.ico
├── Program.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── StartupApp.csproj
└── StartupApp.sln
├── Test.MMManaged
├── App.config
├── Program.fs
├── Test.MMManaged.fsproj
├── TestMesh.fs
├── TestMeshTransform.fs
├── TestModDB.fs
├── TestModDBInterop.fs
├── TestWriters.fs
├── TestYaml.fs
├── Util.fs
└── paket.references
├── Test.ManagedLaunch
├── Program.fs
└── Test.ManagedLaunch.fsproj
├── Test.NativeLaunch
├── Cargo.lock
├── Cargo.toml
├── basic_format.txt
├── basic_vshader.cso
├── basic_vshader.hlsl
├── dxgiformats.txt
├── runmm.sh
├── simple_vertex_shader.dat
└── src
│ ├── interop_mmobj.rs
│ ├── load_mmobj.rs
│ ├── main.rs
│ └── shadercomp.rs
├── TestData
├── DelMod.yaml
├── ModIndex.yaml
├── Mods
│ ├── FT_Barrel
│ │ ├── FT_BarrelMod.mmobj
│ │ ├── FT_BarrelMod.yaml
│ │ ├── FT_BarrelRef.dds
│ │ ├── FT_BarrelRef.mmobj
│ │ ├── FT_BarrelRef.mtl
│ │ ├── FT_BarrelRef.yaml
│ │ └── FT_BarrelRef_VBDecl.dat
│ ├── FT_Crate
│ │ ├── FT_CrateMod.mmobj
│ │ ├── FT_CrateMod.yaml
│ │ ├── FT_CrateRef.dds
│ │ ├── FT_CrateRef.mmobj
│ │ ├── FT_CrateRef.mtl
│ │ ├── FT_CrateRef.yaml
│ │ └── FT_CrateRef_VBDecl.dat
│ ├── FT_LargeRock
│ │ ├── FT_LargeRockMod.mmobj
│ │ ├── FT_LargeRockMod.yaml
│ │ ├── FT_LargeRockRef.dds
│ │ ├── FT_LargeRockRef.mmobj
│ │ ├── FT_LargeRockRef.mtl
│ │ ├── FT_LargeRockRef.yaml
│ │ └── FT_LargeRockRef_VBDecl.dat
│ └── ModIndex.yaml
├── MonolithMod.mmobj
├── MonolithMod.yaml
├── MonolithRef.mmobj
├── MonolithRef.yaml
├── MonolithRef_VBDecl.dat
├── Test.yaml
├── monolithmod.blend
└── monolithref.blend
├── appveyor.yml
├── build.bat
├── build.fsx
├── installdeps.bat
├── paket.dependencies
├── paket.lock
├── sign.bat
└── updateversions.bat
/.gitignore:
--------------------------------------------------------------------------------
1 | MMWiz/packages/
2 | MMWiz/obj/
3 | ModelMod.sdf
4 | ModelMod.v12.suo
5 | MMWiz/bin/
6 | ModelMod/Debug/
7 | MMWiz/WizUI/obj/
8 | MMView/obj/
9 | MMView/bin/
10 | ModelMod/Release/
11 | MMManaged/obj/
12 | Release/
13 | MMLoader/Debug/
14 | MMAppDomain/obj/
15 | MMAppDomain/bin/
16 | Debug/
17 | packages/
18 | MMDotNet.v12.suo
19 | MMWiz/MMWiz.v12.suo
20 | ModelMod.opensdf
21 | MMData
22 | TestData/monolith.OUT.mmobj
23 | TestData/monolith.TestWrite.mmobj
24 | TestData/monolith.TestWrite.mtl
25 | ipch/
26 | MMManaged/TestFSI.fsx
27 | Logs/
28 | Data/
29 | .fake/
30 | test/
31 | build/
32 | deploy/
33 | .vs/MMDotNet/v14/.suo
34 | .paket/paket.exe
35 | .vs/
36 | certpath.txt
37 | sign/
38 | ModelMod.VC.opendb
39 | MMDotNet.sdf
40 | E2ETestData/
41 | ModelMod.VC.VC.opendb
42 | ModelMod.VC.db
43 | ModelMod/Exports.cpp
44 | ModelMod/exports.h
45 | Native/rb.sh
46 | Native/rb32.sh
47 | Native/testlog.txt
48 | Native/d332-sh.sh
49 | ModelMod/ModelMod.vcxproj.user
50 | TPLib/D3DX9_43_x86_64.dll
51 | TPLib/D3DX9_43_x86.dll
52 | Test.MMManaged/obj
53 | Native/.vscode/settings.json
54 | Native/.ionide/symbolCache.db
55 | MMLaunch/obj
56 | .ionide/symbolCache.db
57 | .rustc_info.json
58 | Native/snaplib/target
59 |
60 | **/target/rls
61 | **/target
62 | Test.ManagedLaunch/obj
63 | Test.ManagedLaunch/bin
64 |
65 | DebugMode.txt
66 | dDebugMode.txt
67 | Native/profiler/__testprofiler__test_prof_summary_log.txt
68 | Native/shared_dx/__testutil__test_log_limit.txt
69 | Native/hook_core/__testhd3d11__test_query_interface.txt
70 | Native/hook_core/__testhd3d11__test_create_device.txt
71 | Native/hook_core/__testhd3d11__test_create_device_threads.txt
72 | Native/hook_core/__testhd3d11__create_and_draw.txt
73 | Test.NativeLaunch/mmobjlist.txt
74 | Native/mod_stats/__test_mod_stats_update.txt
75 | Native/mod_stats/__test_mod_stats.txt
76 | Native/mod_stats/__test_process_messages_1.txt
77 | Native/mod_stats/__test_process_messages_2.txt
78 | Native/mod_stats/__test_process_messages_3.txt
79 | g2025g1_pre.sh
80 | G2025g1
81 | SnapshotProfiles/TestProfile1.yaml
82 | SnapshotProfiles/TexFormat.txt
83 |
--------------------------------------------------------------------------------
/.paket/paket.bootstrapper.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/.paket/paket.bootstrapper.exe
--------------------------------------------------------------------------------
/BatGuano/CopyBlenderToWC.bat:
--------------------------------------------------------------------------------
1 | cd %~dp0
2 |
3 | copy "%appdata%\Blender Foundation\Blender\2.73\scripts\addons\io_scene_mmobj\*.*" ..\BlenderScripts\io_scene_mmobj
4 |
5 | rem pause
6 |
--------------------------------------------------------------------------------
/BatGuano/delspin.bat:
--------------------------------------------------------------------------------
1 | cd %~dp0
2 | del ..\debug\spin.txt
--------------------------------------------------------------------------------
/BatGuano/makespin.bat:
--------------------------------------------------------------------------------
1 | cd %~dp0
2 | dir > ..\debug\spin.txt
3 |
--------------------------------------------------------------------------------
/BlenderScripts/install.py:
--------------------------------------------------------------------------------
1 | # this script is executed by mmlaunch to enable the mmobj plugin
2 |
3 | import addon_utils
4 | import bpy
5 | import sys
6 |
7 | # note, the UI checks for this string because we can't return error codes (see below)
8 | SUCCESS="MMINFO: Plugin enabled"
9 |
10 | outHandle = None
11 |
12 | def wline(line):
13 | if outHandle != None:
14 | print(line, end="\n", file=outHandle)
15 | else:
16 | print(line)
17 |
18 | def install_mmobj():
19 | enabled,_ = addon_utils.check('io_scene_mmobj')
20 | if not enabled:
21 | try:
22 | # this interface changed in 2.77+, try old way first
23 | addon_utils.enable('io_scene_mmobj', True)
24 | except TypeError:
25 | addon_utils.enable('io_scene_mmobj', default_set=True, persistent=True)
26 | enabled,_ = addon_utils.check('io_scene_mmobj')
27 | if enabled:
28 | bpy.ops.wm.save_userpref()
29 | wline(SUCCESS)
30 | else:
31 | # sys.exit(1) # this causes blender to die messily without setting the return code. so we'll just have to print the error
32 | wline("MMERROR: Plugin failed to enable; install path may not be correct, or it is incompatible with this version of blender")
33 | else:
34 | wline(SUCCESS)
35 |
36 | def show_paths():
37 | for p in addon_utils.paths():
38 | wline("MMPATH:" + p)
39 |
40 | defaultCommand = "paths"
41 | command = ""
42 |
43 | commands = {
44 | "paths": show_paths,
45 | "install": install_mmobj
46 | }
47 |
48 | ddIdx = sys.argv.index('--') if '--' in sys.argv else None
49 | if ddIdx == None:
50 | command = defaultCommand
51 | else:
52 | args = sys.argv[(ddIdx+1):]
53 | argc = len(args)
54 | if argc == 0:
55 | command = defaultCommand
56 | elif argc == 1:
57 | command = args[0]
58 | elif argc >= 2:
59 | command = args[0]
60 | outHandle = open(args[1], "w")
61 |
62 | if not command in commands:
63 | print("unknown command")
64 | else:
65 | commands[command]()
66 | if outHandle != None:
67 | outHandle.close()
--------------------------------------------------------------------------------
/DEVNOTES.md:
--------------------------------------------------------------------------------
1 | ## Dev notes
2 |
3 | Its been a while since I wrote most of this code and I don't really
4 | remember all the details of what is going on everywhere. So I made this
5 | document to record any new investigations into changing things
6 | and what issues I found.
7 |
8 | Could use github issues/wiki for this kind of note-taking but I tend to
9 | lose track of information in there. However I will cite any issues that
10 | are relevant here.
11 |
12 | ### 2/21/2022: Deferred managed mod loading
13 |
14 | As of this writing, native code will only create D3D resources for mods
15 | that are actually used in the scene. However once loaded, this memory
16 | is not freed (there is no garbage collection for mods that subsequently
17 | become unused). Ctrl-F1 will clear all of this memory, though mods in
18 | use by the current scene will immediately be reloaded.
19 |
20 | Managed code still loads mesh data for all mods on startup. I looked at
21 | converting some of this to use Lazy loading (via F#'s `lazy` function),
22 | but its a non-trivial change. First issue is that primitive and vertex
23 | counts generally come from the meshes. This means the full mesh needs
24 | to be loaded to get these values, which is slow. It would have been nice
25 | if the mmobj exporter wrote out the vert/prim counts in a comment line
26 | at the top of the file, but I didn't do that back in the day.
27 |
28 | I could probably get away with not knowing the mod vert/prim counts
29 | (they are used for variant processing but maybe not needed early).
30 | However the ref vert/prim counts are needed for native code to
31 | determine when a given rendered primitive actually has some mod available
32 | to replace it. So at a minimum all the ref meshes need to be loaded.
33 |
34 | An option would be to implement additional metadata cache files for each
35 | `.mmobj` on disk. So `.mmobj.cache` or something like that. This could
36 | store the vert/prim counts and anything else needed. There is already
37 | code for detecting whether mmobj files have changed on disk, so this
38 | could just be an extension of that. However the cache file would
39 | probably need to write in an mtime or something so that I don't need to checksum the whole mmobj file, which would be slow. And mtime-based
40 | caching can be a little unreliable, esp when using other software that
41 | "preserves" mtimes. So I'm not going to do this now.
42 |
43 | A related item is the `MeshRelation` objects. These aren't needed until
44 | the mod is actually being prepped for render. I did a test where I
45 | replaced the internal `VertRel` used by this class with a `Lazy`, and it
46 | did help reduce load times especially for unused mods. However,
47 | because of the way the code is structured, we won't actually create the
48 | value until fillModData is called, and then it will block the native thread for potentially 100s of ms, just waiting on managed code, which I don't like to do. So I'd need some scheme where I can start an async
49 | process for that and return "in-progress" to the native code. This would
50 | likely require a new interop API because fillModData needs fully allocated D3D data structures, which would then go unused if
51 | the managed code didn't have any data to fill them with. So, native code
52 | would need to use a new api function to actually start the deferred load and check on its progress for an individual mod. Right now there is a global mod loading API, but not one for individual mods.
53 |
54 | For now I not going to implement deferred/incremental mod loading in the managed code.
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/Docs/binpackage/README.md:
--------------------------------------------------------------------------------
1 | ### ModelMod
2 |
3 | Get the latest version and source code here: https://github.com/jmquigs/ModelMod
4 |
5 | ### Docs
6 |
7 | Required third party software: https://github.com/jmquigs/ModelMod/blob/master/Docs/userguide/README.md#Requirements
8 |
9 | User guide: https://github.com/jmquigs/ModelMod/blob/master/Docs/userguide/README.md
10 |
--------------------------------------------------------------------------------
/MMAppDomain/MMAppDomain.tlb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/MMAppDomain/MMAppDomain.tlb
--------------------------------------------------------------------------------
/MMAppDomain/ModelModCLRAppDomain.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {0AB82497-9F3B-46A5-8FA2-D95E2A79E33B}
8 | Library
9 | Properties
10 | MMAppDomain
11 | ModelModCLRAppDomain
12 | v4.5
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | ..\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | ..\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
57 |
--------------------------------------------------------------------------------
/MMAppDomain/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System.Reflection;
3 | using System.Runtime.InteropServices;
4 |
5 | [assembly: AssemblyTitleAttribute("ModelMod CLR app domain host")]
6 | [assembly: AssemblyDescriptionAttribute("")]
7 | [assembly: GuidAttribute("7b59b7f1-5876-4dd3-abc5-ee380144983d")]
8 | [assembly: AssemblyProductAttribute("ModelMod")]
9 | [assembly: AssemblyVersionAttribute("1.2.0.0")]
10 | [assembly: AssemblyFileVersionAttribute("1.2.0.0")]
11 | namespace System {
12 | internal static class AssemblyVersionInformation {
13 | internal const string Version = "1.2.0.0";
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/MMLaunch/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/MMLaunch/App.fs:
--------------------------------------------------------------------------------
1 | module main
2 |
3 | open System
4 | open FsXaml
5 |
6 | type App = XAML<"App.xaml">
7 |
8 | []
9 | []
10 | let main argv =
11 | App().Root.Run()
--------------------------------------------------------------------------------
/MMLaunch/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/MMLaunch/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace System
2 | open System.Reflection
3 | open System.Runtime.InteropServices
4 |
5 | []
6 | []
7 | []
8 | []
9 | []
10 | []
11 | do ()
12 |
13 | module internal AssemblyVersionInformation =
14 | let [] Version = "1.2.0.0"
15 |
--------------------------------------------------------------------------------
/MMLaunch/BlenderWindow.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
20 |
21 |
23 |
26 |
29 |
30 |
--------------------------------------------------------------------------------
/MMLaunch/ConfirmDialog.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
18 |
21 |
24 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/MMLaunch/ConfirmDialog.xaml.fs:
--------------------------------------------------------------------------------
1 | // ModelMod: 3d data snapshotting & substitution program.
2 | // Copyright(C) 2015,2016 John Quigley
3 |
4 | // This program is free software : you can redistribute it and / or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 2.1 of the License, or
7 | // (at your option) any later version.
8 |
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12 | // GNU General Public License for more details.
13 |
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with this program.If not, see .
16 |
17 | namespace MMLaunch
18 |
19 | open System
20 | open System.IO
21 | open System.Windows
22 | open FSharp.ViewModule
23 | open FSharp.ViewModule.Validation
24 | open System.Windows.Input
25 | open System.ComponentModel
26 | open System.Collections.ObjectModel
27 | open System.Windows.Controls
28 | open Microsoft.Win32
29 |
30 | open FsXaml
31 |
32 | open ViewModelUtil
33 |
34 | type ConfirmDialogView = XAML<"ConfirmDialog.xaml", true>
35 |
36 | type ConfirmDialogViewModel() =
37 | inherit ViewModelBase()
38 |
39 | let mutable view:ConfirmDialogView option = None
40 | let mutable confirmed = false
41 | let mutable displayText = ""
42 | let mutable checkboxText = ""
43 | let mutable checkboxChecked = false
44 |
45 | member x.View
46 | with get() =
47 | match view with
48 | | None -> null
49 | | Some view -> view
50 | and set value =
51 | view <- Some(value)
52 |
53 | member x.Text
54 | with get() = displayText
55 | and set value = displayText <- value; x.RaisePropertyChanged("Text")
56 |
57 | member x.CheckBoxText
58 | with get() = checkboxText
59 | and set value =
60 | checkboxText <- value
61 | x.RaisePropertyChanged("CheckBoxText")
62 | x.RaisePropertyChanged("CheckBoxVisibility")
63 |
64 | member x.CheckBoxVisibility
65 | with get() =
66 | if ViewModelUtil.DesignMode || checkboxText.Trim() <> "" then Visibility.Visible else Visibility.Hidden
67 |
68 | member x.CheckboxChecked
69 | with get () = checkboxChecked
70 | and set (value:bool) =
71 | checkboxChecked <- value
72 | x.RaisePropertyChanged("CheckboxChecked")
73 |
74 | member x.Confirmed
75 | with get() = confirmed
76 |
77 | member x.Cancel =
78 | new RelayCommand (
79 | (fun canExecute -> true),
80 | (fun action -> view |> Option.iter (fun v ->
81 | v.Root.Close() )))
82 |
83 | member x.Confirm =
84 | new RelayCommand (
85 | (fun canExecute -> true),
86 | (fun action -> view |> Option.iter (fun v ->
87 | confirmed <- true
88 | v.Root.Close() )))
89 |
--------------------------------------------------------------------------------
/MMLaunch/CreateModWindow.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
27 |
28 |
31 |
34 |
35 |
47 |
52 |
53 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/MMLaunch/GameProfileWindow.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
--------------------------------------------------------------------------------
/MMLaunch/GameProfileWindow.xaml.fs:
--------------------------------------------------------------------------------
1 | // ModelMod: 3d data snapshotting & substitution program.
2 | // Copyright(C) 2015,2016 John Quigley
3 |
4 | // This program is free software : you can redistribute it and / or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 2.1 of the License, or
7 | // (at your option) any later version.
8 |
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12 | // GNU General Public License for more details.
13 |
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with this program.If not, see .
16 |
17 | namespace MMLaunch
18 |
19 | open System
20 | open System.Diagnostics
21 | open System.Threading
22 | open System.Windows
23 | open System.Windows.Threading
24 | open System.IO
25 | open FSharp.ViewModule
26 | open FSharp.ViewModule.Validation
27 | open System.Windows.Input
28 | open System.ComponentModel
29 | open System.Collections.ObjectModel
30 | open Microsoft.Win32
31 | open FsXaml
32 |
33 | open ViewModelUtil
34 | open ModelMod
35 | open ModelMod.CoreTypes
36 |
37 | type GameProfileView = XAML<"GameProfileWindow.xaml", true>
38 |
39 | type GameProfileViewModel() =
40 | inherit ViewModelBase()
41 |
42 | // The viewmodel is also the actual Model for the GameProfile
43 | let mutable profile = {
44 | GameProfile.ReverseNormals = false
45 | UpdateTangentSpace = true
46 | CommandLineArguments = ""
47 | DataPathName = ""
48 | }
49 | let mutable profileChangedCb: GameProfile -> unit = ignore
50 |
51 | let updateProfile newProfile =
52 | profile <- newProfile
53 | profileChangedCb profile
54 |
55 | member x.Profile
56 | with get() = profile
57 | and set value =
58 | profile <- value
59 | x.RaisePropertyChanged(String.Empty)
60 |
61 | member x.ProfileChangedCb
62 | with get() = profileChangedCb
63 | and set value = profileChangedCb <- value
64 |
65 | member x.ReverseNormals
66 | with get () = profile.ReverseNormals
67 | and set (value:bool) = updateProfile { profile with ReverseNormals = value }
68 |
69 | member x.UpdateTangentSpace
70 | with get() = profile.UpdateTangentSpace
71 | and set (value:bool) = updateProfile { profile with UpdateTangentSpace = value }
72 |
73 | member x.CommandLineArguments
74 | with get () = profile.CommandLineArguments
75 | and set (value:string) = updateProfile { profile with CommandLineArguments = value}
76 |
77 | member x.DataPathName
78 | with get() = profile.DataPathName
79 | and set (value:string) = updateProfile { profile with DataPathName = value }
80 |
--------------------------------------------------------------------------------
/MMLaunch/KnownGames.fs:
--------------------------------------------------------------------------------
1 | namespace MMLaunch
2 |
3 | module KnownGames =
4 |
5 | type DllPath =
6 | | D3D9 of string
7 | | D3D11 of string
8 |
9 | type KnownGame = {
10 | ExeBaseName: string
11 | D3DPaths: DllPath list
12 | Is64Bit: bool
13 | }
14 |
15 | let AllKnownGames = [
16 | {
17 | KnownGame.ExeBaseName = "gw2-64"
18 | D3DPaths = [D3D9(@"bin64"); D3D11(@"")]
19 | Is64Bit = true
20 | }
21 | {
22 | KnownGame.ExeBaseName = "gw"
23 | D3DPaths = [D3D9(@"")]
24 | Is64Bit = false
25 | }
26 | {
27 | KnownGame.ExeBaseName = "TESV"
28 | D3DPaths = [D3D9(@"")] // not sure about this
29 | Is64Bit = false
30 | }
31 | {
32 | KnownGame.ExeBaseName = "DragonAge2"
33 | D3DPaths = [D3D9(@"")] // not sure about this
34 | Is64Bit = false
35 | }
36 | ]
37 |
--------------------------------------------------------------------------------
/MMLaunch/ModelMod.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/MMLaunch/ModelMod.ico
--------------------------------------------------------------------------------
/MMLaunch/PreferencesWindow.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
16 |
17 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/MMLaunch/PreferencesWindow.xaml.fs:
--------------------------------------------------------------------------------
1 | // ModelMod: 3d data snapshotting & substitution program.
2 | // Copyright(C) 2015,2016 John Quigley
3 |
4 | // This program is free software : you can redistribute it and / or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 2.1 of the License, or
7 | // (at your option) any later version.
8 |
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12 | // GNU General Public License for more details.
13 |
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with this program.If not, see .
16 |
17 | namespace MMLaunch
18 |
19 | open System
20 | open System.Diagnostics
21 | open System.Threading
22 | open System.Windows
23 | open System.Windows.Threading
24 | open System.IO
25 | open FSharp.ViewModule
26 | open FSharp.ViewModule.Validation
27 | open System.Windows.Input
28 | open System.ComponentModel
29 | open System.Collections.ObjectModel
30 | open Microsoft.Win32
31 |
32 | open System.Windows.Forms // just for FolderBrowserDialog !
33 | open FsXaml
34 |
35 | open ViewModelUtil
36 | open ModelMod
37 |
38 | type PreferencesView = XAML<"PreferencesWindow.xaml", true>
39 |
40 | type PreferencesViewModel() =
41 | inherit ViewModelBase()
42 |
43 | let mutable docRoot = RegConfig.getDocRoot()
44 |
45 | member x.DocRoot
46 | with get() = docRoot
47 | and set value =
48 | if not (Directory.Exists value) then
49 | ViewModelUtil.pushDialog (sprintf "Directory does not exist: %s" value)
50 | else
51 | docRoot <- value
52 | RegConfig.setDocRoot docRoot |> ignore
53 | x.RaisePropertyChanged("DocRoot")
54 |
55 | member x.Browse = alwaysExecutable (fun action ->
56 | use fb = new FolderBrowserDialog()
57 |
58 | match fb.ShowDialog() with
59 | | DialogResult.OK ->
60 | if Directory.Exists fb.SelectedPath then
61 | x.DocRoot <- fb.SelectedPath
62 | | _ -> ()
63 | )
64 |
--------------------------------------------------------------------------------
/MMLaunch/PreviewHost.fs:
--------------------------------------------------------------------------------
1 | // ModelMod: 3d data snapshotting & substitution program.
2 | // Copyright(C) 2015,2016 John Quigley
3 |
4 | // This program is free software : you can redistribute it and / or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 2.1 of the License, or
7 | // (at your option) any later version.
8 |
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12 | // GNU General Public License for more details.
13 |
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with this program.If not, see .
16 |
17 | namespace MMLaunch
18 |
19 | open System.IO
20 |
21 | open WpfInteropSample
22 | open ModelMod.StartConf
23 | open ModelMod.CoreTypes
24 |
25 | type PreviewHost() =
26 | inherit WpfInteropSample.D3D11Host()
27 |
28 | let mutable selectedFile:string = ""
29 | let mutable control:MeshView.Main.MeshViewControl option = None
30 |
31 | member x.SelectedFile
32 | with get() = selectedFile
33 | and set value =
34 | selectedFile <- value
35 | x.Initialize()
36 |
37 | override x.Initialize() =
38 | x.Uninitialize()
39 |
40 | if (File.Exists selectedFile) then
41 | let conf = {
42 | Conf.ModIndexFile = None
43 | FilesToLoad = [selectedFile]
44 | AppSettings =
45 | Some({
46 | Window = None
47 | CamPosition = Some(Vec3F(0.f,3.75f,10.0f))
48 | MeshReadFlags = { ReadMaterialFile = true; ReverseTransform = false }
49 | })
50 | }
51 | control <- Some(new MeshView.Main.MeshViewControl(conf, x.GraphicsDevice))
52 | ()
53 |
54 | override x.Uninitialize() =
55 | match control with
56 | | None -> ()
57 | | Some ctrl -> (ctrl :> System.IDisposable).Dispose()
58 | control <- None
59 |
60 | override x.Render(time: System.TimeSpan) =
61 | match control with
62 | | None -> ()
63 | | Some (control) ->
64 |
65 | let gt = new Microsoft.Xna.Framework.GameTime(System.TimeSpan(0L), time)
66 | control.Update(gt)
67 | control.Draw(gt)
68 | ()
--------------------------------------------------------------------------------
/MMLaunch/Resource.rc:
--------------------------------------------------------------------------------
1 | 1 ICON "..\ModelMod.ico"
--------------------------------------------------------------------------------
/MMLaunch/Resource.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/MMLaunch/Resource.res
--------------------------------------------------------------------------------
/MMLaunch/TestFSI.fsx:
--------------------------------------------------------------------------------
1 |
2 | #load "BlenderUtil.fs"
3 |
4 | open MMLaunch
5 |
6 | BlenderUtil.findInstallPath()
--------------------------------------------------------------------------------
/MMLaunch/ViewModelUtil.fs:
--------------------------------------------------------------------------------
1 | // ModelMod: 3d data snapshotting & substitution program.
2 | // Copyright(C) 2015,2016 John Quigley
3 |
4 | // This program is free software : you can redistribute it and / or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 2.1 of the License, or
7 | // (at your option) any later version.
8 |
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12 | // GNU General Public License for more details.
13 |
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with this program.If not, see .
16 |
17 | namespace MMLaunch
18 |
19 | open System
20 | open System.ComponentModel
21 | open System.Windows
22 | open FSharp.ViewModule
23 | open FSharp.ViewModule.Validation
24 | open System.Windows.Input
25 |
26 | open Microsoft.Win32
27 |
28 | // When used with Exception as the fail type, this
29 | // encourages the idiom of using pattern matching to
30 | // handle errors, rather than require try blocks in random places.
31 | type Result<'SuccessType,'FailType> =
32 | Ok of 'SuccessType
33 | | Err of 'FailType
34 |
35 | module ViewModelUtil =
36 | let DesignMode = DesignerProperties.GetIsInDesignMode(new DependencyObject())
37 |
38 | type RelayCommand (canExecute:(obj -> bool), action:(obj -> unit)) =
39 | let event = new DelegateEvent()
40 | interface ICommand with
41 | []
42 | member x.CanExecuteChanged = event.Publish
43 | member x.CanExecute arg = canExecute(arg)
44 | member x.Execute arg = action(arg)
45 |
46 | let alwaysExecutable (action:(obj -> unit)) =
47 | new RelayCommand ((fun canExecute -> true), action)
48 |
49 | let pushDialog(msg:string) =
50 | MessageBox.Show(msg) |> ignore
51 |
52 | let pushOkCancelDialog(msg:string) =
53 | MessageBox.Show(msg, "Confirm", MessageBoxButton.YesNo)
54 |
55 | let pushSelectFileDialog(initialDir:string option,filter:string) =
56 | let dlg = new OpenFileDialog()
57 |
58 | match initialDir with
59 | | None -> ()
60 | | Some dir ->
61 | dlg.InitialDirectory <- dir
62 |
63 | dlg.Filter <- filter
64 | dlg.FilterIndex <- 0
65 | dlg.RestoreDirectory <- true
66 |
67 | let res = dlg.ShowDialog()
68 | if res.HasValue && res.Value then
69 | Some (dlg.FileName)
70 | else
71 | None
72 |
73 |
--------------------------------------------------------------------------------
/MMLaunch/WpfInteropSample/App.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/MMLaunch/WpfInteropSample/App.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace WpfInteropSample
2 | {
3 | public partial class App
4 | {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/MMLaunch/WpfInteropSample/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
24 |
30 |
36 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/MMLaunch/WpfInteropSample/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace WpfInteropSample
2 | {
3 | public partial class MainWindow
4 | {
5 | public MainWindow()
6 | {
7 | InitializeComponent();
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/MMLaunch/WpfInteropSample/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("WpfInteropSample")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("WpfInteropSample")]
15 | [assembly: AssemblyCopyright("Copyright © 2013")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | [assembly: ComVisible(false)]
23 |
24 | //In order to begin building localizable applications, set
25 | //CultureYouAreCodingWith in your .csproj file
26 | //inside a . For example, if you are using US english
27 | //in your source files, set the to en-US. Then uncomment
28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
29 | //the line below to match the UICulture setting in the project file.
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
36 | //(used if a resource is not found in the page,
37 | // or application resource dictionaries)
38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
39 | //(used if a resource is not found in the page,
40 | // app, or any theme specific resource dictionaries)
41 | )]
42 |
43 |
44 | // Version information for an assembly consists of the following four values:
45 | //
46 | // Major Version
47 | // Minor Version
48 | // Build Number
49 | // Revision
50 | //
51 | // You can specify all the values or you can default the Build and Revision Numbers
52 | // by using the '*' as shown below:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.0.0")]
55 | [assembly: AssemblyFileVersion("1.0.0.0")]
56 |
--------------------------------------------------------------------------------
/MMLaunch/WpfInteropSample/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.18033
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace WpfHost.Properties
12 | {
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// Returns the cached ResourceManager instance used by this class.
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WpfHost.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// Overrides the current thread's CurrentUICulture property for all
56 | /// resource lookups using this strongly typed resource class.
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/MMLaunch/WpfInteropSample/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.18033
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace WpfHost.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/MMLaunch/WpfInteropSample/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/MMLaunch/WpfInteropSample/ReadMe.txt:
--------------------------------------------------------------------------------
1 | This sample shows how to display MonoGame graphics in a WPF D3DImage.
2 |
3 | This sample requires SharpDX >= v2.5.0!
--------------------------------------------------------------------------------
/MMLaunch/WpfInteropSample/WpfInteropSample.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 11.00
3 | # Visual Studio 2010
4 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{0A3E2DFD-8744-4C43-A60C-2213386B1CF4}"
5 | ProjectSection(SolutionItems) = preProject
6 | ..\..\paket.dependencies = ..\..\paket.dependencies
7 | EndProjectSection
8 | EndProject
9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfInteropSample", "WpfInteropSample.csproj", "{B7751FAB-AE42-457F-8D69-51BEE5DC080A}"
10 | EndProject
11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Framework.Windows", "..\..\MonoGame.Framework\MonoGame.Framework.Windows.csproj", "{7DE47032-A904-4C29-BD22-2D235E8D91BA}"
12 | EndProject
13 | Global
14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
15 | Debug|Any CPU = Debug|Any CPU
16 | Debug|Mixed Platforms = Debug|Mixed Platforms
17 | Debug|x86 = Debug|x86
18 | Release|Any CPU = Release|Any CPU
19 | Release|Mixed Platforms = Release|Mixed Platforms
20 | Release|x86 = Release|x86
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {B7751FAB-AE42-457F-8D69-51BEE5DC080A}.Debug|Any CPU.ActiveCfg = Debug|x86
24 | {B7751FAB-AE42-457F-8D69-51BEE5DC080A}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
25 | {B7751FAB-AE42-457F-8D69-51BEE5DC080A}.Debug|Mixed Platforms.Build.0 = Debug|x86
26 | {B7751FAB-AE42-457F-8D69-51BEE5DC080A}.Debug|x86.ActiveCfg = Debug|x86
27 | {B7751FAB-AE42-457F-8D69-51BEE5DC080A}.Debug|x86.Build.0 = Debug|x86
28 | {B7751FAB-AE42-457F-8D69-51BEE5DC080A}.Release|Any CPU.ActiveCfg = Release|x86
29 | {B7751FAB-AE42-457F-8D69-51BEE5DC080A}.Release|Mixed Platforms.ActiveCfg = Release|x86
30 | {B7751FAB-AE42-457F-8D69-51BEE5DC080A}.Release|Mixed Platforms.Build.0 = Release|x86
31 | {B7751FAB-AE42-457F-8D69-51BEE5DC080A}.Release|x86.ActiveCfg = Release|x86
32 | {B7751FAB-AE42-457F-8D69-51BEE5DC080A}.Release|x86.Build.0 = Release|x86
33 | {7DE47032-A904-4C29-BD22-2D235E8D91BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
34 | {7DE47032-A904-4C29-BD22-2D235E8D91BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
35 | {7DE47032-A904-4C29-BD22-2D235E8D91BA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
36 | {7DE47032-A904-4C29-BD22-2D235E8D91BA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
37 | {7DE47032-A904-4C29-BD22-2D235E8D91BA}.Debug|x86.ActiveCfg = Debug|Any CPU
38 | {7DE47032-A904-4C29-BD22-2D235E8D91BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {7DE47032-A904-4C29-BD22-2D235E8D91BA}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {7DE47032-A904-4C29-BD22-2D235E8D91BA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
41 | {7DE47032-A904-4C29-BD22-2D235E8D91BA}.Release|Mixed Platforms.Build.0 = Release|Any CPU
42 | {7DE47032-A904-4C29-BD22-2D235E8D91BA}.Release|x86.ActiveCfg = Release|Any CPU
43 | EndGlobalSection
44 | GlobalSection(SolutionProperties) = preSolution
45 | HideSolutionNode = FALSE
46 | EndGlobalSection
47 | EndGlobal
48 |
--------------------------------------------------------------------------------
/MMLaunch/paket.references:
--------------------------------------------------------------------------------
1 | Expression.Blend.Sdk
2 | FSharp.ViewModule.Core
3 | FsXaml.Wpf
4 | YamlDotNet
--------------------------------------------------------------------------------
/MMManaged/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace System
2 | open System.Reflection
3 | open System.Runtime.InteropServices
4 |
5 | []
6 | []
7 | []
8 | []
9 | []
10 | []
11 | do ()
12 |
13 | module internal AssemblyVersionInformation =
14 | let [] Version = "1.2.0.0"
15 |
--------------------------------------------------------------------------------
/MMManaged/Dn5-MMManaged.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 | Library
6 | MMManaged
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | ..\packages\MonoGame.Framework.WindowsDX\lib\net40\MonoGame.Framework.dll
33 |
34 |
35 | ..\packages\MonoGame.Framework.WindowsDX\lib\net40\SharpDX.dll
36 |
37 |
38 | ..\packages\MonoGame.Framework.WindowsDX\lib\net40\SharpDX.Direct3D9.dll
39 |
40 |
41 | ..\packages\YamlDotNet\lib\net35\YamlDotNet.dll
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/MMManaged/LoadInFSI.fsx:
--------------------------------------------------------------------------------
1 | (*
2 | This file can be used to test this assembly in F# Interactive.
3 | Create a file called "TestFSI.fsx" with these lines:
4 |
5 | #load "LoadInFSI.fsx"
6 | open ModelMod
7 | ... // your code here
8 |
9 | You can then select all text in TestFSI.fsx (Ctrl-A) and hit Alt-enter to
10 | send it to FSI to run it. The advantage of doing it this way is that
11 | TestFSI.fsx is ignored by source control, so you can put whatever you want
12 | in there without the risk of it accidentally getting committed/conflicted.
13 |
14 | This file contains the basic structure of the project, so it is in
15 | version control - don't put test code here.
16 | *)
17 |
18 | #I @"..\packages\MonoGame.Framework.WindowsDX\lib\net40\"
19 | //#I @"..\packages\YamlDotNet\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\"
20 | #r @"SharpDX.dll"
21 | #r @"SharpDX.Direct3D9.dll"
22 | #r @"MonoGame.Framework.dll"
23 | //#r @"YamlDotNet.dll"
24 |
25 | #load "Logging.fs"
26 | #load "Util.fs"
27 | #load "CoreTypes.fs"
28 |
29 | (*
30 | To speed up iteration time, the rest of the project files are omitted -
31 | use additional #load lines for what you need in TestFSI.fsx. You may need
32 | to add more "open ModelMod" lines if you get errors there, because the modules
33 | assume that everything in ModelMod is in scope.
34 | *)
35 |
--------------------------------------------------------------------------------
/MMManaged/Logging.fs:
--------------------------------------------------------------------------------
1 | // ModelMod: 3d data snapshotting & substitution program.
2 | // Copyright(C) 2015,2016 John Quigley
3 |
4 | // This program is free software : you can redistribute it and / or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 2.1 of the License, or
7 | // (at your option) any later version.
8 |
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12 | // GNU General Public License for more details.
13 |
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with this program.If not, see .
16 |
17 | namespace ModelMod
18 |
19 | open System.Collections.Generic
20 |
21 | module Logging =
22 | type ILog =
23 | abstract member Info : Printf.StringFormat<'a,unit> -> 'a
24 | abstract member Warn : Printf.StringFormat<'a,unit> -> 'a
25 | abstract member Error : Printf.StringFormat<'a,unit> -> 'a
26 |
27 | type CategoryName = string
28 | type NewCategoryName = string
29 | type LoggerFactory = CategoryName -> NewCategoryName * ILog
30 |
31 | let ConsoleLoggerFactory category =
32 | // based on
33 | // http://stackoverflow.com/questions/5277902/printf-style-logging-for-f?lq=1
34 | let formatInfo (result : string ) = printfn "info [%s]: %s" category result
35 | let formatWarn (result : string ) = printfn "warn [%s]: %s" category result
36 | let formatError (result : string ) = printfn "error [%s]: %s" category result
37 |
38 | category, { new ILog with
39 | member x.Info format = Printf.ksprintf (formatInfo) format
40 | member x.Warn format = Printf.ksprintf (formatWarn) format
41 | member x.Error format = Printf.ksprintf (formatError) format
42 | }
43 |
44 | let mutable private loggerFactory = ConsoleLoggerFactory
45 |
46 | let private loggers = new Dictionary()
47 |
48 | let setLoggerFactory(f:LoggerFactory) =
49 | loggers.Clear()
50 | loggerFactory <- f
51 |
52 | let makeLogger x = loggerFactory x
53 |
54 | let getLogger(category) =
55 | let ok, logger = loggers.TryGetValue(category)
56 | let logger =
57 | if ok then logger
58 | else
59 | // ignore the returned category; it may have changed, and we want to store it in the dict
60 | // using the input name so that we can reuse it for future uses of the same category.
61 | let _,logger = makeLogger(category)
62 | loggers.Add(category,logger)
63 | logger
64 | logger
65 |
66 | type logOnceFn = (string -> unit)
67 |
68 | let logOnce(infoWarnOrError:int): logOnceFn =
69 | let log = getLogger("LogOnce")
70 | let mutable logged = false
71 | fun msg ->
72 | if not logged then
73 | match infoWarnOrError with
74 | | 0 -> log.Info "%s" msg
75 | | 1 -> log.Warn "%s" msg
76 | | _ -> log.Error "%s" msg
77 | logged <- true
78 |
79 | let mutable logOnceFns = new Dictionary()
80 | let getLogOnceFn(onceFnId:string,infoWarnOrError:int) =
81 | let ok, ofn = logOnceFns.TryGetValue onceFnId
82 | if ok then
83 | ofn
84 | else
85 | let ofn = logOnce(infoWarnOrError)
86 | logOnceFns.Add(onceFnId, ofn)
87 | ofn
88 |
--------------------------------------------------------------------------------
/MMManaged/MemoryCache.fs:
--------------------------------------------------------------------------------
1 | // ModelMod: 3d data snapshotting & substitution program.
2 | // Copyright(C) 2015,2016 John Quigley
3 |
4 | // This program is free software : you can redistribute it and / or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 2.1 of the License, or
7 | // (at your option) any later version.
8 |
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12 | // GNU General Public License for more details.
13 |
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with this program.If not, see .
16 |
17 | namespace ModelMod
18 |
19 | open System.IO
20 |
21 | open CoreTypes
22 | open InteropTypes
23 |
24 | open System.Collections.Generic
25 |
26 | /// This is a simple in-memory cache for loaded meshes. It speeds up reload iteration time,
27 | /// since only modified meshes are reloaded. Would be nice to extend this to other things
28 | /// (yaml, meshrelation), since time spent in those can add up as well.
29 | /// To force a clear of the cache, use the full reload keybinding to reload the
30 | /// whole assembly.
31 | module MemoryCache =
32 | let private log = Logging.getLogger("MemoryCache")
33 |
34 | type CacheEntry = {
35 | Type:ModType
36 | Flags:MeshReadFlags
37 | Mesh:Mesh
38 | MTime:System.DateTime
39 | }
40 |
41 | let cache = new Dictionary()
42 |
43 | let clear() = cache.Clear()
44 |
45 | let get (path, (modType:ModType), flags):Mesh option =
46 | let ok,entry = cache.TryGetValue path
47 | if ok then
48 | if entry.Type = modType && entry.Flags = flags then
49 | let mtime = File.GetLastWriteTime(path)
50 |
51 | if mtime <= entry.MTime then
52 | log.Info "Cache hit for file: %s" path
53 | Some(entry.Mesh)
54 | else
55 | log.Info "File updated, reloading: %s" path
56 | None
57 | else
58 | log.Warn "Unusable asset cache file; flags or mod type mismatch: %s" path
59 | None
60 | else
61 | log.Info "Cache miss for file: %s" path
62 | None
63 |
64 | let save(path, (modType:ModType), flags, (mesh:Mesh)) =
65 | let mtime = File.GetLastWriteTime(path)
66 | let entry = {
67 | Type = modType
68 | Flags = flags
69 | Mesh = mesh
70 | MTime = mtime
71 | }
72 |
73 | cache.[path] <- entry
74 |
--------------------------------------------------------------------------------
/MMManaged/Program.fs:
--------------------------------------------------------------------------------
1 | module Main
2 |
3 | open System
4 | open System.IO
5 | open System.Windows
6 |
7 | open ModelMod
8 |
9 | // This module is useful for running the managed code under a profiler or debugger.
10 | // To use it, change the project type
11 | // to a "console application", then uncomment the entry point below. You can then run it under
12 | // the visual studio profiler or standlone.
13 | // Also set targetDataDir below.
14 | // While this program is somewhat useful for testing managed code only, for
15 | // the full experience its better to use Test.NativeLaunch so that the
16 | // managed-native interop can be tested.
17 |
18 | let targetDataDir = @"E2ETestData" // set this to your MM data root if this isn't what you want
19 | let searchPaths = [@".\"; @"..\"; @"..\..\"; ]
20 |
21 | let testPath =
22 | if Path.IsPathRooted(targetDataDir) then
23 | Some(targetDataDir)
24 | else
25 | searchPaths
26 | |> List.tryPick
27 | (fun p ->
28 | let p = Path.GetFullPath(p) + targetDataDir
29 | if Directory.Exists(p) then Some(p) else None)
30 |
31 | let load() =
32 | let testPath =
33 | match testPath with
34 | | None -> failwithf "can't find %A in any of these paths: %A" targetDataDir searchPaths
35 | | Some(p) -> p
36 | if not (Directory.Exists testPath) then
37 | failwithf "dir does not exist: %s" testPath
38 |
39 | let mpath = Path.Combine(testPath, "ModIndex.yaml")
40 | let mdb =
41 | ModDB.loadModDB
42 | ({
43 | StartConf.Conf.ModIndexFile = Some(mpath)
44 | FilesToLoad = []
45 | AppSettings = None
46 | }, None)
47 | mdb
48 |
49 | let timeLoads(allowCache) =
50 | let eTimes = Array.zeroCreate 10
51 | [0..(eTimes.Length - 1)] |> List.iter
52 | (fun i ->
53 | if not allowCache then MemoryCache.clear()
54 | let sw = new Util.StopwatchTracker("foo")
55 | sw.SW.Start()
56 | load() |> ignore
57 | let e = sw.SW.ElapsedMilliseconds
58 | eTimes.[i] <- e
59 | )
60 | let eTimes = eTimes |> Array.map double |> Array.sort
61 | let mean = eTimes |> Array.average
62 | let median = eTimes |> fun a -> (a.[5] + a.[4]) / 2.0
63 | let p90 = eTimes.[int (float eTimes.Length * 0.9)]
64 | let stddev =
65 | eTimes |> Array.map (fun t -> (t - mean) ** 2.0) |> Array.average |> Math.Sqrt
66 |
67 | printf "load times (caching: %A): mean: %f, median: %f, 90%%: %f, stddev: %f " allowCache mean median p90 stddev
68 |
69 | let testFill() =
70 | let mdb = load()
71 |
72 | let destDecl:byte [] = Array.zeroCreate (64)
73 | let destVB:byte[] = Array.zeroCreate (833760)
74 | let destIB:byte[] = [||]
75 |
76 | State.Data.Moddb <- mdb
77 | ModDBInterop.testFill(0, destDecl, destVB, destIB) |> ignore
78 |
79 | //[]
80 | let main argv =
81 | let db = load()
82 | //timeLoads(true)
83 | 0
--------------------------------------------------------------------------------
/MMManaged/StartConf.fs:
--------------------------------------------------------------------------------
1 | // ModelMod: 3d data snapshotting & substitution program.
2 | // Copyright(C) 2015,2016 John Quigley
3 |
4 | // This program is free software : you can redistribute it and / or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 2.1 of the License, or
7 | // (at your option) any later version.
8 |
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12 | // GNU General Public License for more details.
13 |
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with this program.If not, see .
16 |
17 | namespace ModelMod
18 |
19 | open System.IO
20 |
21 | open YamlDotNet.RepresentationModel
22 |
23 | open CoreTypes
24 |
25 | /// Contains startup configuration utilities.
26 | /// Allows override of the standard registry and modindex load
27 | /// scheme. Normally only used for non-game invocations
28 | /// (preview window and MMView tool). Unlike RunConfig, StartConf data is not stored in the registry.
29 | module StartConf =
30 | // only use for MMView tool
31 | type WinSettings = {
32 | PosX: int
33 | PosY: int
34 | Width: int
35 | Height: int
36 | AllowResize: bool
37 | }
38 | type AppSettings = {
39 | Window: WinSettings option
40 | CamPosition: Vec3F option
41 | MeshReadFlags: MeshReadFlags
42 | }
43 | type Conf = {
44 | ModIndexFile: string option
45 | FilesToLoad: string list
46 | AppSettings: AppSettings option // only present for the UI tools; MMView, etc
47 | }
48 |
49 | let loadConf confPath (appSettings:AppSettings option) =
50 | let text = File.ReadAllText(confPath)
51 | use input = new StringReader(text)
52 | let yamlStream = new YamlStream()
53 | yamlStream.Load(input)
54 | let docCount = yamlStream.Documents.Count
55 | if (docCount <> 1) then
56 | failwithf "Expected 1 document, got %d" docCount
57 | let mapNode = Yaml.toMapping "No root node found" (yamlStream.Documents.[0].RootNode)
58 |
59 | let modIndexFile = mapNode |> Yaml.getOptionalValue "modIndex" |> Yaml.toOptionalString
60 |
61 | let files = mapNode |> Yaml.getOptionalValue "files" |> Yaml.toOptionalSequence // Yaml "'Files' must be a list of files to load" |> Seq.map string |> List.ofSeq
62 | let files =
63 | match files with
64 | | None -> []
65 | | Some files -> files |> Seq.map string |> List.ofSeq
66 |
67 | let conf = {
68 | ModIndexFile= modIndexFile
69 | FilesToLoad = files
70 | AppSettings = appSettings
71 | }
72 |
73 | Some (conf)
--------------------------------------------------------------------------------
/MMManaged/paket.references:
--------------------------------------------------------------------------------
1 | MonoGame.Framework.WindowsDX
2 | YamlDotNet
--------------------------------------------------------------------------------
/MMView/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/MMView/Camera.fs:
--------------------------------------------------------------------------------
1 | // ModelMod: 3d data snapshotting & substitution program.
2 | // Copyright(C) 2015,2016 John Quigley
3 |
4 | // This program is free software : you can redistribute it and / or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 2.1 of the License, or
7 | // (at your option) any later version.
8 |
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12 | // GNU General Public License for more details.
13 |
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with this program.If not, see .
16 |
17 | namespace MeshView
18 |
19 | module Camera =
20 | open Microsoft.Xna.Framework
21 | open Microsoft.Xna.Framework.Input
22 |
23 | type CameraData(view,proj:Matrix,rot:Matrix,pos:Vector3) =
24 | member x.Rotation = rot
25 | member x.Position = pos
26 | member x.View = view
27 | member x.Projection = proj
28 |
29 | let make proj position =
30 | let defRot = Matrix.Identity
31 | let target = 10.0f * defRot.Forward
32 | let view = Matrix.CreateLookAt(position, target, defRot.Up)
33 |
34 | CameraData(view,proj,defRot,position)
35 |
36 | let update (c:CameraData) (keyState:KeyboardState) gameTime =
37 | let position = c.Position
38 | let rot = c.Rotation
39 |
40 | let moveSpeed = 0.3f;
41 | let rotSpeed = 0.02f;
42 |
43 | let move (vec:Vector3) = moveSpeed * vec
44 |
45 | let position = if (keyState.IsKeyDown(Keys.W)) then (position + move rot.Forward) else position
46 | let position = if (keyState.IsKeyDown(Keys.S)) then (position + move rot.Backward) else position
47 | let position = if (keyState.IsKeyDown(Keys.A)) then (position + move rot.Left) else position
48 | let position = if (keyState.IsKeyDown(Keys.D)) then (position + move rot.Right) else position
49 | let position = if (keyState.IsKeyDown(Keys.Q)) then (position + move rot.Up) else position
50 | let position = if (keyState.IsKeyDown(Keys.E)) then (position + move rot.Down) else position
51 |
52 | let yaw = 0.0f
53 | let pitch = 0.0f
54 | let pitch = pitch + if (keyState.IsKeyDown(Keys.I)) then rotSpeed else 0.0f
55 | let pitch = pitch + if (keyState.IsKeyDown(Keys.K)) then -rotSpeed else 0.0f
56 | let yaw = yaw + if (keyState.IsKeyDown(Keys.J)) then rotSpeed else 0.0f
57 | let yaw = yaw + if (keyState.IsKeyDown(Keys.L)) then -rotSpeed else 0.0f
58 |
59 | let rot = rot * Matrix.CreateFromAxisAngle(rot.Right, pitch);
60 | let rot = rot * Matrix.CreateFromAxisAngle(rot.Up, yaw);
61 |
62 | let target = position + rot.Forward
63 |
64 | let view = Matrix.CreateLookAt(position, target, rot.Up)
65 |
66 | new CameraData(view,c.Projection,rot,position)
--------------------------------------------------------------------------------
/MMView/Program.fs:
--------------------------------------------------------------------------------
1 | // ModelMod: 3d data snapshotting & substitution program.
2 | // Copyright(C) 2015,2016 John Quigley
3 |
4 | // This program is free software : you can redistribute it and / or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 2.1 of the License, or
7 | // (at your option) any later version.
8 |
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12 | // GNU General Public License for more details.
13 |
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with this program.If not, see .
16 |
17 | module Program
18 |
19 | []
20 | let main argv =
21 | MeshView.Main.run argv
22 | 0
23 |
24 |
25 |
--------------------------------------------------------------------------------
/MMView/paket.references:
--------------------------------------------------------------------------------
1 | MonoGame.Framework.WindowsDX
2 | YamlDotNet
--------------------------------------------------------------------------------
/ModelMod.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/ModelMod.ico
--------------------------------------------------------------------------------
/Native/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 | members = [
3 | "constant_tracking",
4 | "hook_core",
5 | "d3dx",
6 | "device_state",
7 | "dnclr",
8 | "global_state",
9 | "input",
10 | "interop",
11 | "mod_load",
12 | "mod_stats",
13 | "profiler",
14 | "shader_capture",
15 | "shared_dx",
16 | "types",
17 | "util",
18 | "hook_snapshot",
19 | #"snap_plugin",
20 | "snaplib"
21 | ]
22 | exclude=["snap_plugin"]
23 | resolver = "2"
24 |
25 | [profile.release]
26 | opt-level = 3
27 | # this controls how many crates llvm processes in parallel, reducing it might
28 | # improve run time performance, but slows down compilation.
29 | # https://doc.rust-lang.org/rustc/codegen-options/index.html
30 | codegen-units = 1
31 | panic = 'unwind'
32 |
33 | # other stuff
34 | #debug = true
35 | #rpath = false
36 | #lto = false
37 | #debug-assertions = false
38 |
--------------------------------------------------------------------------------
/Native/MMCore.code-workspace:
--------------------------------------------------------------------------------
1 | {
2 | "folders": [
3 | {
4 | "path": "..\\..\\Docs"
5 | },
6 | {
7 | "path": "hook_core"
8 | },
9 | {
10 | "path": "shared_dx"
11 | },
12 | {
13 | "path": "d3dx"
14 | },
15 | {
16 | "path": "constant_tracking"
17 | },
18 | {
19 | "path": "global_state"
20 | },
21 | {
22 | "path": "input"
23 | },
24 | {
25 | "path": "profiler"
26 | },
27 | {
28 | "path": "types"
29 | },
30 | {
31 | "path": "util"
32 | },
33 | {
34 | "path": "device_state"
35 | },
36 | {
37 | "path": "dnclr"
38 | },
39 | {
40 | "path": "mod_load"
41 | },
42 | {
43 | "path": "interop"
44 | },
45 | {
46 | "path": "snaplib"
47 | },
48 | {
49 | "path": "hook_snapshot"
50 | },
51 | {
52 | "path": "mod_stats"
53 | },
54 | {
55 | "path": "shader_capture"
56 | }
57 | ],
58 | "settings": {}
59 | }
--------------------------------------------------------------------------------
/Native/build_pgo.sh:
--------------------------------------------------------------------------------
1 | set -e
2 |
3 | toolchain=$(rustup show active-toolchain | cut -d' ' -f 1 | sed -e 's/nightly-//')
4 | echo $toolchain
5 |
6 | pgodir=$(pwd)/pgo-data
7 | rm -rf $pgodir
8 |
9 | # would be nice to try this, but it doesn't work on windows with msvc and panic=unwind
10 | # https://github.com/rust-lang/rust/issues/61002
11 | # even if don't use panic=unwind here, a bunch of crates that I depend on do use it, and
12 | # I can't turn it off there.
13 |
14 | RUSTFLAGS="-Cprofile-generate=$pgodir" \
15 | cargo build --release --target=$toolchain
16 |
17 | # would do more stuff here as described in
18 | # https://doc.rust-lang.org/rustc/profile-guided-optimization.html
19 |
--------------------------------------------------------------------------------
/Native/constant_tracking/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | [[package]]
4 | name = "constant_tracking"
5 | version = "0.1.0"
6 | dependencies = [
7 | "serde",
8 | "serde_yaml",
9 | "shared_dx",
10 | "winapi",
11 | ]
12 |
13 | [[package]]
14 | name = "dtoa"
15 | version = "0.4.6"
16 | source = "registry+https://github.com/rust-lang/crates.io-index"
17 | checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
18 |
19 | [[package]]
20 | name = "lazy_static"
21 | version = "1.4.0"
22 | source = "registry+https://github.com/rust-lang/crates.io-index"
23 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
24 |
25 | [[package]]
26 | name = "linked-hash-map"
27 | version = "0.5.3"
28 | source = "registry+https://github.com/rust-lang/crates.io-index"
29 | checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
30 |
31 | [[package]]
32 | name = "proc-macro2"
33 | version = "1.0.21"
34 | source = "registry+https://github.com/rust-lang/crates.io-index"
35 | checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c"
36 | dependencies = [
37 | "unicode-xid",
38 | ]
39 |
40 | [[package]]
41 | name = "quote"
42 | version = "1.0.7"
43 | source = "registry+https://github.com/rust-lang/crates.io-index"
44 | checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
45 | dependencies = [
46 | "proc-macro2",
47 | ]
48 |
49 | [[package]]
50 | name = "serde"
51 | version = "1.0.116"
52 | source = "registry+https://github.com/rust-lang/crates.io-index"
53 | checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5"
54 | dependencies = [
55 | "serde_derive",
56 | ]
57 |
58 | [[package]]
59 | name = "serde_derive"
60 | version = "1.0.116"
61 | source = "registry+https://github.com/rust-lang/crates.io-index"
62 | checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8"
63 | dependencies = [
64 | "proc-macro2",
65 | "quote",
66 | "syn",
67 | ]
68 |
69 | [[package]]
70 | name = "serde_yaml"
71 | version = "0.8.13"
72 | source = "registry+https://github.com/rust-lang/crates.io-index"
73 | checksum = "ae3e2dd40a7cdc18ca80db804b7f461a39bb721160a85c9a1fa30134bf3c02a5"
74 | dependencies = [
75 | "dtoa",
76 | "linked-hash-map",
77 | "serde",
78 | "yaml-rust",
79 | ]
80 |
81 | [[package]]
82 | name = "shared_dx"
83 | version = "0.1.0"
84 | dependencies = [
85 | "lazy_static",
86 | "winapi",
87 | ]
88 |
89 | [[package]]
90 | name = "syn"
91 | version = "1.0.41"
92 | source = "registry+https://github.com/rust-lang/crates.io-index"
93 | checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b"
94 | dependencies = [
95 | "proc-macro2",
96 | "quote",
97 | "unicode-xid",
98 | ]
99 |
100 | [[package]]
101 | name = "unicode-xid"
102 | version = "0.2.1"
103 | source = "registry+https://github.com/rust-lang/crates.io-index"
104 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
105 |
106 | [[package]]
107 | name = "winapi"
108 | version = "0.3.9"
109 | source = "registry+https://github.com/rust-lang/crates.io-index"
110 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
111 | dependencies = [
112 | "winapi-i686-pc-windows-gnu",
113 | "winapi-x86_64-pc-windows-gnu",
114 | ]
115 |
116 | [[package]]
117 | name = "winapi-i686-pc-windows-gnu"
118 | version = "0.4.0"
119 | source = "registry+https://github.com/rust-lang/crates.io-index"
120 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
121 |
122 | [[package]]
123 | name = "winapi-x86_64-pc-windows-gnu"
124 | version = "0.4.0"
125 | source = "registry+https://github.com/rust-lang/crates.io-index"
126 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
127 |
128 | [[package]]
129 | name = "yaml-rust"
130 | version = "0.4.4"
131 | source = "registry+https://github.com/rust-lang/crates.io-index"
132 | checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
133 | dependencies = [
134 | "linked-hash-map",
135 | ]
136 |
--------------------------------------------------------------------------------
/Native/constant_tracking/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "constant_tracking"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [target.'cfg(windows)'.dependencies]
10 | winapi = { version = "0.3", features = ["libloaderapi", "d3d9", "objidlbase",
11 | "processthreadsapi", "memoryapi", "winerror", "winuser", "winreg",
12 | "dinput"] }
13 |
14 | [dependencies]
15 | shared_dx = { path = "../shared_dx" }
16 | serde = { version = "1.0", features = ["derive"] }
17 | serde_yaml = "0.9"
18 |
--------------------------------------------------------------------------------
/Native/constant_tracking/src/lib.rs:
--------------------------------------------------------------------------------
1 | // clippy just hates what i've done here
2 | #![allow(clippy::all)]
3 |
4 | mod constant_tracking;
5 |
6 | pub use crate::constant_tracking::*;
7 |
--------------------------------------------------------------------------------
/Native/d3dx/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "d3dx"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 |
10 | [target.'cfg(windows)'.dependencies]
11 | winapi = { version = "0.3", features = ["libloaderapi", "d3d9", "objidlbase",
12 | "processthreadsapi", "memoryapi", "winerror", "winuser", "winreg",
13 | "dinput"] }
14 |
15 | [dependencies]
16 | shared_dx = { path = "../shared_dx" }
17 | util = { path = "../util" }
18 | global_state = { path = "../global_state" }
19 | types = { path = "../types" }
--------------------------------------------------------------------------------
/Native/d3dx/src/lib.rs:
--------------------------------------------------------------------------------
1 | #![allow(static_mut_refs)]
2 | extern crate util;
3 |
4 | mod d3dx;
5 | pub use crate::d3dx::*;
6 |
--------------------------------------------------------------------------------
/Native/device_state/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | [[package]]
4 | name = "device_state"
5 | version = "0.1.0"
6 | dependencies = [
7 | "shared_dx",
8 | ]
9 |
10 | [[package]]
11 | name = "lazy_static"
12 | version = "1.4.0"
13 | source = "registry+https://github.com/rust-lang/crates.io-index"
14 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
15 |
16 | [[package]]
17 | name = "shared_dx"
18 | version = "0.1.0"
19 | dependencies = [
20 | "lazy_static",
21 | "winapi",
22 | ]
23 |
24 | [[package]]
25 | name = "winapi"
26 | version = "0.3.9"
27 | source = "registry+https://github.com/rust-lang/crates.io-index"
28 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
29 | dependencies = [
30 | "winapi-i686-pc-windows-gnu",
31 | "winapi-x86_64-pc-windows-gnu",
32 | ]
33 |
34 | [[package]]
35 | name = "winapi-i686-pc-windows-gnu"
36 | version = "0.4.0"
37 | source = "registry+https://github.com/rust-lang/crates.io-index"
38 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
39 |
40 | [[package]]
41 | name = "winapi-x86_64-pc-windows-gnu"
42 | version = "0.4.0"
43 | source = "registry+https://github.com/rust-lang/crates.io-index"
44 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
45 |
--------------------------------------------------------------------------------
/Native/device_state/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "device_state"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | shared_dx = { path = "../shared_dx" }
--------------------------------------------------------------------------------
/Native/device_state/src/device_state.rs:
--------------------------------------------------------------------------------
1 | use shared_dx::types::{DeviceState, HookD3D11State, HookDeviceState};
2 | use std::{ptr::null_mut, sync::{RwLockWriteGuard, RwLockReadGuard}};
3 | use shared_dx::util::write_log_file;
4 |
5 | // At some point need to make this private and just use accessor functions (especially with locks)
6 | pub static mut DEVICE_STATE: *mut DeviceState = null_mut();
7 |
8 | /// This is primarily used by tests at the moment that need the device state. In general MM
9 | /// is not currently thread safe, as all supported games use only a single render
10 | /// thread, but that might change in the future. The perf overhead of locking inside
11 | /// draw primitive is probably too great but a thread local might be viable, however I tried
12 | /// that before and didn't like it, but maybe I was just wrong (prev commit is in
13 | /// dc46643366ba6f44306ee79448afd73aec5038aa ).
14 | /// Note: if you are using this and the log lock in a test, lock the log first ^_^
15 | pub static mut DEVICE_STATE_LOCK: std::sync::RwLock<()> = std::sync::RwLock::new(());
16 |
17 | pub fn dev_state() -> &'static mut DeviceState {
18 | unsafe {
19 | if DEVICE_STATE == null_mut() {
20 | write_log_file("accessing null device state pointer, this 'should never happen'. we gonna crash boys");
21 | panic!("Aborting because I'm about to dereference a null device state pointer.");
22 | }
23 | &mut (*DEVICE_STATE)
24 | }
25 | }
26 |
27 | /// As `dev_state()` but only returns the d3d11 state. No locking. Returns None if no state
28 | /// or current state is not d3d11.
29 | pub unsafe fn dev_state_d3d11_nolock<'a>() -> Option<&'a mut HookD3D11State> {
30 | match dev_state().hook {
31 | Some(HookDeviceState::D3D11(ref mut h)) => {
32 | Some(h)
33 | },
34 | _ => None
35 | }
36 | }
37 |
38 | // TODO11 benchmark this and use it where needed
39 | // As `dev_state()` but also returns only the d3d11 state and locks.
40 | pub unsafe fn dev_state_d3d11_write<'a>() -> Option<(RwLockWriteGuard<'a, ()>, &'a mut HookD3D11State)> {
41 | match DEVICE_STATE_LOCK.write() {
42 | Ok(lock) => {
43 | match dev_state().hook {
44 | Some(HookDeviceState::D3D11(ref mut h)) => {
45 | Some((lock,h))
46 | },
47 | _ => None
48 | }
49 | },
50 | Err(_) => {
51 | write_log_file(&format!("dev_state_d3d11_write: failed to get lock"));
52 | None
53 | }
54 | }
55 | }
56 |
57 | pub unsafe fn dev_state_d3d11_read<'a>() -> Option<(RwLockReadGuard<'a, ()>, &'a mut HookD3D11State)> {
58 | match DEVICE_STATE_LOCK.read() {
59 | Ok(lock) => {
60 | match dev_state().hook {
61 | Some(HookDeviceState::D3D11(ref mut h)) => {
62 | Some((lock,h))
63 | },
64 | _ => None
65 | }
66 | },
67 | Err(_) => {
68 | write_log_file(&format!("dev_state_d3d11_write: failed to get lock"));
69 | None
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Native/device_state/src/lib.rs:
--------------------------------------------------------------------------------
1 | #![allow(static_mut_refs)]
2 |
3 | mod device_state;
4 | pub use crate::device_state::*;
5 |
--------------------------------------------------------------------------------
/Native/dnclr/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "dnclr"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | shared_dx = { path = "../shared_dx" }
11 | util = { path = "../util" }
12 | global_state = { path = "../global_state" }
13 | types = { path = "../types" }
14 |
15 | [target.'cfg(windows)'.dependencies]
16 | winapi = { version = "0.3", features = ["libloaderapi", "d3d9", "objidlbase",
17 | "processthreadsapi", "memoryapi", "winerror", "winuser", "winreg",
18 | "dinput"] }
19 |
--------------------------------------------------------------------------------
/Native/dnclr/src/lib.rs:
--------------------------------------------------------------------------------
1 |
2 | #[macro_use]
3 | #[cfg(windows)]
4 | extern crate winapi;
5 |
6 | mod dnclr;
7 | pub use crate::dnclr::*;
--------------------------------------------------------------------------------
/Native/global_state/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "global_state"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | lazy_static = "1.1.0"
11 | fnv = "1.0.6"
12 |
13 | [target.'cfg(windows)'.dependencies]
14 | winapi = { version = "0.3", features = ["libloaderapi", "d3d9", "objidlbase",
15 | "processthreadsapi", "memoryapi", "winerror", "winuser", "winreg",
16 | "dinput"] }
17 | types = { path = "../types" }
18 | input = { path = "../input" }
19 | constant_tracking = { path = "../constant_tracking" }
20 | snaplib = { path = "../snaplib" }
21 | shared_dx = { path = "../shared_dx" }
--------------------------------------------------------------------------------
/Native/global_state/src/lib.rs:
--------------------------------------------------------------------------------
1 | #[macro_use]
2 | extern crate lazy_static;
3 |
4 | extern crate types;
5 | extern crate fnv;
6 |
7 | mod global_state;
8 | pub use crate::global_state::*;
9 |
--------------------------------------------------------------------------------
/Native/hook_core/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | /target/
3 | **/*.rs.bk
4 |
--------------------------------------------------------------------------------
/Native/hook_core/.ionide/symbolCache.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/Native/hook_core/.ionide/symbolCache.db
--------------------------------------------------------------------------------
/Native/hook_core/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | }
--------------------------------------------------------------------------------
/Native/hook_core/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "hook_core"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 | build = "build.rs"
7 |
8 | [dependencies]
9 | fnv = "1.0.6"
10 | shared_dx = { path = "../shared_dx" }
11 | profiler = { path = "../profiler" }
12 | global_state = { path = "../global_state" }
13 | util = { path = "../util" }
14 | input = { path = "../input" }
15 | constant_tracking = { path = "../constant_tracking" }
16 | d3dx = { path = "../d3dx" }
17 | types = { path = "../types" }
18 | mod_load = { path = "../mod_load" }
19 | mod_stats = { path = "../mod_stats" }
20 | device_state = { path = "../device_state" }
21 | dnclr = { path = "../dnclr" }
22 | interop = { path = "../interop" }
23 | shader_capture = { path = "../shader_capture" }
24 | snaplib = { path = "../snaplib" }
25 | hook_snapshot = { path = "../hook_snapshot" }
26 | lazy_static = "1.1.0"
27 |
28 | [target.'cfg(windows)'.dependencies]
29 | winapi = { version = "0.3", features = ["libloaderapi", "d3d9", "d3d11", "dxgi", "objidlbase",
30 | "processthreadsapi", "memoryapi", "winerror", "winuser", "winreg",
31 | "dinput", "sysinfoapi"] }
32 |
33 | [lib]
34 | crate-type = ["cdylib"]
35 |
36 | [build-dependencies]
37 | winres = "0.1"
38 | rustc_version = "0.2"
39 | chrono = "*"
40 |
41 | [package.metadata.winres]
42 | ProductName= "ModelMod"
43 | FileDescription="D3D11/9 wrapper for ModelMod"
44 | OriginalFilename = "hook_core.dll"
45 | LegalCopyright = "Copyright © 2023"
46 | ProductVersion = "1.2.0.0"
47 |
48 | [features]
49 | default = []
50 | profile = []
51 | mmdisable = []
52 |
--------------------------------------------------------------------------------
/Native/hook_core/bresh.sh:
--------------------------------------------------------------------------------
1 | # NOTE: use git bash, not WSL
2 | rustup default nightly-i686-pc-windows-msvc
3 |
4 | # if [ "$1" == "profile" ]; then
5 | # BCMD="cargo build --release --features=profile"
6 | # else
7 | # BCMD="cargo build --release"
8 | # fi
9 |
10 | # to build a submodule with a feature specific to that module, it needs to be built explicitly first.
11 | # then build everything else that doesn't use it.
12 | # example: prepend this to the build command below to build
13 | # with "noautohook":
14 | # ( cd hook_core && cargo build --release --features=noautohook ) &&
15 | # ("noautohook" is a nonexistance feature that was once going to be used for the late-init mode
16 | # but turned out to be unnecessary).
17 |
18 | # (can't specify features on the root workspace due to:
19 | # https://github.com/rust-lang/cargo/issues/4753
20 | # https://github.com/rust-lang/cargo/issues/5015
21 | #)
22 |
23 | cargo build --release && cp -v target/release/hook_core.dll ../Release/MMNative32.dll
24 |
--------------------------------------------------------------------------------
/Native/hook_core/build.rs:
--------------------------------------------------------------------------------
1 |
2 | extern crate winres;
3 | extern crate rustc_version;
4 | extern crate chrono;
5 |
6 | fn main() {
7 |
8 | use std::process::Command;
9 |
10 | if cfg!(target_os = "windows") {
11 | let res = winres::WindowsResource::new();
12 | // can't set an icon because its a DLL, but winres will still pull
13 | // values out of cargo.toml and stick them in the resource.
14 | res.compile().unwrap();
15 | }
16 |
17 | // https://stackoverflow.com/questions/43753491/include-git-commit-hash-as-string-into-rust-program
18 | let output = Command::new("git").args(["rev-parse", "HEAD"]).output().unwrap();
19 | let git_hash = String::from_utf8(output.stdout).unwrap();
20 | println!("cargo:rustc-env=GIT_HASH={}", git_hash);
21 |
22 | // build timestamp
23 | let build_ts = chrono::offset::Local::now();
24 | println!("cargo:rustc-env=BUILD_TS={}", build_ts);
25 |
26 | println!("cargo:rustc-env=RUSTCVER={}", rustc_version::version().unwrap());
27 | println!("cargo:rustc-env=RUSTCDATE={}", rustc_version::version_meta().unwrap().commit_date.unwrap());
28 | }
--------------------------------------------------------------------------------
/Native/hook_core/buildrel.sh:
--------------------------------------------------------------------------------
1 | # this used to be entirely in bash but I ported it to Fake since this didn't work on
2 | # appveyor. But then appveyor has cargo issues (it can't reliably update its index due to
3 | # some SSL issue). But I still kept the new Fake implementation
4 |
5 | # search upwards in the directory tree for the build.fsx file
6 | DIR="./"
7 | for i in {1..4}; do
8 | if [ -f "$DIR/build.fsx" ]; then
9 | break
10 | fi
11 | DIR="$DIR/.."
12 | done
13 |
14 | if [ ! -f "$DIR/build.fsx" ]; then
15 | echo "Can't find build.fsx"
16 | exit 1
17 | fi
18 |
19 | (cd $DIR && TARGET=BuildNativeOnly fsi build.fsx)
20 |
21 |
--------------------------------------------------------------------------------
/Native/hook_core/d332-sh.sh:
--------------------------------------------------------------------------------
1 | if [ "$1" == "profile" ]; then
2 | BCMD="cargo build --release --features=profile"
3 | else
4 | BCMD="cargo build --release"
5 | fi
6 |
7 | $BCMD && cp -v target/release/hook_core.dll /d/Diablo\ 3/Diablo\ III/d3d9.dll && RUST_BACKTRACE=1 /d/Diablo\ 3/Diablo\ III/Diablo\ III.exe
--------------------------------------------------------------------------------
/Native/hook_core/r2025g1.sh:
--------------------------------------------------------------------------------
1 | SPATH=$(dirname $0)
2 | . $SPATH/shutil.sh
3 | REQ=x86_64
4 | check_tc $REQ
5 |
6 | set -e
7 | # find the parent MM directory, where the symlink to the game exe should be set
8 | # (developer should manually set that up with mklink /j )
9 | MMPATH=$SPATH
10 |
11 | find_mm
12 |
13 | echo "MM: $MMPATH"
14 |
15 | # find the symlink to the exe
16 | GLINK="G2025g1"
17 |
18 | GPATH="$MMPATH/$GLINK"
19 | if [ ! -f "$GPATH" ]; then
20 | echo "Game symlink $GPATH does not exist"
21 | exit 1
22 | fi
23 |
24 | # possible features:
25 | # profile
26 | # mmdisable
27 | if [ "$1" != "" ]; then
28 | echo "Building with features: $1"
29 | BCMD="cargo build --release --features=$1"
30 | else
31 | BCMD="cargo build --release"
32 | fi
33 |
34 | echo "==> Using d3d11"
35 | DEST=$(dirname "$(readlink $GPATH)")
36 | DEST=$DEST/d3d11.dll
37 |
38 | $BCMD
39 |
40 | # this is the rust "source" target dir, not the copy dest
41 | TARGDIR="target"
42 | if [ ! -d "TARGDIR" ]; then
43 | TARGDIR="../target"
44 | fi
45 | cp -v $TARGDIR/release/hook_core.dll "$DEST"
46 | echo "press enter to run game now or ctrl-c to abort..."
47 |
48 | read $discard
49 |
50 | if [ -f "$MMPATH/g2025g1_pre.sh" ]; then
51 | set +e
52 | source "$MMPATH/g2025g1_pre.sh"
53 | if [ "$?" -ne 0 ]; then
54 | echo "pre script had error, aborting"
55 | exit 1
56 | fi
57 | echo "ran pre script"
58 | set -e
59 | fi
60 |
61 | REXE="$(readlink $GPATH)"
62 | export RUST_BACKTRACE=1 && "$REXE"
63 | echo "game has exited"
--------------------------------------------------------------------------------
/Native/hook_core/rb.sh:
--------------------------------------------------------------------------------
1 | SPATH=$(dirname $0)
2 | . $SPATH/shutil.sh
3 | REQ=x86_64
4 | check_tc $REQ
5 |
6 | # possible features:
7 | # profile
8 | # mmdisable
9 | if [ "$1" != "" ]; then
10 | echo "Building with features: $1"
11 | BCMD="cargo build --release --features=$1"
12 | else
13 | BCMD="cargo build --release"
14 | fi
15 |
16 | # NOTE: use git bash, not WSL
17 | GPATH="/f/Guild Wars 2"
18 | if [ ! -d "$GPATH" ]; then
19 | GPATH="/c/Guild Wars 2"
20 | fi
21 | if [ ! -d "$GPATH" ]; then
22 | echo "Can't find game"
23 | exit 1
24 | fi
25 |
26 | # select d3d 9 or 11 via first argument, file goes in a different place in each case
27 | if [ "$1" == "9" ]; then
28 | echo "==> Using d3d9"
29 | DEST=bin64/d3d9.dll
30 | else
31 | echo "==> Using d3d11"
32 | DEST=d3d11.dll
33 | fi
34 |
35 | $BCMD && cp -v target/release/hook_core.dll "$GPATH/$DEST" && RUST_BACKTRACE=1 "$GPATH/Gw2-64.exe"
36 |
--------------------------------------------------------------------------------
/Native/hook_core/rb32.sh:
--------------------------------------------------------------------------------
1 | SPATH=$(dirname $0)
2 | . $SPATH/shutil.sh
3 | REQ=i686
4 | check_tc $REQ
5 |
6 |
7 | if [ "$1" == "profile" ]; then
8 | BCMD="cargo build --release --features=profile"
9 | else
10 | BCMD="cargo build --release"
11 | fi
12 |
13 | $BCMD && cp -v target/release/hook_core.dll /d/Guild\ Wars\ 2/d3d9.dll && RUST_BACKTRACE=1 /d/Guild\ Wars\ 2/Gw2.exe -32
--------------------------------------------------------------------------------
/Native/hook_core/rgw1.sh:
--------------------------------------------------------------------------------
1 | SPATH=$(dirname $0)
2 | . $SPATH/shutil.sh
3 | REQ=i686
4 | check_tc $REQ
5 |
6 | if [ "$1" == "profile" ]; then
7 | BCMD="cargo build --release --features=profile"
8 | else
9 | BCMD="cargo build --release"
10 | fi
11 |
12 | # NOTE: use git bash, not WSL
13 | GPATH="/f"
14 |
15 | if [ ! -d "$GPATH" ]; then
16 | GPATH="/e"
17 | fi
18 |
19 | $BCMD && cp -v target/release/hook_core.dll $GPATH/Guild\ Wars/d3d9.dll && RUST_BACKTRACE=1 $GPATH/Guild\ Wars/Gw.exe
20 |
--------------------------------------------------------------------------------
/Native/hook_core/rme2.sh:
--------------------------------------------------------------------------------
1 | SPATH=$(dirname $0)
2 | . $SPATH/shutil.sh
3 | REQ=i686
4 | check_tc $REQ
5 |
6 | if [ "$1" == "profile" ]; then
7 | BCMD="cargo build --release --features=profile"
8 | else
9 | BCMD="cargo build --release"
10 | fi
11 |
12 | # NOTE: use git bash, not WSL
13 | GPATH="/d"
14 |
15 | if [ ! -d "$GPATH" ]; then
16 | GPATH="/e"
17 | fi
18 |
19 | GREL="Steam/steamapps/common/mass effect 2/Binaries"
20 |
21 | echo "TDIR:"
22 | set -e
23 | ls -ld "$GPATH/$GREL"
24 | #exit 1
25 | $BCMD && cp -v target/release/hook_core.dll "$GPATH/$GREL/d3d9.dll" && RUST_BACKTRACE=1 "$GPATH/$GREL/MassEffect2.exe"
26 |
--------------------------------------------------------------------------------
/Native/hook_core/rt.sh:
--------------------------------------------------------------------------------
1 | # 'cargo test' will generate an executable for the tests to run from, but won't build the dll.
2 | # we need the DLL for the managed code to integrate; it can't import symbols from an executable.
3 | # so need to 'cargo build' before running the tests to generate the dll.
4 | # any test which invokes the clr will load the dll,
5 | # which means that during tests there are two copies of the code present in the same
6 | # process, one from the test executable and one from the dll. Other than the
7 | # "duplicate globals" problem (which the code works around by passing a pointer to global
8 | # state in and out of managed code), I haven't seen other issues. but this isn't an ideal
9 | # situation.
10 | cargo build && RUST_BACKTRACE=1 cargo test -- --nocapture --test-threads=1 $1
--------------------------------------------------------------------------------
/Native/hook_core/rtl.sh:
--------------------------------------------------------------------------------
1 | # run test 10 times in a loop exit if any errors
2 | for i in {1..10}; do
3 | echo "Run $i"
4 | cargo test --release
5 | if [ $? -ne 0 ]; then
6 | echo "Test failed"
7 | exit 1
8 | fi
9 | done
10 |
--------------------------------------------------------------------------------
/Native/hook_core/shutil.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function check_tc {
4 | local REQ=$1
5 | ATC=$(rustup show active-toolchain | grep $REQ)
6 |
7 | if [ "$ATC" == "" ]; then
8 | echo "active toolchain does not contain required string $REQ"
9 | echo "switch to a toolchain that does (using 'rustup default tcname')"
10 | echo "use 'rustup show' to list toolchains"
11 | exit 1
12 | fi
13 |
14 | echo "==> USING TOOLCHAIN: $ATC"
15 | }
16 |
17 | # set MMPATH to source script dir before calling this
18 | function find_mm {
19 | MMPATH=$(realpath "$MMPATH")
20 | # Walk upward until we find "ModelMod"
21 | while [ "$MMPATH" != "/" ]; do
22 | if [ -d "$MMPATH/ModelMod" ]; then
23 | # Found it: set MMPATH to the ModelMod directory
24 | MMPATH="$MMPATH/ModelMod"
25 | echo "Found ModelMod at: $MMPATH"
26 | return
27 | fi
28 | # Move one directory up
29 | MMPATH=$(dirname "$MMPATH")
30 | done
31 |
32 | # If we exit the loop, we didn't find it
33 | echo "Error: ModelMod directory not found."
34 | exit 1
35 | }
--------------------------------------------------------------------------------
/Native/hook_core/src/hook_constants.rs:
--------------------------------------------------------------------------------
1 |
2 | // This lib is disabled for now since I don't use this.
3 | // Constants are captured in one shot during snapshot.
4 | pub use winapi::shared::d3d9::*;
5 | pub use winapi::shared::d3d9types::*;
6 | pub use winapi::shared::minwindef::*;
7 | pub use winapi::um::winnt::{HRESULT, LPCWSTR};
8 |
9 | use global_state::GLOBAL_STATE;
10 |
11 | use device_state::dev_state;
12 |
13 | pub unsafe extern "system" fn hook_set_vertex_sc_f(
14 | THIS: *mut IDirect3DDevice9,
15 | StartRegister: UINT,
16 | pConstantData: *const f32,
17 | Vector4fCount: UINT
18 | ) -> HRESULT {
19 | let hr = (dev_state().hook_direct3d9device.as_ref().unwrap().real_set_vertex_sc_f)(THIS, StartRegister, pConstantData, Vector4fCount);
20 | if hr == 0 {
21 | GLOBAL_STATE.vertex_constants.as_mut().map(|vconsts| {
22 | vconsts.floats.set(StartRegister, pConstantData, Vector4fCount);
23 | });
24 | }
25 | hr
26 | }
27 |
28 | pub unsafe extern "system" fn hook_set_vertex_sc_i(
29 | THIS: *mut IDirect3DDevice9,
30 | StartRegister: UINT,
31 | pConstantData: *const i32,
32 | Vector4iCount: UINT,
33 | ) -> HRESULT {
34 | let hr = (dev_state().hook_direct3d9device.as_ref().unwrap().real_set_vertex_sc_i)(THIS, StartRegister, pConstantData, Vector4iCount);
35 | if hr == 0 {
36 | GLOBAL_STATE.vertex_constants.as_mut().map(|vconsts| {
37 | vconsts.ints.set(StartRegister, pConstantData, Vector4iCount);
38 | });
39 | }
40 | hr
41 | }
42 |
43 | pub unsafe extern "system" fn hook_set_vertex_sc_b(
44 | THIS: *mut IDirect3DDevice9,
45 | StartRegister: UINT,
46 | pConstantData: *const BOOL,
47 | BoolCount: UINT
48 | ) -> HRESULT {
49 | let hr = (dev_state().hook_direct3d9device.as_ref().unwrap().real_set_vertex_sc_b)(THIS, StartRegister, pConstantData, BoolCount);
50 | if hr == 0 {
51 | GLOBAL_STATE.vertex_constants.as_mut().map(|vconsts| {
52 | vconsts.bools.set(StartRegister, pConstantData, BoolCount);
53 | });
54 | }
55 | hr
56 | }
57 | // pixel functions:
58 | pub unsafe extern "system" fn hook_set_pixel_sc_f(
59 | THIS: *mut IDirect3DDevice9,
60 | StartRegister: UINT,
61 | pConstantData: *const f32,
62 | Vector4fCount: UINT
63 | ) -> HRESULT {
64 | let hr = (dev_state().hook_direct3d9device.as_ref().unwrap().real_set_pixel_sc_f)(THIS, StartRegister, pConstantData, Vector4fCount);
65 | if hr == 0 {
66 | GLOBAL_STATE.pixel_constants.as_mut().map(|pconsts| {
67 | pconsts.floats.set(StartRegister, pConstantData, Vector4fCount);
68 | });
69 | }
70 | hr
71 | }
72 |
73 | pub unsafe extern "system" fn hook_set_pixel_sc_i(
74 | THIS: *mut IDirect3DDevice9,
75 | StartRegister: UINT,
76 | pConstantData: *const i32,
77 | Vector4iCount: UINT,
78 | ) -> HRESULT {
79 | let hr = (dev_state().hook_direct3d9device.as_ref().unwrap().real_set_pixel_sc_i)(THIS, StartRegister, pConstantData, Vector4iCount);
80 | if hr == 0 {
81 | GLOBAL_STATE.pixel_constants.as_mut().map(|pconsts| {
82 | pconsts.ints.set(StartRegister, pConstantData, Vector4iCount);
83 | });
84 | }
85 | hr
86 | }
87 |
88 | pub unsafe extern "system" fn hook_set_pixel_sc_b(
89 | THIS: *mut IDirect3DDevice9,
90 | StartRegister: UINT,
91 | pConstantData: *const BOOL,
92 | BoolCount: UINT
93 | ) -> HRESULT {
94 | let hr = (dev_state().hook_direct3d9device.as_ref().unwrap().real_set_pixel_sc_b)(THIS, StartRegister, pConstantData, BoolCount);
95 | if hr == 0 {
96 | GLOBAL_STATE.pixel_constants.as_mut().map(|pconsts| {
97 | pconsts.bools.set(StartRegister, pConstantData, BoolCount);
98 | });
99 | }
100 | hr
101 | }
102 |
--------------------------------------------------------------------------------
/Native/hook_core/src/lib.rs:
--------------------------------------------------------------------------------
1 | #![allow(static_mut_refs)]
2 |
3 | #![allow(non_snake_case)]
4 | // this is here to silence the spammy warnings from the COM macro definitions in dnclr.
5 | // need to turn this on periodically to find the try dead code.
6 | #![allow(dead_code)]
7 | //#![feature(test)]
8 | //extern crate test;
9 |
10 | //build.rs sets these, we log them to the logfile on startup.
11 | const RUSTCVER:&str = env!("RUSTCVER");
12 | const RUSTCDATE:&str = env!("RUSTCDATE");
13 | const GIT_HASH:&str = env!("GIT_HASH");
14 | const BUILD_TS:&str = env!("BUILD_TS");
15 |
16 | extern crate fnv;
17 |
18 | #[cfg(windows)]
19 | extern crate winapi;
20 |
21 | extern crate lazy_static;
22 |
23 | extern crate shared_dx;
24 | extern crate global_state;
25 | extern crate util;
26 | extern crate input;
27 | extern crate constant_tracking;
28 | extern crate d3dx;
29 | extern crate types;
30 |
31 | #[macro_use]
32 | extern crate profiler;
33 |
34 | mod debugmode;
35 | mod hook_render;
36 | mod hook_render_d3d11;
37 | mod input_commands;
38 | mod hook_device;
39 | //mod hook_constants;
40 | mod mod_render;
41 | mod hook_device_d3d11;
42 |
43 | pub use interop::{LogError, LogInfo, LogWarn};
44 | pub use interop::{OnInitialized, SaveTexture};
45 |
46 | pub use hook_render::Direct3DCreate9;
47 | pub use hook_render::D3DPERF_BeginEvent;
48 | pub use hook_render::D3DPERF_EndEvent;
49 | pub use hook_render::D3DPERF_SetMarker;
50 | pub use hook_render::D3DPERF_SetRegion;
51 | pub use hook_render::D3DPERF_QueryRepeatFrame;
52 | pub use hook_render::D3DPERF_SetOptions;
53 | pub use hook_render::D3DPERF_GetStatus;
54 |
--------------------------------------------------------------------------------
/Native/hook_snapshot/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "hook_snapshot"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | fnv = "1.0.6"
11 | shared_dx = { path = "../shared_dx" }
12 | profiler = { path = "../profiler" }
13 | global_state = { path = "../global_state" }
14 | util = { path = "../util" }
15 | constant_tracking = { path = "../constant_tracking" }
16 | d3dx = { path = "../d3dx" }
17 | types = { path = "../types" }
18 | device_state = { path = "../device_state" }
19 | interop = { path = "../interop" }
20 | shader_capture = { path = "../shader_capture" }
21 | snaplib = { path = "../snaplib" }
22 | #snap_plugin = { path = "../snap_plugin" }
23 | lazy_static = "1.1.0"
24 |
25 | [target.'cfg(windows)'.dependencies]
26 | winapi = { version = "0.3", features = ["libloaderapi", "d3d9", "objidlbase",
27 | "processthreadsapi", "memoryapi", "winerror", "winuser", "winreg",
28 | "dinput"] }
--------------------------------------------------------------------------------
/Native/hook_snapshot/src/lib.rs:
--------------------------------------------------------------------------------
1 | // at some point after spewing enough warnings, clippy should just say "have you considered
2 | // taking up python?"
3 | #![allow(clippy::all)]
4 |
5 | #![allow(static_mut_refs)]
6 |
7 | #![allow(non_snake_case)]
8 | mod hook_snapshot;
9 | mod snap_extdll;
10 | pub use crate::hook_snapshot::*;
11 |
12 | #[macro_use]
13 | extern crate lazy_static;
--------------------------------------------------------------------------------
/Native/hook_snapshot/src/snap_extdll.rs:
--------------------------------------------------------------------------------
1 | use snaplib::snap_config::SnapConfig;
2 | use util;
3 | use std::{self, path::{PathBuf}};
4 | use winapi::shared::minwindef::HINSTANCE;
5 | use shared_dx::{error::*, util::write_log_file};
6 |
7 | use winapi::um::winnt::LPCSTR;
8 |
9 | use crate::SNAP_CONFIG;
10 | type GetActivePlayerTransformFn = unsafe extern "system" fn() -> LPCSTR;
11 |
12 | pub struct XDLLState {
13 | pub _handle: HINSTANCE,
14 | pub GetActivePlayerTransform: GetActivePlayerTransformFn,
15 | }
16 |
17 | impl XDLLState {
18 | pub fn get_player_transform(&self) -> Result {
19 | unsafe {
20 | let xfrm = (self.GetActivePlayerTransform)();
21 | let ret = std::ffi::CStr::from_ptr(xfrm);
22 | let ret = ret.to_string_lossy();
23 | if ret.starts_with("error") {
24 | return Err(HookError::SnapshotFailed(format!("failed to get player transform: {:?}", ret)));
25 | }
26 | Ok(ret.into_owned())
27 | }
28 | }
29 | }
30 |
31 | pub static mut XDLLSTATE : Option = None;
32 |
33 | pub unsafe fn init_xdll() -> Result<()> {
34 | if XDLLSTATE.is_some() {
35 | return Ok(())
36 | }
37 | let snap_conf =
38 | match SNAP_CONFIG.read() {
39 | Err(e) => {
40 | write_log_file(&format!("failed to lock snap config: {}", e));
41 | SnapConfig::new()
42 | },
43 | Ok(c) => c.clone()
44 | };
45 | if snap_conf.extdll_path.trim().is_empty() {
46 | return Ok(())
47 | }
48 | let p = PathBuf::from(&snap_conf.extdll_path);
49 | if !p.exists() || !p.is_file() {
50 | return Err(HookError::SnapshotFailed(
51 | format!("error: snap extdll '{}' does not exist or is not a file: {:?}", &snap_conf.extdll_path, p)));
52 | }
53 |
54 | write_log_file(&format!("loading snap extdll: {}", snap_conf.extdll_path));
55 | let handle = util::load_lib(&snap_conf.extdll_path)?;
56 | //let handle = GetModuleHandleW(std::ptr::null_mut());
57 | write_log_file("loading snap extdll fns");
58 | // Note: leaks handle on error
59 | let ptransform:GetActivePlayerTransformFn = std::mem::transmute(util::get_proc_address(handle, "GetActivePlayerTransform")?);
60 | XDLLSTATE = Some(XDLLState{
61 | _handle: handle,
62 | GetActivePlayerTransform: ptransform
63 | });
64 | Ok(())
65 | }
66 |
67 | // We don't unload currently
68 | #[allow(dead_code)]
69 | unsafe fn unload_xdll() -> Result<()> {
70 | if !XDLLSTATE.is_some() {
71 | return Ok(())
72 | }
73 | let state = XDLLSTATE.take().unwrap();
74 | util::unload_lib(state._handle)?;
75 | Ok(())
76 | }
77 |
--------------------------------------------------------------------------------
/Native/input/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | [[package]]
4 | name = "fnv"
5 | version = "1.0.7"
6 | source = "registry+https://github.com/rust-lang/crates.io-index"
7 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
8 |
9 | [[package]]
10 | name = "input"
11 | version = "0.1.0"
12 | dependencies = [
13 | "fnv",
14 | "profiler",
15 | "shared_dx",
16 | "util",
17 | "winapi",
18 | ]
19 |
20 | [[package]]
21 | name = "lazy_static"
22 | version = "1.4.0"
23 | source = "registry+https://github.com/rust-lang/crates.io-index"
24 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
25 |
26 | [[package]]
27 | name = "profiler"
28 | version = "0.1.0"
29 | dependencies = [
30 | "shared_dx",
31 | ]
32 |
33 | [[package]]
34 | name = "shared_dx"
35 | version = "0.1.0"
36 | dependencies = [
37 | "lazy_static",
38 | "winapi",
39 | ]
40 |
41 | [[package]]
42 | name = "util"
43 | version = "0.1.0"
44 | dependencies = [
45 | "shared_dx",
46 | "winapi",
47 | ]
48 |
49 | [[package]]
50 | name = "winapi"
51 | version = "0.3.9"
52 | source = "registry+https://github.com/rust-lang/crates.io-index"
53 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
54 | dependencies = [
55 | "winapi-i686-pc-windows-gnu",
56 | "winapi-x86_64-pc-windows-gnu",
57 | ]
58 |
59 | [[package]]
60 | name = "winapi-i686-pc-windows-gnu"
61 | version = "0.4.0"
62 | source = "registry+https://github.com/rust-lang/crates.io-index"
63 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
64 |
65 | [[package]]
66 | name = "winapi-x86_64-pc-windows-gnu"
67 | version = "0.4.0"
68 | source = "registry+https://github.com/rust-lang/crates.io-index"
69 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
70 |
--------------------------------------------------------------------------------
/Native/input/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "input"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | fnv = "1.0.6"
11 | util = { path = "../util" }
12 | shared_dx = { path = "../shared_dx" }
13 | profiler = { path = "../profiler" }
14 |
15 | [target.'cfg(windows)'.dependencies]
16 | winapi = { version = "0.3", features = ["libloaderapi", "d3d9", "objidlbase",
17 | "processthreadsapi", "memoryapi", "winerror", "winuser", "winreg",
18 | "dinput"] }
--------------------------------------------------------------------------------
/Native/input/src/lib.rs:
--------------------------------------------------------------------------------
1 | #[macro_use]
2 | #[cfg(windows)]
3 | extern crate winapi;
4 |
5 | extern crate util;
6 |
7 | //#[macro_use]
8 | extern crate profiler;
9 |
10 | mod input;
11 | pub use crate::input::*;
12 |
--------------------------------------------------------------------------------
/Native/interop/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "interop"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | lazy_static = "1.1.0"
11 | shared_dx = { path = "../shared_dx" }
12 | global_state = { path = "../global_state" }
13 | util = { path = "../util" }
14 | d3dx = { path = "../d3dx" }
15 | types = { path = "../types" }
16 |
--------------------------------------------------------------------------------
/Native/interop/src/lib.rs:
--------------------------------------------------------------------------------
1 |
2 | #[macro_use]
3 | extern crate lazy_static;
4 |
5 | mod interop;
6 | pub use crate::interop::*;
7 |
--------------------------------------------------------------------------------
/Native/mod_load/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "mod_load"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [target.'cfg(windows)'.dependencies]
10 | winapi = { version = "0.3", features = ["libloaderapi", "d3d9", "objidlbase",
11 | "processthreadsapi", "memoryapi", "winerror", "winuser", "winreg",
12 | "dinput"] }
13 |
14 | [features]
15 | default = []
16 | tangent_debug = ["glam"]
17 |
18 | [dependencies]
19 | fnv = "1.0.6"
20 | shared_dx = { path = "../shared_dx" }
21 | util = { path = "../util" }
22 | global_state = { path = "../global_state" }
23 | types = { path = "../types" }
24 | d3dx = { path = "../d3dx" }
25 | device_state = { path = "../device_state" }
26 | glam = { version = "*", optional = true }
--------------------------------------------------------------------------------
/Native/mod_load/src/lib.rs:
--------------------------------------------------------------------------------
1 | // wow you think maybe there is some undocumented unsafe stuff going on here?
2 | #![allow(clippy::missing_safety_doc)]
3 |
4 | #![allow(static_mut_refs)]
5 |
6 | mod mod_load;
7 | mod mod_vector;
8 | mod data_encoding;
9 | pub use crate::mod_load::*;
--------------------------------------------------------------------------------
/Native/mod_stats/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "mod_stats"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | fnv = "1.0.6"
10 | shared_dx = { path = "../shared_dx" }
11 | util = { path = "../util" }
12 | global_state = { path = "../global_state" }
13 | types = { path = "../types" }
--------------------------------------------------------------------------------
/Native/mod_stats/src/lib.rs:
--------------------------------------------------------------------------------
1 | // this is allowed in other crates because the issue pervades the code at the moment,
2 | // but this crate only generates one warning so leave it enabled here so that
3 | // I don't completely forget about it
4 | //#![allow(static_mut_refs)]
5 |
6 | pub mod mod_stats;
7 |
--------------------------------------------------------------------------------
/Native/profiler/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | [[package]]
4 | name = "lazy_static"
5 | version = "1.4.0"
6 | source = "registry+https://github.com/rust-lang/crates.io-index"
7 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
8 |
9 | [[package]]
10 | name = "profiler"
11 | version = "0.1.0"
12 | dependencies = [
13 | "shared_dx",
14 | ]
15 |
16 | [[package]]
17 | name = "shared_dx"
18 | version = "0.1.0"
19 | dependencies = [
20 | "lazy_static",
21 | "winapi",
22 | ]
23 |
24 | [[package]]
25 | name = "winapi"
26 | version = "0.3.9"
27 | source = "registry+https://github.com/rust-lang/crates.io-index"
28 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
29 | dependencies = [
30 | "winapi-i686-pc-windows-gnu",
31 | "winapi-x86_64-pc-windows-gnu",
32 | ]
33 |
34 | [[package]]
35 | name = "winapi-i686-pc-windows-gnu"
36 | version = "0.4.0"
37 | source = "registry+https://github.com/rust-lang/crates.io-index"
38 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
39 |
40 | [[package]]
41 | name = "winapi-x86_64-pc-windows-gnu"
42 | version = "0.4.0"
43 | source = "registry+https://github.com/rust-lang/crates.io-index"
44 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
45 |
--------------------------------------------------------------------------------
/Native/profiler/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "profiler"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | shared_dx = { path = "../shared_dx" }
11 | fnv = "1.0.6"
12 |
13 | [features]
14 | default = []
15 | profile = []
--------------------------------------------------------------------------------
/Native/profiler/src/lib.rs:
--------------------------------------------------------------------------------
1 | mod profile;
2 |
3 | //pub use profile::*;
4 |
--------------------------------------------------------------------------------
/Native/resetlinks.sh:
--------------------------------------------------------------------------------
1 | set -e
2 |
3 | # WARNING: this script can remove existing Rust "target" directories and files inside.
4 | # but it shouldn't make any changes unless you run it with DRY_RUN=0 in the environment.
5 | # NOTE: since moving to a workspace this script is less useful since the
6 | # workspace uses a single target directory (at the root). Notably the
7 | # detection scheme used by this script (looking for lib.rs) does not locate
8 | # that workspace-specific "target" directory, so that symlink (if needed)
9 | # must be created manually.
10 |
11 | # I use symlinks for the target directories to redirect Rust output files to a filesystem with
12 | # better performance and more importantly a lot more space. These symlinks are windows
13 | # "Junction" files created with the mklink tool. The related script `setjunc.sh` is used to
14 | # make the links. The output is kind of spammy because a new windows shell is launched for
15 | # each dir.
16 |
17 | # This script resets all the symlinks to point at new targets. It also removes existing target
18 | # directories (if any) that have not been symlinked. The files in those directories are
19 | # destroyed, so cargo must be re-run to rebuild the rust code.
20 |
21 | DIRS=$(ls)
22 | WD=$(pwd)
23 |
24 | for d in $DIRS; do
25 | libsrc="$WD/$d/src/lib.rs"
26 | if [ -f "$libsrc" ]; then
27 | echo "Checking lib $WD/$d"
28 | if [ -d "$WD/$d/target" ]; then
29 | if [ "$DRY_RUN" == "0" ]; then
30 | cd $WD/$d
31 | echo "Recreating link in $WD/$d"
32 | rm -rf ./target
33 | sh ../setjunc.sh ModelMod
34 | fi
35 | ls "$WD/$d/target/"
36 | if [ -L "$WD/$d/target" ]; then
37 | echo " Would reset existing link: $WD/$d/target"
38 | elif [ -d "$WD/$d/target" ]; then
39 | echo " Would REMOVE existing dir and files and recreate link: $WD/$d/target"
40 | else
41 | echo " Would create new link: $WD/$d/target"
42 | fi
43 |
44 | fi
45 | fi
46 | done
47 |
48 | if [ "$DRY_RUN" != "0" ]; then
49 | echo "dry run complete, rerun with DRY_RUN=0 to make changes"
50 | fi
--------------------------------------------------------------------------------
/Native/setjunc.sh:
--------------------------------------------------------------------------------
1 | set -e
2 |
3 | rustoutroot=$1
4 |
5 | thistarget="./target"
6 |
7 | if [[ -L "$thistarget" && -d "$thistarget" ]]; then
8 | echo "$thistarget is already a symlink"
9 | exit 0
10 | fi
11 |
12 | rustout=""
13 | if [ -d "/f" ]; then
14 | rustout="/f/RustOut"
15 | elif [ -d "/e" ]; then
16 | rustout="/e/RustOut"
17 | fi
18 |
19 | if [ "$rustoutroot" != "" ]; then
20 | rustout="$rustout/$rustoutroot"
21 | fi
22 |
23 | if [ "$rustout" == "" ]; then
24 | echo "Can't find suitable rust out directory"
25 | exit 1
26 | fi
27 |
28 | dir=$(basename $(pwd))
29 | rustout="$rustout/$dir"
30 | echo $rustout
31 |
32 | if [ ! -d $rustout ]; then
33 | mkdir -p $rustout
34 | fi
35 |
36 | target="$rustout/target"
37 | if [ ! -d $target ]; then
38 | if [ -d "./target" ]; then
39 | echo "moving target: ./target => $target"
40 | mv "./target" $target
41 | fi
42 | fi
43 |
44 | if [ ! -d "$target" ]; then
45 | mkdir -p $target
46 | fi
47 |
48 | dir=$(pwd)
49 | thistarget="$dir/target"
50 | # cygpath will fail if the dir doesn't exist, so make it
51 | made_it=false
52 | if [ ! -d $thistarget ]; then
53 | touch $thistarget
54 | made_it=true
55 | fi
56 | dos_thistarget=$(cygpath -d $thistarget)
57 | if [ "$made_it" == "true" ]; then
58 | rm $thistarget
59 | fi
60 |
61 | dos_desttarget=$(cygpath -d $target)
62 | echo "mklink /j $dos_thistarget $dos_desttarget" > mklink.bat
63 | cmd "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | shared_dx = { path = "../shared_dx" }
11 | global_state = { path = "../global_state" }
12 | types = { path = "../types" }
13 |
14 | [target.'cfg(windows)'.dependencies]
15 | winapi = { version = "0.3", features = ["libloaderapi", "d3d9", "objidlbase",
16 | "processthreadsapi", "memoryapi", "winerror", "winuser", "winreg",
17 | "dinput"] }
--------------------------------------------------------------------------------
/Native/shader_capture/src/lib.rs:
--------------------------------------------------------------------------------
1 | #![allow(static_mut_refs)]
2 |
3 | mod shader_capture;
4 |
5 | pub use crate::shader_capture::*;
6 |
--------------------------------------------------------------------------------
/Native/shared_dx/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | [[package]]
4 | name = "lazy_static"
5 | version = "1.4.0"
6 | source = "registry+https://github.com/rust-lang/crates.io-index"
7 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
8 |
9 | [[package]]
10 | name = "shared_dx"
11 | version = "0.1.0"
12 | dependencies = [
13 | "lazy_static",
14 | "winapi",
15 | ]
16 |
17 | [[package]]
18 | name = "winapi"
19 | version = "0.3.8"
20 | source = "registry+https://github.com/rust-lang/crates.io-index"
21 | checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
22 | dependencies = [
23 | "winapi-i686-pc-windows-gnu",
24 | "winapi-x86_64-pc-windows-gnu",
25 | ]
26 |
27 | [[package]]
28 | name = "winapi-i686-pc-windows-gnu"
29 | version = "0.4.0"
30 | source = "registry+https://github.com/rust-lang/crates.io-index"
31 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
32 |
33 | [[package]]
34 | name = "winapi-x86_64-pc-windows-gnu"
35 | version = "0.4.0"
36 | source = "registry+https://github.com/rust-lang/crates.io-index"
37 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
38 |
--------------------------------------------------------------------------------
/Native/shared_dx/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "shared_dx"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [target.'cfg(windows)'.dependencies]
10 | winapi = { version = "0.3", features = ["libloaderapi", "d3d9", "d3d11", "objidlbase",
11 | "processthreadsapi", "memoryapi", "winerror", "winuser", "winreg",
12 | "dinput"] }
13 |
14 | [dependencies]
15 | lazy_static = "*"
16 | fnv = "1.0.6"
--------------------------------------------------------------------------------
/Native/shared_dx/src/defs_dx9.rs:
--------------------------------------------------------------------------------
1 | use winapi::ctypes::c_void;
2 | pub use winapi::shared::d3d9::*;
3 | pub use winapi::shared::d3d9types::*;
4 | pub use winapi::shared::minwindef::*;
5 | pub use winapi::shared::windef::{HWND, RECT};
6 | pub use winapi::shared::winerror::{E_FAIL, S_OK};
7 | use winapi::um::unknwnbase::{IUnknown, IUnknownVtbl};
8 | use winapi::um::wingdi::RGNDATA;
9 | pub use winapi::um::winnt::{HRESULT, LPCWSTR};
10 |
11 | use crate::impl_release_drop;
12 |
13 | pub type D3DXSaveTextureToFileWFn = unsafe extern "system" fn(
14 | path: LPCWSTR,
15 | fileformat: i32,
16 | src_texture: *mut IDirect3DBaseTexture9,
17 | src_palette: *mut c_void,
18 | ) -> HRESULT;
19 |
20 | RIDL!(#[uuid(0x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58, 0xd, 0x98, 0x9c, 0x3a, 0x1, 0x2)]
21 | interface ID3DXBuffer(ID3DXBufferVtbl): IUnknown(IUnknownVtbl) {
22 | fn GetBufferPointer() -> LPVOID,
23 | fn GetBufferSize() -> DWORD,
24 | });
25 |
26 | impl_release_drop!(ID3DXBuffer);
27 |
28 | pub type D3DXDisassembleShaderFn = unsafe extern "system" fn(
29 | pShader: *const DWORD,
30 | EnableColorCode: BOOL,
31 | pComments: *mut c_void,
32 | ppDisassembly: *mut *mut ID3DXBuffer,
33 | ) -> HRESULT;
34 |
35 | pub type CreateDeviceFn = unsafe extern "system" fn(
36 | THIS: *mut IDirect3D9,
37 | Adapter: UINT,
38 | DeviceType: D3DDEVTYPE,
39 | hFocusWindow: HWND,
40 | BehaviorFlags: DWORD,
41 | pPresentationParameters: *mut D3DPRESENT_PARAMETERS,
42 | ppReturnedDeviceInterface: *mut *mut IDirect3DDevice9,
43 | ) -> HRESULT;
44 | pub type DrawIndexedPrimitiveFn = unsafe extern "system" fn(
45 | THIS: *mut IDirect3DDevice9,
46 | arg1: D3DPRIMITIVETYPE,
47 | BaseVertexIndex: INT,
48 | MinVertexIndex: UINT,
49 | NumVertices: UINT,
50 | startIndex: UINT,
51 | primCount: UINT,
52 | ) -> HRESULT;
53 | pub type BeginSceneFn = unsafe extern "system" fn(THIS: *mut IDirect3DDevice9) -> HRESULT;
54 | pub type IUnknownReleaseFn = unsafe extern "system" fn(THIS: *mut IUnknown) -> ULONG;
55 | pub type PresentFn = unsafe extern "system" fn(
56 | THIS: *mut IDirect3DDevice9,
57 | pSourceRect: *const RECT,
58 | pDestRect: *const RECT,
59 | hDestWindowOverride: HWND,
60 | pDirtyRegion: *const RGNDATA,
61 | ) -> HRESULT;
62 | pub type SetTextureFn = unsafe extern "system" fn(
63 | THIS: *mut IDirect3DDevice9,
64 | Stage: DWORD,
65 | pTexture: *mut IDirect3DBaseTexture9,
66 | ) -> HRESULT;
67 |
68 | // shader constants
69 | pub type SetVertexShaderConstantFFn = unsafe extern "system" fn(
70 | THIS: *mut IDirect3DDevice9,
71 | StartRegister: UINT,
72 | pConstantData: *const f32,
73 | Vector4fCount: UINT,
74 | ) -> HRESULT;
75 |
76 | pub type SetVertexShaderConstantBFn = unsafe extern "system" fn(
77 | THIS: *mut IDirect3DDevice9,
78 | StartRegister: UINT,
79 | pConstantData: *const BOOL,
80 | BoolCount: UINT,
81 | ) -> HRESULT;
82 |
83 | pub type SetVertexShaderConstantIFn = unsafe extern "system" fn(
84 | THIS: *mut IDirect3DDevice9,
85 | StartRegister: UINT,
86 | pConstantData: *const i32,
87 | Vector4iCount: UINT,
88 | ) -> HRESULT;
89 |
90 | pub type SetPixelShaderConstantFFn = unsafe extern "system" fn(
91 | THIS: *mut IDirect3DDevice9,
92 | StartRegister: UINT,
93 | pConstantData: *const f32,
94 | Vector4fCount: UINT,
95 | ) -> HRESULT;
96 |
97 | pub type SetPixelShaderConstantBFn = unsafe extern "system" fn(
98 | THIS: *mut IDirect3DDevice9,
99 | StartRegister: UINT,
100 | pConstantData: *const BOOL,
101 | BoolCount: UINT,
102 | ) -> HRESULT;
103 |
104 | pub type SetPixelShaderConstantIFn = unsafe extern "system" fn(
105 | THIS: *mut IDirect3DDevice9,
106 | StartRegister: UINT,
107 | pConstantData: *const i32,
108 | Vector4iCount: UINT,
109 | ) -> HRESULT;
110 |
111 | impl_release_drop!(IDirect3DBaseTexture9);
112 | impl_release_drop!(IDirect3DVertexDeclaration9);
113 | impl_release_drop!(IDirect3DIndexBuffer9);
114 | impl_release_drop!(IDirect3DPixelShader9);
115 | impl_release_drop!(IDirect3DVertexShader9);
--------------------------------------------------------------------------------
/Native/shared_dx/src/error.rs:
--------------------------------------------------------------------------------
1 | use std::{ffi::OsString, num::TryFromIntError};
2 |
3 | #[derive(Debug)]
4 | pub enum HookError {
5 | ProtectFailed,
6 | LoadLibFailed(String),
7 | GetProcAddressFailed(String),
8 | CLRInitFailed(String),
9 | NulError(std::ffi::NulError),
10 | BadStateError(String),
11 | GlobalStateCopyFailed,
12 | Direct3D9InstanceNotFound,
13 | CreateDeviceFailed(i32),
14 | ConfReadFailed(String),
15 | NoRegistryKey(String),
16 | FailedToConvertString(OsString),
17 | WinApiError(String),
18 | ModuleNameError(String),
19 | UnableToLocatedManagedDLL(String),
20 | D3D9HookFailed,
21 | D3D9DeviceHookFailed,
22 | GlobalLockError,
23 | IOError(std::io::Error),
24 | DInputCreateFailed(String),
25 | DInputError(String),
26 | TimeConversionError(std::time::SystemTimeError),
27 | CStrConvertFailed(std::str::Utf8Error),
28 | ConversionFailed(String),
29 | SnapshotFailed(String),
30 | CaptureFailed(String),
31 | SnapshotPluginError(String),
32 | MeshUpdateFailed(String),
33 | NoShader(),
34 | SerdeError(String),
35 | D3D11DeviceHookFailed(String),
36 | D3D11NoContext,
37 | D3D11Unsupported(String),
38 | }
39 |
40 | impl std::convert::From for HookError {
41 | fn from(error: std::ffi::NulError) -> Self {
42 | HookError::NulError(error)
43 | }
44 | }
45 |
46 | impl std::convert::From for HookError {
47 | fn from(error: std::ffi::OsString) -> Self {
48 | HookError::FailedToConvertString(error)
49 | }
50 | }
51 |
52 | impl std::convert::From for HookError {
53 | fn from(error: std::io::Error) -> Self {
54 | HookError::IOError(error)
55 | }
56 | }
57 |
58 | impl std::convert::From for HookError {
59 | fn from(error: std::time::SystemTimeError) -> Self {
60 | HookError::TimeConversionError(error)
61 | }
62 | }
63 |
64 | impl std::convert::From for HookError {
65 | fn from(error: std::str::Utf8Error) -> Self {
66 | HookError::CStrConvertFailed(error)
67 | }
68 | }
69 |
70 | impl From for HookError {
71 | fn from(error: TryFromIntError) -> Self {
72 | HookError::ConversionFailed(format!("Failed to convert int: {}", error))
73 | }
74 | }
75 |
76 | pub type Result = std::result::Result;
77 |
--------------------------------------------------------------------------------
/Native/shared_dx/src/lib.rs:
--------------------------------------------------------------------------------
1 | /*!
2 | * Contains type declarations for DX11 and DX9.
3 | */
4 | #![allow(non_snake_case)]
5 |
6 | //#[macro_use]
7 | #[cfg(windows)]
8 | #[macro_use]
9 | extern crate winapi;
10 |
11 | #[macro_use]
12 | extern crate lazy_static;
13 |
14 | pub mod defs_dx11;
15 | pub mod types_dx11;
16 | pub mod defs_dx9;
17 | pub mod types_dx9;
18 | pub mod error;
19 | pub mod state;
20 | pub mod util;
21 | pub mod types;
22 |
23 | /// Contains DX11 render state
24 | pub mod dx11rs;
--------------------------------------------------------------------------------
/Native/shared_dx/src/state.rs:
--------------------------------------------------------------------------------
1 | // pub trait ImplDeviceState {
2 |
3 | // }
4 |
5 | // pub struct HookState {
6 |
7 | // }
8 | // pub static mut GLOBAL_STATE: HookState = HookState {};
9 |
--------------------------------------------------------------------------------
/Native/shared_dx/src/types_dx11.rs:
--------------------------------------------------------------------------------
1 | use crate::defs_dx11::*;
2 |
3 | pub struct HookDirect3D11Device {
4 | pub real_create_buffer: CreateBufferFn,
5 | pub real_create_texture_2d: CreateTexture2DFn,
6 | pub real_query_interface: QueryInterfaceFn,
7 | pub real_create_input_layout: CreateInputLayoutFn
8 | }
9 | pub struct HookDirect3D11Context {
10 | pub real_query_interface: QueryInterfaceFn,
11 | pub real_release: IUnknownReleaseFn,
12 | pub real_vs_setconstantbuffers: VSSetConstantBuffersFn,
13 | pub real_draw: DrawFn,
14 | pub real_draw_auto: DrawAutoFn,
15 | pub real_draw_indexed: DrawIndexedFn,
16 | pub real_draw_instanced: DrawInstancedFn,
17 | pub real_draw_indexed_instanced: DrawIndexedInstancedFn,
18 | pub real_draw_instanced_indirect: DrawInstancedIndirectFn,
19 | pub real_draw_indexed_instanced_indirect: DrawIndexedInstancedIndirectFn,
20 | pub real_ia_set_vertex_buffers: IASetVertexBuffersFn,
21 | pub real_ia_set_input_layout: IASetInputLayoutFn,
22 | pub real_ia_set_primitive_topology: IASetPrimitiveTopologyFn,
23 | pub real_ps_set_shader_resources: PSSetShaderResourcesFn,
24 | }
25 | pub struct HookDirect3D11 {
26 | pub context: HookDirect3D11Context,
27 | }
--------------------------------------------------------------------------------
/Native/shared_dx/src/types_dx9.rs:
--------------------------------------------------------------------------------
1 | use crate::defs_dx9::*;
2 |
3 | pub struct HookDirect3D9 {
4 | pub real_create_device: CreateDeviceFn,
5 | }
6 |
7 | #[derive(Clone)]
8 | pub struct HookDirect3D9Device {
9 | pub real_draw_indexed_primitive: DrawIndexedPrimitiveFn,
10 | //pub real_begin_scene: BeginSceneFn,
11 | pub real_present: PresentFn,
12 | pub real_release: IUnknownReleaseFn,
13 | pub real_set_texture: SetTextureFn,
14 | pub ref_count: ULONG,
15 | // shader constants
16 | pub real_set_vertex_sc_f: SetVertexShaderConstantFFn,
17 | pub real_set_vertex_sc_i: SetVertexShaderConstantIFn,
18 | pub real_set_vertex_sc_b: SetVertexShaderConstantBFn,
19 | pub real_set_pixel_sc_f: SetPixelShaderConstantFFn,
20 | pub real_set_pixel_sc_i: SetPixelShaderConstantIFn,
21 | pub real_set_pixel_sc_b: SetPixelShaderConstantBFn,
22 | }
23 |
24 | impl HookDirect3D9Device {
25 | pub fn new(
26 | real_draw_indexed_primitive: DrawIndexedPrimitiveFn,
27 | //real_begin_scene: BeginSceneFn,
28 | real_present: PresentFn,
29 | real_release: IUnknownReleaseFn,
30 | real_set_texture: SetTextureFn,
31 | real_set_vertex_sc_f: SetVertexShaderConstantFFn,
32 | real_set_vertex_sc_i: SetVertexShaderConstantIFn,
33 | real_set_vertex_sc_b: SetVertexShaderConstantBFn,
34 | real_set_pixel_sc_f: SetPixelShaderConstantFFn,
35 | real_set_pixel_sc_i: SetPixelShaderConstantIFn,
36 | real_set_pixel_sc_b: SetPixelShaderConstantBFn,
37 | ) -> HookDirect3D9Device {
38 | HookDirect3D9Device {
39 | real_draw_indexed_primitive,
40 | //real_begin_scene: real_begin_scene,
41 | real_release,
42 | real_present,
43 | real_set_texture,
44 | real_set_vertex_sc_f,
45 | real_set_vertex_sc_i,
46 | real_set_vertex_sc_b,
47 | real_set_pixel_sc_f,
48 | real_set_pixel_sc_i,
49 | real_set_pixel_sc_b,
50 |
51 | ref_count: 0,
52 | }
53 | }
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/Native/snap_plugin/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "snap_plugin"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | shared_dx = { path = "../shared_dx" }
11 | util = { path = "../util" }
12 | snaplib = { path = "../snaplib" }
--------------------------------------------------------------------------------
/Native/snap_plugin/src/lib.rs:
--------------------------------------------------------------------------------
1 | mod snap_plugin;
2 | pub use snap_plugin::*;
--------------------------------------------------------------------------------
/Native/snap_plugin/src/snap_plugin.rs:
--------------------------------------------------------------------------------
1 | use shared_dx::defs::LPDIRECT3DDEVICE9;
2 | use shared_dx::error::Result;
3 | use shared_dx::error::HookError;
4 | use snaplib::anim_frame::AnimFrame;
5 |
6 | use util;
7 |
8 | const PLUGIN_VER:u32 = 1;
9 |
10 | #[repr(C)] pub struct FrameCaptureState { private: [u8; 0] }
11 |
12 | #[repr(C)]
13 | #[derive(Debug)]
14 | pub enum PluginError {
15 | FailedToCaptureState(String),
16 | FailedToProcessState(String),
17 | }
18 |
19 | impl std::convert::From for HookError {
20 | fn from(error: PluginError) -> Self {
21 | HookError::SnapshotPluginError(format!("{:?}", error))
22 | }
23 | }
24 |
25 | pub type GetVersionFn = extern "C" fn () -> u32;
26 | pub type InitFn = extern "C" fn () -> std::result::Result<(), PluginError>;
27 | pub type AnimFrameCaptureFn = extern "C" fn (device: LPDIRECT3DDEVICE9) -> std::result::Result<*mut FrameCaptureState, PluginError>;
28 | pub type AnimFrameProcessFn = extern "C" fn (cap_state: *mut FrameCaptureState, frame: *mut AnimFrame, fsize:u32) -> std::result::Result<(), PluginError>;
29 |
30 | pub struct SnapPlugin {
31 | capture_fn:AnimFrameCaptureFn,
32 | process_fn:AnimFrameProcessFn,
33 | }
34 | impl SnapPlugin {
35 | fn anim_frame_capture(&mut self, device: LPDIRECT3DDEVICE9) -> Result<*mut FrameCaptureState> {
36 | let res = unsafe { (self.capture_fn)(device) }?;
37 | Ok(res)
38 | }
39 | fn anim_frame_process(&mut self, cap_state: *mut FrameCaptureState, frame: &mut AnimFrame) -> Result<()> {
40 | let fsize:u32 = std::mem::size_of::() as u32;
41 | let res = unsafe { (self.process_fn)(cap_state, frame, fsize) } ?;
42 | Ok(res)
43 | }
44 | }
45 | pub fn load(path:&str) -> Result {
46 | let h = util::load_lib(path)?;
47 |
48 | let load = || {
49 | unsafe {
50 | let getver:GetVersionFn = std::mem::transmute(util::get_proc_address(h, "get_version")?);
51 | let ver = getver();
52 | if ver != PLUGIN_VER {
53 | return Err(HookError::SnapshotFailed(format!("Can't load plugin {}: has old version {}, we need {}", path, ver, PLUGIN_VER)));
54 | }
55 | // all functions must be available before we call init
56 | let capture_fn:AnimFrameCaptureFn = std::mem::transmute(util::get_proc_address(h, "anim_frame_capture")?);
57 | let process_fn:AnimFrameProcessFn = std::mem::transmute(util::get_proc_address(h, "anim_frame_process")?);
58 |
59 | let init:InitFn = std::mem::transmute(util::get_proc_address(h, "init")?);
60 | init()?;
61 | Ok(SnapPlugin{
62 | capture_fn,
63 | process_fn,
64 | })
65 | }
66 | };
67 |
68 | let res = load();
69 | if res.is_err() {
70 | util::unload_lib(h)?;
71 | }
72 | res
73 | }
--------------------------------------------------------------------------------
/Native/snaplib/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "snaplib"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | shared_dx = { path = "../shared_dx" }
11 | serde = { version = "1.0", features = ["derive"] }
12 | serde_yaml = "0.9"
13 | bincode = "1.3.1"
14 | anyhow = "*"
15 | constant_tracking = { path = "../constant_tracking" }
16 |
17 | [target.'cfg(windows)'.dependencies]
18 | winapi = { version = "0.3", features = ["libloaderapi", "d3d9", "objidlbase",
19 | "processthreadsapi", "memoryapi", "winerror", "winuser", "winreg",
20 | "dinput"] }
--------------------------------------------------------------------------------
/Native/snaplib/src/anim_snap_state.rs:
--------------------------------------------------------------------------------
1 | use shared_dx::defs_dx9::UINT;
2 | use std::time::SystemTime;
3 | use shared_dx::error::Result;
4 |
5 | use constant_tracking;
6 | pub struct AnimConstants {
7 | pub snapped_at: SystemTime,
8 | pub prim_count: UINT,
9 | pub vert_count: UINT,
10 | pub constants: constant_tracking::ConstantGroup,
11 | pub sequence: usize,
12 | pub frame: u64,
13 | pub capture_count: u32,
14 | pub player_transform: Result,
15 | pub snap_on_count: u32,
16 | // currently these matrices are not captured because they are identity
17 | // worldmat: D3DMATRIX,
18 | // viewmat: D3DMATRIX,
19 | // projmat: D3DMATRIX,
20 | }
21 | use std::collections::{HashSet,HashMap}; // TODO: make sure i'm not using the slow hash function version of these
22 | pub struct AnimSnapState {
23 | pub sequence_vconstants:Vec,
24 | pub expected_primverts: HashSet<(UINT,UINT)>,
25 | pub seen_primverts: HashSet<(UINT,UINT)>,
26 | pub capture_count_this_frame: HashMap<(UINT,UINT), u32>,
27 | pub seen_all: bool,
28 | pub next_vconst_idx: usize,
29 | pub sequence_start_time: SystemTime,
30 | pub curr_frame: u64,
31 | pub start_frame: u64,
32 | pub snap_dir: String,
33 | }
34 |
--------------------------------------------------------------------------------
/Native/snaplib/src/lib.rs:
--------------------------------------------------------------------------------
1 | extern crate serde;
2 | extern crate serde_yaml;
3 |
4 | pub mod anim_snap_state;
5 | pub mod anim_frame;
6 | pub mod snap_config;
7 |
--------------------------------------------------------------------------------
/Native/test_e2e/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "test_e2e"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | lazy_static = "1.1.0"
11 | hook_core = { path = "../hook_core" }
12 |
13 | [target.'cfg(windows)'.dependencies]
14 | winapi = { version = "0.3", features = ["libloaderapi", "d3d9", "objidlbase",
15 | "processthreadsapi", "memoryapi", "winerror", "winuser", "winreg",
16 | "dinput"] }
--------------------------------------------------------------------------------
/Native/test_e2e/src/lib.rs:
--------------------------------------------------------------------------------
1 |
2 | #[macro_use]
3 | extern crate lazy_static;
4 |
5 | mod test_e2e;
--------------------------------------------------------------------------------
/Native/types/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | [[package]]
4 | name = "lazy_static"
5 | version = "1.4.0"
6 | source = "registry+https://github.com/rust-lang/crates.io-index"
7 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
8 |
9 | [[package]]
10 | name = "shared_dx"
11 | version = "0.1.0"
12 | dependencies = [
13 | "lazy_static",
14 | "winapi",
15 | ]
16 |
17 | [[package]]
18 | name = "types"
19 | version = "0.1.0"
20 | dependencies = [
21 | "shared_dx",
22 | "winapi",
23 | ]
24 |
25 | [[package]]
26 | name = "winapi"
27 | version = "0.3.9"
28 | source = "registry+https://github.com/rust-lang/crates.io-index"
29 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
30 | dependencies = [
31 | "winapi-i686-pc-windows-gnu",
32 | "winapi-x86_64-pc-windows-gnu",
33 | ]
34 |
35 | [[package]]
36 | name = "winapi-i686-pc-windows-gnu"
37 | version = "0.4.0"
38 | source = "registry+https://github.com/rust-lang/crates.io-index"
39 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
40 |
41 | [[package]]
42 | name = "winapi-x86_64-pc-windows-gnu"
43 | version = "0.4.0"
44 | source = "registry+https://github.com/rust-lang/crates.io-index"
45 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
46 |
--------------------------------------------------------------------------------
/Native/types/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "types"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [target.'cfg(windows)'.dependencies]
10 | winapi = { version = "0.3", features = ["libloaderapi", "d3d9", "objidlbase",
11 | "processthreadsapi", "memoryapi", "winerror", "winuser", "winreg",
12 | "dinput"] }
13 |
14 | [dependencies]
15 | shared_dx = { path = "../shared_dx" }
--------------------------------------------------------------------------------
/Native/types/src/d3ddata.rs:
--------------------------------------------------------------------------------
1 |
2 | use winapi::shared::d3d9::*;
3 | use winapi::um::d3d11::{ID3D11Buffer, ID3D11InputLayout, ID3D11Texture2D, ID3D11Resource, ID3D11ShaderResourceView};
4 |
5 | pub struct ModD3DData9 {
6 | pub vb: *mut IDirect3DVertexBuffer9,
7 | pub decl: *mut IDirect3DVertexDeclaration9,
8 | pub textures: [LPDIRECT3DTEXTURE9; 4],
9 | }
10 |
11 | impl ModD3DData9 {
12 | pub fn new() -> Self {
13 | use std::ptr::null_mut;
14 |
15 | Self {
16 | vb: null_mut(),
17 | decl: null_mut(),
18 | textures: [null_mut(); 4],
19 | }
20 | }
21 |
22 | pub unsafe fn release(&mut self) {
23 | if !self.vb.is_null() {
24 | (*self.vb).Release();
25 | self.vb = std::ptr::null_mut();
26 | }
27 | if !self.decl.is_null() {
28 | (*self.decl).Release();
29 | self.decl = std::ptr::null_mut();
30 | }
31 | for tex in self.textures.iter_mut() {
32 | if !tex.is_null() {
33 | let btex = *tex as *mut IDirect3DBaseTexture9;
34 | (*btex).Release();
35 | *tex = std::ptr::null_mut();
36 | }
37 | }
38 | }
39 | }
40 |
41 | pub struct ModD3DData11 {
42 | pub vb: *mut ID3D11Buffer,
43 | pub vlayout: *mut ID3D11InputLayout,
44 | pub textures: [*mut ID3D11Texture2D; 4],
45 | pub has_textures: bool,
46 | pub srvs: [*mut ID3D11ShaderResourceView; 4],
47 | pub vert_size:u32,
48 | pub vert_count:u32,
49 | }
50 |
51 | impl ModD3DData11 {
52 | pub fn new() -> Self {
53 | use std::ptr::null_mut;
54 |
55 | Self {
56 | vb: null_mut(),
57 | vlayout: null_mut(),
58 | textures: [null_mut(); 4],
59 | has_textures: false,
60 | srvs: [null_mut(); 4],
61 | vert_size: 0,
62 | vert_count: 0,
63 | }
64 | }
65 | /// Create a new ModD3DData11 with the given layout. AddRef is not called on the layout.
66 | pub fn with_layout(layout: *mut ID3D11InputLayout) -> Self {
67 | use std::ptr::null_mut;
68 |
69 | Self {
70 | vb: null_mut(),
71 | vlayout: layout,
72 | textures: [null_mut(); 4],
73 | has_textures: false,
74 | srvs: [null_mut(); 4],
75 | vert_size: 0,
76 | vert_count: 0,
77 | }
78 | }
79 |
80 | pub fn release(&mut self) {
81 | unsafe {
82 | if !self.vb.is_null() {
83 | (*self.vb).Release();
84 | self.vb = std::ptr::null_mut();
85 | }
86 | if !self.vlayout.is_null() {
87 | (*self.vlayout).Release();
88 | self.vlayout = std::ptr::null_mut();
89 | }
90 | for srv in self.srvs.iter_mut() {
91 | if !srv.is_null() {
92 | let bsrv = *srv as *mut ID3D11Resource;
93 | (*bsrv).Release();
94 | *srv = std::ptr::null_mut();
95 | }
96 | }
97 | for tex in self.textures.iter_mut() {
98 | if !tex.is_null() {
99 | let btex = *tex as *mut ID3D11Resource;
100 | (*btex).Release();
101 | *tex = std::ptr::null_mut();
102 | }
103 | }
104 | }
105 | }
106 | }
107 |
108 | /// Container for D3D resources of a mod.
109 | pub enum ModD3DData {
110 | D3D9(ModD3DData9),
111 | D3D11(ModD3DData11),
112 | }
113 |
114 | impl ModD3DData {
115 | /// Release the resource owned by this mod. Safe to call if they are null.
116 | /// Sets own fields to null after release, so they can't be released more than once
117 | /// by this function.
118 | pub unsafe fn release(&mut self) {
119 | match self {
120 | ModD3DData::D3D9(d) => d.release(),
121 | ModD3DData::D3D11(d) => d.release(),
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/Native/types/src/d3dx.rs:
--------------------------------------------------------------------------------
1 | #![allow(non_snake_case)]
2 | use winapi::{shared::{d3d9::*, dxgiformat::DXGI_FORMAT}, um::d3d11::{ID3D11Device, ID3D11Resource, ID3D11DeviceContext}, ctypes::c_void};
3 | //use winapi::shared::d3d9types::*;
4 | use shared_dx::defs_dx9::*;
5 |
6 | pub type D3DXCreateTextureFromFileWFn = unsafe extern "system" fn(
7 | pDevice: LPDIRECT3DDEVICE9,
8 | pSrcFile: LPCWSTR,
9 | ppTexture: *mut LPDIRECT3DTEXTURE9,
10 | ) -> HRESULT;
11 |
12 | pub struct D3DX9Fn {
13 | pub D3DXSaveTextureToFileW: D3DXSaveTextureToFileWFn,
14 | pub D3DXCreateTextureFromFileW: D3DXCreateTextureFromFileWFn,
15 | pub D3DXDisassembleShader: D3DXDisassembleShaderFn,
16 | }
17 |
18 | pub type D3DX11CreateTextureFromFileWFn = unsafe extern "system" fn(
19 | pDevice: *mut ID3D11Device,
20 | pSrcFile: LPCWSTR,
21 | pLoadInfo: *const c_void,
22 | pPump: *const c_void,
23 | ppTexture: *mut *mut ID3D11Resource,
24 | pHResult: *mut HRESULT,
25 | ) -> HRESULT;
26 |
27 | pub type D3DX11SaveTextureToFileWFn = unsafe extern "system" fn(
28 | pContext: *mut ID3D11DeviceContext,
29 | pSrcResource: *mut ID3D11Resource,
30 | DestFormat: DXGI_FORMAT,
31 | pDestFile: LPCWSTR,
32 | ) -> HRESULT;
33 |
34 | pub struct D3DX11Fn {
35 | pub D3DX11SaveTextureToFileW: D3DX11SaveTextureToFileWFn,
36 | pub D3DX11CreateTextureFromFileW: D3DX11CreateTextureFromFileWFn,
37 | //pub D3DX11DisassembleShader: D3DX11DisassembleShaderFn,
38 | }
39 |
40 | pub enum D3DXFn {
41 | DX9(D3DX9Fn),
42 | DX11(D3DX11Fn),
43 | }
--------------------------------------------------------------------------------
/Native/types/src/lib.rs:
--------------------------------------------------------------------------------
1 | pub mod interop;
2 | pub mod native_mod;
3 | pub mod d3dx;
4 | pub mod d3ddata;
5 |
6 | pub use shared_dx::types::TexPtr;
--------------------------------------------------------------------------------
/Native/types/src/native_mod.rs:
--------------------------------------------------------------------------------
1 | use crate::{interop::ModData};
2 | pub use crate::d3ddata::ModD3DData;
3 |
4 | pub enum ModD3DState {
5 | Unloaded,
6 | /// The mod data is partially available. Used for DX11 before where we need a place to
7 | /// store the input layout prior to obtaining the rest of the data.
8 | Partial(ModD3DData),
9 | Loaded(ModD3DData)
10 | }
11 |
12 | impl ModD3DState {
13 | /// Change the state from partial to loaded. If the current state is not partial, this is a no-op.
14 | pub fn set_loaded(&mut self) {
15 | use crate::native_mod::ModD3DState::Unloaded;
16 | use crate::native_mod::ModD3DState::Loaded;
17 |
18 | if let ModD3DState::Partial(_d3d_data) = self {
19 | let prev = std::mem::replace(self, Unloaded);
20 | if let ModD3DState::Partial(d3d_data) = prev {
21 | *self = Loaded(d3d_data);
22 | }
23 | }
24 | }
25 |
26 | pub fn is_loaded(&self) -> bool {
27 | use crate::native_mod::ModD3DState::Loaded;
28 | match self {
29 | Loaded(_) => true,
30 | _ => false,
31 | }
32 | }
33 | }
34 |
35 | pub struct NativeModData {
36 | pub midx: i32,
37 | pub mod_data: ModData,
38 | pub d3d_data: ModD3DState,
39 | pub is_parent: bool,
40 | pub parent_mod_names: Vec,
41 | pub last_frame_render: u64,
42 | pub name: String,
43 | pub fill_attempts: u32,
44 | }
45 |
46 | pub const MAX_RECENT_RENDER_USAGE_THRESH:u64 = 500;
47 | pub const MAX_RECENT_RENDER_PARENT_THRESH:u64 = 150;
48 |
49 | impl NativeModData {
50 | pub fn new() -> Self {
51 | Self {
52 | midx: -1,
53 | mod_data: ModData::new(),
54 | d3d_data: ModD3DState::Unloaded,
55 | is_parent: false,
56 | parent_mod_names: vec![],
57 | last_frame_render: 0,
58 | name: "".to_owned(),
59 | fill_attempts: 0,
60 | }
61 | }
62 | pub fn mod_key(vert_count: u32, prim_count: u32) -> u32 {
63 | //https://en.wikipedia.org/wiki/Pairing_function#Cantor_pairing_function
64 | ((vert_count + prim_count) * (vert_count + prim_count + 1) / 2) + prim_count
65 | }
66 | /// True if mod has been used (rendered) recently, as in the past few seconds. This activity
67 | /// window is signficantly longer than that of `recently_rendered` so it can be used by
68 | /// processes that update less frequently.
69 | pub fn recently_used(&self, curr_frame_num:u64) -> bool {
70 | if self.last_frame_render > curr_frame_num {
71 | // we rendered in the future, so I guess that is recent?
72 | return true;
73 | }
74 | curr_frame_num - self.last_frame_render <= MAX_RECENT_RENDER_USAGE_THRESH
75 | }
76 | /// True if mod has been rendered in the last MAX_RECENT_RENDER_PARENT_THRESH frames.
77 | /// Used for parent mod selection (when a mod with a parent becomes active or goes inactive,
78 | /// this amount of time passes before children are hidden or visible). This window needs to be
79 | /// short enough to avoid visual artifacts, but long enough that renderers who don't have a
80 | /// good idea of the framerate (dx11 currently) have updated the frame count.
81 | pub fn recently_rendered(&self, curr_frame_num:u64) -> bool {
82 | if self.last_frame_render > curr_frame_num {
83 | // we rendered in the future, so I guess that is recent?
84 | return true;
85 | }
86 | curr_frame_num - self.last_frame_render <= MAX_RECENT_RENDER_PARENT_THRESH
87 | }
88 | /// Utility function to split a potentially or'ed list of parents into individual strings
89 | pub fn split_parent_string(pstr:&str) -> Vec {
90 | pstr.trim().split(" or ").map(|p| p.trim()).filter(|p| !p.is_empty()).map(|p| p.to_owned()).collect()
91 | }
92 | }
93 |
94 |
--------------------------------------------------------------------------------
/Native/util/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | [[package]]
4 | name = "lazy_static"
5 | version = "1.4.0"
6 | source = "registry+https://github.com/rust-lang/crates.io-index"
7 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
8 |
9 | [[package]]
10 | name = "shared_dx"
11 | version = "0.1.0"
12 | dependencies = [
13 | "lazy_static",
14 | "winapi",
15 | ]
16 |
17 | [[package]]
18 | name = "util"
19 | version = "0.1.0"
20 | dependencies = [
21 | "shared_dx",
22 | "winapi",
23 | ]
24 |
25 | [[package]]
26 | name = "winapi"
27 | version = "0.3.9"
28 | source = "registry+https://github.com/rust-lang/crates.io-index"
29 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
30 | dependencies = [
31 | "winapi-i686-pc-windows-gnu",
32 | "winapi-x86_64-pc-windows-gnu",
33 | ]
34 |
35 | [[package]]
36 | name = "winapi-i686-pc-windows-gnu"
37 | version = "0.4.0"
38 | source = "registry+https://github.com/rust-lang/crates.io-index"
39 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
40 |
41 | [[package]]
42 | name = "winapi-x86_64-pc-windows-gnu"
43 | version = "0.4.0"
44 | source = "registry+https://github.com/rust-lang/crates.io-index"
45 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
46 |
--------------------------------------------------------------------------------
/Native/util/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "util"
3 | version = "0.1.0"
4 | authors = ["John Quigley "]
5 | edition = "2021"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [features]
10 | ci = []
11 |
12 | [target.'cfg(windows)'.dependencies]
13 | winapi = { version = "0.3", features = ["libloaderapi", "d3d9", "d3d11", "objidlbase",
14 | "processthreadsapi", "memoryapi", "winerror", "winuser", "winreg",
15 | "dinput"] }
16 | shared_dx = { path = "../shared_dx" }
17 | chrono = "*"
18 | aho-corasick = "0.7.20"
--------------------------------------------------------------------------------
/Native/util/src/lib.rs:
--------------------------------------------------------------------------------
1 | #![allow(clippy::not_unsafe_ptr_arg_deref)]
2 |
3 | extern crate shared_dx;
4 |
5 | mod util;
6 | pub use crate::util::*;
7 |
--------------------------------------------------------------------------------
/SnapshotProfiles/SnapshotProfiles.yaml:
--------------------------------------------------------------------------------
1 | # this file should always contain "Profile1" at a minimum.
2 |
3 | Profile1:
4 | pos: ["rot x 90", "rot y 180", "scale 0.1"]
5 | uv: ["flip y"]
6 | Profile2:
7 | pos: ["rot x 90", "rot z 180", "scale 0.1"]
8 | uv: ["flip y"]
9 | Profile3:
10 | pos: ["rot x 90", "rot z 180", "scale 5.0"]
11 | uv: ["flip y"]
12 |
--------------------------------------------------------------------------------
/StartupApp/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/StartupApp/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace System
2 | open System.Reflection
3 | open System.Runtime.InteropServices
4 |
5 | []
6 | []
7 | []
8 | []
9 | []
10 | []
11 | do ()
12 |
13 | module internal AssemblyVersionInformation =
14 | let [] Version = "1.2.0.0"
15 |
--------------------------------------------------------------------------------
/StartupApp/ModelMod.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/StartupApp/ModelMod.ico
--------------------------------------------------------------------------------
/StartupApp/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Diagnostics;
4 |
5 | namespace StartupApp
6 | {
7 | static class Program
8 | {
9 | // The sole purpose of this app is to have a "ModelMod.exe" file that we can stick
10 | // in the root folder so that the user doesn't have to go into "Bin" and randomly
11 | // click executables there. Obviously an installer would be another way to
12 | // handle this, but installers are generally yucky (especially ones that
13 | // require effing elevated privileges) and I'm too lazy to make one.
14 | // This is written in CS so that we don't need an Fsharp.Core outside the bin folder.
15 | [STAThread]
16 | static void Main()
17 | {
18 | String[] paths = { @".", @".\Bin" };
19 | String target = "MMLaunch.exe";
20 |
21 | String found = null;
22 |
23 | foreach (String p in paths) {
24 | var path = Path.Combine(p, target);
25 | if (File.Exists(path))
26 | {
27 | found = path;
28 | break;
29 | }
30 | }
31 |
32 | if (found != null)
33 | {
34 | var proc = new Process();
35 | proc.StartInfo.UseShellExecute = false;
36 | proc.StartInfo.FileName = found;
37 | proc.StartInfo.WorkingDirectory = Path.GetDirectoryName(found);
38 | proc.Start();
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/StartupApp/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("StartupApp")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("StartupApp")]
13 | [assembly: AssemblyCopyright("Copyright © 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("9baa0a1c-8ed3-45d8-9c0a-897096177cc1")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/StartupApp/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace StartupApp.Properties
12 | {
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// Returns the cached ResourceManager instance used by this class.
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("StartupApp.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// Overrides the current thread's CurrentUICulture property for all
56 | /// resource lookups using this strongly typed resource class.
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/StartupApp/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace StartupApp.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/StartupApp/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/StartupApp/StartupApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {9BAA0A1C-8ED3-45D8-9C0A-897096177CC1}
8 | WinExe
9 | Properties
10 | StartupApp
11 | ModelMod
12 | v4.5.2
13 | 512
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 | ModelMod.ico
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | ResXFileCodeGenerator
48 | Resources.Designer.cs
49 | Designer
50 |
51 |
52 | True
53 | Resources.resx
54 |
55 |
56 | SettingsSingleFileGenerator
57 | Settings.Designer.cs
58 |
59 |
60 | True
61 | Settings.settings
62 | True
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
79 |
--------------------------------------------------------------------------------
/StartupApp/StartupApp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.23107.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StartupApp", "StartupApp.csproj", "{9BAA0A1C-8ED3-45D8-9C0A-897096177CC1}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {9BAA0A1C-8ED3-45D8-9C0A-897096177CC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {9BAA0A1C-8ED3-45D8-9C0A-897096177CC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {9BAA0A1C-8ED3-45D8-9C0A-897096177CC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {9BAA0A1C-8ED3-45D8-9C0A-897096177CC1}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/Test.MMManaged/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Test.MMManaged/Program.fs:
--------------------------------------------------------------------------------
1 | // Usually these tests are run using the NUnit Test Adapter for visual studio (free extension).
2 | // I haven't set them up to run outside of VS.
3 | module Tests
4 |
--------------------------------------------------------------------------------
/Test.MMManaged/TestMesh.fs:
--------------------------------------------------------------------------------
1 | module TestMesh
2 |
3 | open NUnit.Framework
4 | open System.IO
5 |
6 | open ModelMod
7 | open ModelMod.CoreTypes
8 |
9 | let monolith =
10 | let mpath = Path.Combine(Util.TestDataDir,"monolithref.mmobj")
11 | MeshUtil.readFrom(mpath,CoreTypes.GPUReplacement,CoreTypes.DefaultReadFlags)
12 |
13 | open MonoGameHelpers
14 |
15 | []
16 | let ``Mesh: mono game helpers``() =
17 | Assert.AreEqual(500us, floatToHalfUint16(halfUint16ToFloat(500us)), "float conversion failed")
18 |
19 | []
20 | let ``Mesh: write``() =
21 | let objPath = Path.Combine(Util.TestDataDir, "monolith.TestWrite.mmobj")
22 | let mtlPath = Path.Combine(Util.TestDataDir, "monolith.TestWrite.mtl")
23 | if File.Exists objPath then File.Delete objPath
24 | if File.Exists mtlPath then File.Delete mtlPath
25 |
26 | // fake some data
27 | let posTransforms = [|"scale 2"|]
28 | let uvTransforms = [| "flip x" |]
29 | let tex0 = "dummy.dds"
30 | let monolith = {
31 | monolith with
32 | AppliedPositionTransforms = posTransforms
33 | AppliedUVTransforms = uvTransforms
34 | Tex0Path = tex0
35 | }
36 | MeshUtil.writeObj monolith objPath
37 |
38 | let monolith = MeshUtil.readFrom(objPath,CoreTypes.GPUReplacement,CoreTypes.DefaultReadFlags)
39 |
40 | Assert.AreEqual (monolith.Positions.Length, 8, sprintf "incorrect pos count: %A" monolith)
41 | Assert.AreEqual (monolith.Normals.Length, 8, sprintf "incorrect nrm count: %A" monolith)
42 | Assert.AreEqual (monolith.UVs.Length, 3, sprintf "incorrect uv count: %A" monolith)
43 | Assert.AreEqual (monolith.Triangles.Length, 12, sprintf "incorrect uv count: %A" monolith)
44 | Assert.AreEqual (monolith.AppliedPositionTransforms, posTransforms, sprintf "incorrect pos transforms: %A" monolith)
45 | Assert.AreEqual (monolith.AppliedUVTransforms, uvTransforms, sprintf "incorrect uv transforms: %A" monolith)
46 | // tex0 path will NOT currently be read in - it comes from yaml. this is "by design"
47 | Assert.AreEqual (monolith.Tex0Path, "", sprintf "incorrect tex0 path: %A" monolith)
48 |
49 | // check some stuff textually
50 | let checkHasLine (text:string[]) (x:string) =
51 | let found = text |> Array.tryFind (fun s -> s.Trim() = x.Trim() )
52 | match found with
53 | | None -> failwithf "line '%A' not found in text" x
54 | | Some s -> ()
55 |
56 | let objHasLine = checkHasLine (File.ReadAllLines(objPath))
57 | let mtlHasLine = checkHasLine (File.ReadAllLines(mtlPath))
58 |
59 | objHasLine "mtllib monolith.TestWrite.mtl"
60 | mtlHasLine "map_Kd dummy.dds"
61 |
--------------------------------------------------------------------------------
/Test.MMManaged/TestMeshTransform.fs:
--------------------------------------------------------------------------------
1 | module TestMeshTransform
2 |
3 | open NUnit.Framework
4 | open System.IO
5 |
6 |
7 | open ModelMod
8 | open ModelMod.CoreTypes
9 |
10 | let vecEq = Util.veqEqEpsilon 0.000001f
11 |
12 | let monolith =
13 | let mpath = Path.Combine(Util.TestDataDir,"monolithref.mmobj")
14 | MeshUtil.readFrom(mpath,CoreTypes.GPUReplacement,CoreTypes.DefaultReadFlags)
15 |
16 | []
17 | let ``MeshTransform: basic rotation``() =
18 | let v = new Vec3F(0.f,1.f,0.f)
19 | let res = MeshTransform.rotX false 90.f v
20 | let ex = Vec3F(0.f, 0.f, 1.f)
21 | Assert.IsTrue (vecEq res ex, sprintf "rotX: %A %A" res ex)
22 |
23 | []
24 | let ``MeshTransform: go ape with the monolith``() =
25 | // this test is too big, but it does exercise the majority of the transforming code, at least
26 | let nm = monolith |> MeshTransform.applyMeshTransforms [|"rot x 90"; "rot z 45"; "scale 0.5"|] [||]
27 |
28 | // for visual debugging:
29 | //MeshUtil.WriteObj nm (Path.Combine(Util.TestDataDir, "monolith.OUT.mmobj"))
30 |
31 | // check first few positions
32 | let checkPos p1 ep1 msg =
33 | Assert.IsTrue (vecEq p1 ep1, sprintf "%s: got: %A; expected: %A" msg p1 ep1)
34 |
35 | checkPos nm.Positions.[0] (Vec3F(1.414214f,1.414214f,0.f)) "mismatch on pos 0"
36 | checkPos nm.Positions.[1] (Vec3F(1.06066f,1.767767f,0.f)) "mismatch on pos 1"
37 | checkPos nm.Positions.[2] (Vec3F(-0.3535534f,0.3535534f,0.f)) "mismatch on pos 2"
38 | checkPos nm.Positions.[3] (Vec3F(0.f,0.f,0.f)) "mismatch on pos 3"
39 |
40 |
41 |
--------------------------------------------------------------------------------
/Test.MMManaged/TestModDB.fs:
--------------------------------------------------------------------------------
1 | module TestModDB
2 |
3 | open NUnit.Framework
4 | open System.IO
5 | open System.Reflection
6 |
7 | open ModelMod
8 | open ModelMod.CoreTypes
9 |
10 | []
11 | let ``ModDB: load mod db``() =
12 | let mpath = Path.Combine(Util.TestDataDir, "ModIndex.yaml")
13 | let mdb =
14 | ModDB.loadModDB
15 | ({
16 | StartConf.Conf.ModIndexFile = Some(mpath)
17 | FilesToLoad = []
18 | AppSettings = None
19 | }, None)
20 |
21 | Assert.AreEqual (mdb.Mods.Length, 2, sprintf "incorrect number of mods: %A" mdb.Mods)
22 | Assert.AreEqual (mdb.References.Length, 1, sprintf "incorrect number of references: %A" mdb.References)
23 | Assert.AreEqual (mdb.MeshRelations.Length, 1, sprintf "incorrect number of meshrels: %A" mdb.MeshRelations)
24 |
25 | // check ref
26 | let () =
27 | let mref = List.head mdb.References
28 | Assert.AreEqual (mref.Name, "MonolithRef", sprintf "wrong ref name: %A" mref)
29 | // check ref mesh, a few properties at least
30 | let refMesh = mref.Mesh.Value
31 | Assert.AreEqual (refMesh.Positions.Length, 8, sprintf "wrong ref mesh vert count: %A" refMesh)
32 | Assert.AreEqual (refMesh.Triangles.Length, 12, sprintf "wrong ref mesh prim count: %A" refMesh)
33 |
34 | // check mod
35 | let () =
36 | let mmod = List.item 0 mdb.Mods
37 | let mref = List.head mdb.References
38 | let refMesh = mref.Mesh.Value
39 |
40 | Assert.AreEqual (mmod.Name, "MonolithMod", sprintf "wrong mod name: %A" mmod)
41 | Assert.AreEqual (mmod.RefName, Some("MonolithRef"), sprintf "wrong mod ref name: %A" mmod)
42 | Assert.AreEqual (mmod.Ref, Some(mref), sprintf "wrong mod ref: %A" mmod)
43 | Assert.IsTrue (mmod.Mesh <> None, sprintf "wrong mod mesh: %A" mmod)
44 | let attributes = {
45 | DeletedGeometry = []
46 | }
47 | Assert.AreEqual (mmod.Attributes, attributes, sprintf "wrong mod attributes: expected %A, got %A" attributes mmod.Attributes)
48 |
49 | // check mod mesh
50 | let modMesh = Option.get mmod.Mesh
51 | let modMesh = modMesh.Value
52 | Assert.AreEqual (modMesh.Positions.Length, 24, sprintf "wrong ref mesh vert count: %A" refMesh)
53 | Assert.AreEqual (modMesh.Triangles.Length, 36, sprintf "wrong ref mesh prim count: %A" refMesh)
54 |
55 | // check deletion mod
56 | let () =
57 | let dmod = List.item 1 mdb.Mods
58 | let delGeometry = [ { PrimCount = 100; VertCount = 200 }; { PrimCount = 150; VertCount = 300 }; ]
59 | let attributes = {
60 | DeletedGeometry = delGeometry
61 | }
62 | Assert.AreEqual (dmod.Name, "DelMod", sprintf "wrong mod name: %A" dmod)
63 | Assert.AreEqual (dmod.RefName, None, sprintf "wrong mod ref name: %A" dmod)
64 | Assert.AreEqual (dmod.Ref, None, sprintf "wrong mod ref: %A" dmod)
65 | Assert.AreEqual (dmod.Mesh, None, sprintf "wrong mod mesh: %A" dmod)
66 | Assert.AreEqual (dmod.Attributes, attributes, sprintf "wrong mod attributes: expected %A, got %A" attributes dmod.Attributes)
67 |
68 | // should be two deletion mods in the database, one for each prim/vert pair. leave further checking for the interop test
69 | Assert.AreEqual (mdb.DeletionMods.Length, 2, sprintf "wrong del mod count: %A" mdb.DeletionMods)
70 |
71 | ()
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/Test.MMManaged/TestYaml.fs:
--------------------------------------------------------------------------------
1 | module TestYaml
2 |
3 | open NUnit.Framework
4 | open System.IO
5 | open System.Reflection
6 |
7 | open ModelMod
8 |
9 | let loadTestDoc() =
10 | let ydocs = Yaml.load (Path.Combine(Util.TestDataDir, "Test.yaml"))
11 | Assert.AreEqual (ydocs.Count, 1, sprintf "incorrect number of yaml documents: %A" ydocs)
12 | let doc = ydocs.Item(0)
13 | let mapNode = Yaml.toMapping "root is not a mapping node" doc.RootNode
14 | mapNode
15 |
16 | []
17 | let ``Yaml: module functions``() =
18 | let checkFails (x:System.Lazy<'a>) (msg:string) =
19 | try
20 | x.Value |> ignore
21 | failwith msg
22 | with
23 | | _ -> ()
24 |
25 | let mapNode = loadTestDoc()
26 |
27 | // toString
28 | let s = mapNode |> Yaml.getValue "Something" |> Yaml.toString
29 | Assert.AreEqual (s, "Somewhere", sprintf "incorrect string: %A" s)
30 | checkFails (lazy (mapNode |> Yaml.getValue "Mapping" |> Yaml.toString)) "should have thrown on Mapping field"
31 |
32 | // toOptionalString
33 | let s = mapNode |> Yaml.getOptionalValue "Something" |> Yaml.toOptionalString
34 | Assert.AreEqual (Option.get s, "Somewhere", sprintf "incorrect string: %A" s)
35 | let s = mapNode |> Yaml.getOptionalValue "Missing" |> Yaml.toOptionalString
36 | Assert.AreEqual (s, None, sprintf "incorrect string: %A" s)
37 |
38 | // toInt
39 | let s = mapNode |> Yaml.getValue "Int" |> Yaml.toInt
40 | Assert.AreEqual (s, 47, sprintf "incorrect int: %A" s)
41 | checkFails (lazy (mapNode |> Yaml.getValue "Something" |> Yaml.toInt)) "should have thrown on Something field"
42 |
43 | // toBool
44 | let s = mapNode |> Yaml.getOptionalValue "bool" |> Yaml.toBool false
45 | Assert.AreEqual (s, true, sprintf "incorrect bool: %A" s)
46 | let s = mapNode |> Yaml.getOptionalValue "missing" |> Yaml.toBool true
47 | Assert.AreEqual (s, true, sprintf "incorrect bool: %A" s)
48 |
49 | // sequence
50 | let s = mapNode |> Yaml.getValue "Sequence" |> Yaml.toSequence "expected a sequence" |> Seq.map Yaml.toInt |> List.ofSeq
51 | Assert.AreEqual (s, [1;2;3;4;5], sprintf "incorrect sequence: %A" s)
52 | checkFails (lazy (mapNode |> Yaml.getValue "Mapping" |> Yaml.toSequence "expected a sequence")) "should have thrown on Mapping field"
53 |
54 | // mapping
55 | let _ =
56 | let mapNode = mapNode |> Yaml.getValue "Mapping" |> Yaml.toMapping "a mapping is required"
57 |
58 | let s = mapNode |> Yaml.toMapping "Mapping"
59 | let aval = s |> Yaml.getValue "a" |> Yaml.toInt
60 | Assert.AreEqual (aval, 1, sprintf "incorrect value for a: %A" aval)
61 | let bval = s |> Yaml.getValue "b" |> Yaml.toInt
62 | Assert.AreEqual (bval, 2, sprintf "incorrect value for b: %A" bval)
63 |
64 | checkFails (lazy (mapNode |> Yaml.getValue "Something" |> Yaml.toMapping "a mapping is required")) "should have thrown on Something field"
65 | ()
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/Test.MMManaged/Util.fs:
--------------------------------------------------------------------------------
1 | module Util
2 |
3 | open System
4 | open System.Reflection
5 | open System.IO
6 |
7 | open ModelMod.CoreTypes
8 |
9 | let veqEqEpsilon (ep:float32) (v1:Vec3F) (v2:Vec3F) =
10 | let dx = Math.Abs(v1.X - v2.X)
11 | let dy = Math.Abs(v1.Y - v2.Y)
12 | let dz = Math.Abs(v1.Z - v2.Z)
13 | dx < ep && dy < ep && dz < ep
14 |
15 | let TestDataDir =
16 | let asmPath = Assembly.GetExecutingAssembly().CodeBase.Replace("file:///","")
17 |
18 | let paths = [ @"..\..\TestData"; @"..\TestData"; "@\..\..\..\..\..\TestData" ]
19 |
20 | let paths = paths |> List.map (fun p -> Path.GetFullPath(Path.Combine(asmPath,p)))
21 |
22 | let found =
23 | paths |> List.tryPick (fun p ->
24 | if Directory.Exists p then
25 | Some(p)
26 | else
27 | None
28 | )
29 |
30 | match found with
31 | | None -> failwithf "Failed to locate test data directory, searched: %A" paths
32 | | Some path -> path
33 |
--------------------------------------------------------------------------------
/Test.MMManaged/paket.references:
--------------------------------------------------------------------------------
1 | FsUnit
2 | MonoGame.Framework.WindowsDX
3 | NUnit
--------------------------------------------------------------------------------
/Test.ManagedLaunch/Program.fs:
--------------------------------------------------------------------------------
1 | open System
2 | open ModelMod
3 |
4 | (*
5 | This is intended to be a stub/test launcher for the managed assembly library, used for
6 | development only.
7 |
8 | It illustrates how the native code is expected to initialize the assembly using the
9 | interop interface.
10 | While a managed launcher like this could just bypass the interop interface and call the API inside the
11 | library directly, doing it this way lets us test (and debug if needed) that interface without having
12 | native code involved.
13 |
14 | Some of the following hardcoded options will most likely need to be changed before it runs.
15 |
16 | Note that this project hard references the Release dll of MMManaged so you should build that first
17 | to get rid of the red wiggles.
18 |
19 | *)
20 |
21 | /// ModelMod root. In a source checkout this is the root of the tree.
22 | let MMRoot = @"M:\ModelMod"
23 | /// Game whose data you want to load. The game won't actually be launched, managed code doesn't do that,
24 | /// but the name is used to find a profile in the registry and then the data associated with that profile.
25 | /// Use MMLaunch to make a profile for the game. If you don't, this script may not load assets properly.
26 | let GameExe = @"F:\Guild Wars 2\Gw2.exe"
27 |
28 | /// You probably shouldn't change this. In a normal native launch it would be something like "38291382|d3d9".
29 | /// `|` is a delimiter. The first part is the integer address of a native-owned memory blob. Managed code doesn't
30 | /// look into this and simply passes it back to the native code in a callback (OnInitialized).
31 | /// The second part tells MMManaged the context it is running in, so that it knows how to locate certain native
32 | /// functions it expects to be available in its own native context.
33 | /// Here we use 0 and "standalone" because there is no native context.
34 | let MainArgs = "0|standalone"
35 |
36 | []
37 | let main argv =
38 | printfn "ModelMod Main Stub starting"
39 | // initialize in standalone mode with a null global state pointer (don't need that, only native uses it).
40 | let r = ModelMod.Main.Main(MainArgs)
41 | if r <> 0 then
42 | failwithf "Interop main failed, code %A" r
43 | match ModelMod.Main.StandaloneState with
44 | | None -> failwithf "Standalone state not initialized"
45 | | Some(state) ->
46 | let cd = state.callbacks.SetPaths.Invoke(MMRoot, GameExe)
47 | // the returned conf data is always valid, but it might just contain defaults if a profile could not be loaded.
48 | // SetPaths() doesn't return an error in that case for whatever reason.
49 | // oh well, just try loading
50 | let res = state.callbacks.LoadModDB.Invoke()
51 | let mutable loading = true
52 | while loading do
53 | let loadstate = state.callbacks.GetLoadingState.Invoke()
54 | loading <- loadstate = ModelMod.InteropTypes.AsyncLoadInProgress || loadstate = ModelMod.InteropTypes.AsyncLoadPending
55 | if loading then
56 | System.Threading.Thread.Sleep(250)
57 |
58 | printfn "ModelMod Main Stub exiting, code: %A" r
59 | 0
--------------------------------------------------------------------------------
/Test.ManagedLaunch/Test.ManagedLaunch.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net5.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | ..\Release\MMManaged.dll
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Test.NativeLaunch/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "aho-corasick"
7 | version = "0.7.20"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
10 | dependencies = [
11 | "memchr",
12 | ]
13 |
14 | [[package]]
15 | name = "anyhow"
16 | version = "1.0.69"
17 | source = "registry+https://github.com/rust-lang/crates.io-index"
18 | checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
19 |
20 | [[package]]
21 | name = "cfg-if"
22 | version = "1.0.0"
23 | source = "registry+https://github.com/rust-lang/crates.io-index"
24 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
25 |
26 | [[package]]
27 | name = "getrandom"
28 | version = "0.2.8"
29 | source = "registry+https://github.com/rust-lang/crates.io-index"
30 | checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
31 | dependencies = [
32 | "cfg-if",
33 | "libc",
34 | "wasi",
35 | ]
36 |
37 | [[package]]
38 | name = "libc"
39 | version = "0.2.139"
40 | source = "registry+https://github.com/rust-lang/crates.io-index"
41 | checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
42 |
43 | [[package]]
44 | name = "memchr"
45 | version = "2.5.0"
46 | source = "registry+https://github.com/rust-lang/crates.io-index"
47 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
48 |
49 | [[package]]
50 | name = "ppv-lite86"
51 | version = "0.2.17"
52 | source = "registry+https://github.com/rust-lang/crates.io-index"
53 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
54 |
55 | [[package]]
56 | name = "rand"
57 | version = "0.8.5"
58 | source = "registry+https://github.com/rust-lang/crates.io-index"
59 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
60 | dependencies = [
61 | "libc",
62 | "rand_chacha",
63 | "rand_core",
64 | ]
65 |
66 | [[package]]
67 | name = "rand_chacha"
68 | version = "0.3.1"
69 | source = "registry+https://github.com/rust-lang/crates.io-index"
70 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
71 | dependencies = [
72 | "ppv-lite86",
73 | "rand_core",
74 | ]
75 |
76 | [[package]]
77 | name = "rand_core"
78 | version = "0.6.4"
79 | source = "registry+https://github.com/rust-lang/crates.io-index"
80 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
81 | dependencies = [
82 | "getrandom",
83 | ]
84 |
85 | [[package]]
86 | name = "test_native_launch"
87 | version = "0.1.0"
88 | dependencies = [
89 | "aho-corasick",
90 | "anyhow",
91 | "rand",
92 | "winapi",
93 | ]
94 |
95 | [[package]]
96 | name = "wasi"
97 | version = "0.11.0+wasi-snapshot-preview1"
98 | source = "registry+https://github.com/rust-lang/crates.io-index"
99 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
100 |
101 | [[package]]
102 | name = "winapi"
103 | version = "0.3.9"
104 | source = "registry+https://github.com/rust-lang/crates.io-index"
105 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
106 | dependencies = [
107 | "winapi-i686-pc-windows-gnu",
108 | "winapi-x86_64-pc-windows-gnu",
109 | ]
110 |
111 | [[package]]
112 | name = "winapi-i686-pc-windows-gnu"
113 | version = "0.4.0"
114 | source = "registry+https://github.com/rust-lang/crates.io-index"
115 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
116 |
117 | [[package]]
118 | name = "winapi-x86_64-pc-windows-gnu"
119 | version = "0.4.0"
120 | source = "registry+https://github.com/rust-lang/crates.io-index"
121 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
122 |
--------------------------------------------------------------------------------
/Test.NativeLaunch/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "test_native_launch"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | winapi = { version = "0.3", features = ["libloaderapi",
10 | "d3d9",
11 | "d3d11",
12 | "d3d11sdklayers", # ID3D11InfoQueue + message enums
13 | "dxgi",
14 | "objidlbase",
15 | "processthreadsapi", "memoryapi", "winerror", "winuser", "winreg",
16 | "dinput", "sysinfoapi", "errhandlingapi"] }
17 | anyhow = "*"
18 | rand = "*"
19 | aho-corasick = "0.7.20"
--------------------------------------------------------------------------------
/Test.NativeLaunch/basic_format.txt:
--------------------------------------------------------------------------------
1 | // format: semanticname semanticindex offset dxgiformat
2 | // for determining the size of the vert the highest offset + format size of that elem is used,
3 | // so it should be ok to comment out lines here to disable things without changing offsets;
4 | // that should just cause unused space in the vert
5 | Position 0 0 R32G32B32_Float
6 | Normal 0 12 R16G16B16A16_SInt // normal & tangent; 2 s16 per vec packed format
7 | Binormal 0 20 R16G16_SInt // 2 s16 packed format
8 | TEXCOORD 0 24 R16G16B16A16_SNorm
9 |
--------------------------------------------------------------------------------
/Test.NativeLaunch/basic_vshader.cso:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/Test.NativeLaunch/basic_vshader.cso
--------------------------------------------------------------------------------
/Test.NativeLaunch/basic_vshader.hlsl:
--------------------------------------------------------------------------------
1 | struct VS_INPUT
2 | {
3 | float3 position : POSITION;
4 | int4 normal : NORMAL;
5 | int2 binormal : BINORMAL;
6 | float4 texturecoordinate0 : TEXCOORD0;
7 | };
8 |
9 | struct VS_OUTPUT
10 | {
11 | float4 position : SV_POSITION;
12 | };
13 |
14 | VS_OUTPUT main(VS_INPUT input)
15 | {
16 | VS_OUTPUT output;
17 | output.position = float4(input.position, 1.0);
18 | return output;
19 | }
20 |
--------------------------------------------------------------------------------
/Test.NativeLaunch/dxgiformats.txt:
--------------------------------------------------------------------------------
1 | // from: https://github.com/retep998/winapi-rs/blob/0.3/src/shared/dxgiformat.rs
2 | DXGI_FORMAT_UNKNOWN = 0
3 | DXGI_FORMAT_R32G32B32A32_TYPELESS = 1
4 | DXGI_FORMAT_R32G32B32A32_FLOAT = 2
5 | DXGI_FORMAT_R32G32B32A32_UINT = 3
6 | DXGI_FORMAT_R32G32B32A32_SINT = 4
7 | DXGI_FORMAT_R32G32B32_TYPELESS = 5
8 | DXGI_FORMAT_R32G32B32_FLOAT = 6
9 | DXGI_FORMAT_R32G32B32_UINT = 7
10 | DXGI_FORMAT_R32G32B32_SINT = 8
11 | DXGI_FORMAT_R16G16B16A16_TYPELESS = 9
12 | DXGI_FORMAT_R16G16B16A16_FLOAT = 10
13 | DXGI_FORMAT_R16G16B16A16_UNORM = 11
14 | DXGI_FORMAT_R16G16B16A16_UINT = 12
15 | DXGI_FORMAT_R16G16B16A16_SNORM = 13
16 | DXGI_FORMAT_R16G16B16A16_SINT = 14
17 | DXGI_FORMAT_R32G32_TYPELESS = 15
18 | DXGI_FORMAT_R32G32_FLOAT = 16
19 | DXGI_FORMAT_R32G32_UINT = 17
20 | DXGI_FORMAT_R32G32_SINT = 18
21 | DXGI_FORMAT_R32G8X24_TYPELESS = 19
22 | DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20
23 | DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21
24 | DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22
25 | DXGI_FORMAT_R10G10B10A2_TYPELESS = 23
26 | DXGI_FORMAT_R10G10B10A2_UNORM = 24
27 | DXGI_FORMAT_R10G10B10A2_UINT = 25
28 | DXGI_FORMAT_R11G11B10_FLOAT = 26
29 | DXGI_FORMAT_R8G8B8A8_TYPELESS = 27
30 | DXGI_FORMAT_R8G8B8A8_UNORM = 28
31 | DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29
32 | DXGI_FORMAT_R8G8B8A8_UINT = 30
33 | DXGI_FORMAT_R8G8B8A8_SNORM = 31
34 | DXGI_FORMAT_R8G8B8A8_SINT = 32
35 | DXGI_FORMAT_R16G16_TYPELESS = 33
36 | DXGI_FORMAT_R16G16_FLOAT = 34
37 | DXGI_FORMAT_R16G16_UNORM = 35
38 | DXGI_FORMAT_R16G16_UINT = 36
39 | DXGI_FORMAT_R16G16_SNORM = 37
40 | DXGI_FORMAT_R16G16_SINT = 38
41 | DXGI_FORMAT_R32_TYPELESS = 39
42 | DXGI_FORMAT_D32_FLOAT = 40
43 | DXGI_FORMAT_R32_FLOAT = 41
44 | DXGI_FORMAT_R32_UINT = 42
45 | DXGI_FORMAT_R32_SINT = 43
46 | DXGI_FORMAT_R24G8_TYPELESS = 44
47 | DXGI_FORMAT_D24_UNORM_S8_UINT = 45
48 | DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46
49 | DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47
50 | DXGI_FORMAT_R8G8_TYPELESS = 48
51 | DXGI_FORMAT_R8G8_UNORM = 49
52 | DXGI_FORMAT_R8G8_UINT = 50
53 | DXGI_FORMAT_R8G8_SNORM = 51
54 | DXGI_FORMAT_R8G8_SINT = 52
55 | DXGI_FORMAT_R16_TYPELESS = 53
56 | DXGI_FORMAT_R16_FLOAT = 54
57 | DXGI_FORMAT_D16_UNORM = 55
58 | DXGI_FORMAT_R16_UNORM = 56
59 | DXGI_FORMAT_R16_UINT = 57
60 | DXGI_FORMAT_R16_SNORM = 58
61 | DXGI_FORMAT_R16_SINT = 59
62 | DXGI_FORMAT_R8_TYPELESS = 60
63 | DXGI_FORMAT_R8_UNORM = 61
64 | DXGI_FORMAT_R8_UINT = 62
65 | DXGI_FORMAT_R8_SNORM = 63
66 | DXGI_FORMAT_R8_SINT = 64
67 | DXGI_FORMAT_A8_UNORM = 65
68 | DXGI_FORMAT_R1_UNORM = 66
69 | DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67
70 | DXGI_FORMAT_R8G8_B8G8_UNORM = 68
71 | DXGI_FORMAT_G8R8_G8B8_UNORM = 69
72 | DXGI_FORMAT_BC1_TYPELESS = 70
73 | DXGI_FORMAT_BC1_UNORM = 71
74 | DXGI_FORMAT_BC1_UNORM_SRGB = 72
75 | DXGI_FORMAT_BC2_TYPELESS = 73
76 | DXGI_FORMAT_BC2_UNORM = 74
77 | DXGI_FORMAT_BC2_UNORM_SRGB = 75
78 | DXGI_FORMAT_BC3_TYPELESS = 76
79 | DXGI_FORMAT_BC3_UNORM = 77
80 | DXGI_FORMAT_BC3_UNORM_SRGB = 78
81 | DXGI_FORMAT_BC4_TYPELESS = 79
82 | DXGI_FORMAT_BC4_UNORM = 80
83 | DXGI_FORMAT_BC4_SNORM = 81
84 | DXGI_FORMAT_BC5_TYPELESS = 82
85 | DXGI_FORMAT_BC5_UNORM = 83
86 | DXGI_FORMAT_BC5_SNORM = 84
87 | DXGI_FORMAT_B5G6R5_UNORM = 85
88 | DXGI_FORMAT_B5G5R5A1_UNORM = 86
89 | DXGI_FORMAT_B8G8R8A8_UNORM = 87
90 | DXGI_FORMAT_B8G8R8X8_UNORM = 88
91 | DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89
92 | DXGI_FORMAT_B8G8R8A8_TYPELESS = 90
93 | DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91
94 | DXGI_FORMAT_B8G8R8X8_TYPELESS = 92
95 | DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93
96 | DXGI_FORMAT_BC6H_TYPELESS = 94
97 | DXGI_FORMAT_BC6H_UF16 = 95
98 | DXGI_FORMAT_BC6H_SF16 = 96
99 | DXGI_FORMAT_BC7_TYPELESS = 97
100 | DXGI_FORMAT_BC7_UNORM = 98
101 | DXGI_FORMAT_BC7_UNORM_SRGB = 99
102 | DXGI_FORMAT_AYUV = 100
103 | DXGI_FORMAT_Y410 = 101
104 | DXGI_FORMAT_Y416 = 102
105 | DXGI_FORMAT_NV12 = 103
106 | DXGI_FORMAT_P010 = 104
107 | DXGI_FORMAT_P016 = 105
108 | DXGI_FORMAT_420_OPAQUE = 106
109 | DXGI_FORMAT_YUY2 = 107
110 | DXGI_FORMAT_Y210 = 108
111 | DXGI_FORMAT_Y216 = 109
112 | DXGI_FORMAT_NV11 = 110
113 | DXGI_FORMAT_AI44 = 111
114 | DXGI_FORMAT_IA44 = 112
115 | DXGI_FORMAT_P8 = 113
116 | DXGI_FORMAT_A8P8 = 114
117 | DXGI_FORMAT_B4G4R4A4_UNORM = 115
118 | DXGI_FORMAT_P208 = 130
119 | DXGI_FORMAT_V208 = 131
120 | DXGI_FORMAT_V408 = 132
121 |
122 |
--------------------------------------------------------------------------------
/Test.NativeLaunch/runmm.sh:
--------------------------------------------------------------------------------
1 | set -e
2 |
3 | mmdir=../Native
4 |
5 | # change into mm native dir, check target symlink and build mm dll
6 | (cd $mmdir && rm -f $mmdir/target && sh ./setjunc.sh >/dev/null && cargo build)
7 | cp -v $mmdir/target/debug/hook_core.dll target/debug/d3d11.dll
8 | cargo run -- $@
9 |
10 | # ad hoc benchmark functions for testing the load_mmobj module. intended
11 | # to be pasted into a bash shell.
12 | #cat /m/ModelMod/Logs/ModelMod.test_native_launch.log | grep -i "M:SW:readmmob" | awk '{print $NF}' | sed 's/ms//' | awk '{s+=$1} END {print s}'
13 |
14 | # function to record a new sample named by its first argument, fails if that files already exists
15 | function record_sample {
16 | if [ -f $1 ]; then
17 | echo "existing sample: "
18 | cat $1 | awk '{print $NF}' | sed 's/ms//' | awk '{s+=$1} END {print s}'
19 | #echo "file $1 already exists"
20 | return
21 | fi
22 | cat /m/ModelMod/Logs/ModelMod.test_native_launch.log | grep -i "M:SW:readmmob" > $1
23 | cat $1 | awk '{print $NF}' | sed 's/ms//' | awk '{s+=$1} END {print s}'
24 | }
25 |
26 | # average of the given N sample files
27 | function avg_samples {
28 | for f in $@; do
29 | cat $f | awk '{print $NF}' | sed 's/ms//' | awk '{s+=$1} END {print s}'
30 | done | awk '{s+=$1} END {print s/NR}'
31 | }
32 |
--------------------------------------------------------------------------------
/Test.NativeLaunch/simple_vertex_shader.dat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/Test.NativeLaunch/simple_vertex_shader.dat
--------------------------------------------------------------------------------
/TestData/DelMod.yaml:
--------------------------------------------------------------------------------
1 | type: "Mod"
2 | meshtype: Deletion
3 | delGeometry: [
4 | { pc: 100, vc: 200 },
5 | { pc: 150, vc: 300 }
6 | ]
--------------------------------------------------------------------------------
/TestData/ModIndex.yaml:
--------------------------------------------------------------------------------
1 | type: "Index"
2 | mods:
3 | - {name: "MonolithMod" }
4 | - {name: "DelMod" }
5 |
--------------------------------------------------------------------------------
/TestData/Mods/FT_Barrel/FT_BarrelMod.yaml:
--------------------------------------------------------------------------------
1 | Type: Mod
2 | Ref: FT_BarrelRef
3 | ModType: GPUReplacement
4 | MeshPath: FT_BarrelMod.mmobj
5 |
--------------------------------------------------------------------------------
/TestData/Mods/FT_Barrel/FT_BarrelRef.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/TestData/Mods/FT_Barrel/FT_BarrelRef.dds
--------------------------------------------------------------------------------
/TestData/Mods/FT_Barrel/FT_BarrelRef.mtl:
--------------------------------------------------------------------------------
1 | # ModelMod material file
2 | newmtl (null)
3 | map_Kd FT_BarrelRef.dds
4 |
--------------------------------------------------------------------------------
/TestData/Mods/FT_Barrel/FT_BarrelRef.yaml:
--------------------------------------------------------------------------------
1 | Type: Reference
2 | MeshPath: FT_BarrelRef.mmobj
3 | VertDeclPath: FT_BarrelRef_VBDecl.dat
4 | ExpectedPrimCount: 396
5 | ExpectedVertCount: 286
6 |
--------------------------------------------------------------------------------
/TestData/Mods/FT_Barrel/FT_BarrelRef_VBDecl.dat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/TestData/Mods/FT_Barrel/FT_BarrelRef_VBDecl.dat
--------------------------------------------------------------------------------
/TestData/Mods/FT_Crate/FT_CrateMod.yaml:
--------------------------------------------------------------------------------
1 | Type: Mod
2 | Ref: FT_CrateRef
3 | ModType: GPUReplacement
4 | MeshPath: FT_CrateMod.mmobj
5 |
--------------------------------------------------------------------------------
/TestData/Mods/FT_Crate/FT_CrateRef.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/TestData/Mods/FT_Crate/FT_CrateRef.dds
--------------------------------------------------------------------------------
/TestData/Mods/FT_Crate/FT_CrateRef.mtl:
--------------------------------------------------------------------------------
1 | # ModelMod material file
2 | newmtl (null)
3 | map_Kd FT_CrateRef.dds
4 |
--------------------------------------------------------------------------------
/TestData/Mods/FT_Crate/FT_CrateRef.yaml:
--------------------------------------------------------------------------------
1 | Type: Reference
2 | MeshPath: FT_CrateRef.mmobj
3 | VertDeclPath: FT_CrateRef_VBDecl.dat
4 | ExpectedPrimCount: 586
5 | ExpectedVertCount: 765
6 |
--------------------------------------------------------------------------------
/TestData/Mods/FT_Crate/FT_CrateRef_VBDecl.dat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/TestData/Mods/FT_Crate/FT_CrateRef_VBDecl.dat
--------------------------------------------------------------------------------
/TestData/Mods/FT_LargeRock/FT_LargeRockMod.yaml:
--------------------------------------------------------------------------------
1 | Type: Mod
2 | Ref: FT_LargeRockRef
3 | ModType: GPUReplacement
4 | MeshPath: FT_LargeRockMod.mmobj
5 |
--------------------------------------------------------------------------------
/TestData/Mods/FT_LargeRock/FT_LargeRockRef.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/TestData/Mods/FT_LargeRock/FT_LargeRockRef.dds
--------------------------------------------------------------------------------
/TestData/Mods/FT_LargeRock/FT_LargeRockRef.mtl:
--------------------------------------------------------------------------------
1 | # ModelMod material file
2 | newmtl (null)
3 | map_Kd FT_LargeRockRef.dds
4 |
--------------------------------------------------------------------------------
/TestData/Mods/FT_LargeRock/FT_LargeRockRef.yaml:
--------------------------------------------------------------------------------
1 | Type: Reference
2 | MeshPath: FT_LargeRockRef.mmobj
3 | VertDeclPath: FT_LargeRockRef_VBDecl.dat
4 | ExpectedPrimCount: 80
5 | ExpectedVertCount: 75
6 |
--------------------------------------------------------------------------------
/TestData/Mods/FT_LargeRock/FT_LargeRockRef_VBDecl.dat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/TestData/Mods/FT_LargeRock/FT_LargeRockRef_VBDecl.dat
--------------------------------------------------------------------------------
/TestData/Mods/ModIndex.yaml:
--------------------------------------------------------------------------------
1 | type: "Index"
2 | mods:
3 | - {name: "FT_BarrelMod"}
4 | - {name: "FT_CrateMod"}
5 | - {name: "FT_LargeRockMod"}
6 |
--------------------------------------------------------------------------------
/TestData/MonolithMod.mmobj:
--------------------------------------------------------------------------------
1 | # Blender v2.73 (sub 0) OBJ File: 'monolithmod.blend'
2 | # www.blender.org
3 | o Body_Plane
4 | v 4.000000 0.000000 0.000000
5 | v 4.000000 0.000000 -1.000000
6 | v 0.000000 0.000000 -1.000000
7 | v 0.000000 0.000000 0.000000
8 | v 0.000000 9.000000 0.000002
9 | v 4.000000 9.000000 0.000002
10 | v 0.000000 9.000000 -0.999997
11 | v 4.000000 9.000000 -0.999997
12 | vt 0.000000 0.000000
13 | vt 1.000000 0.000000
14 | vt 1.000000 1.000000
15 | vn -0.577300 0.577300 -0.577300
16 | vn -0.577300 0.577300 0.577300
17 | vn 0.577300 0.577300 0.577300
18 | vn 0.577300 0.577300 -0.577300
19 | vn 0.577300 -0.577300 -0.577300
20 | vn -0.577300 -0.577300 -0.577300
21 | vn 0.577300 -0.577300 0.577300
22 | vn -0.577300 -0.577300 0.577300
23 | s 1
24 | f 1/1/1 2/2/2 3/3/3
25 | f 4/1/4 5/2/5 6/3/6
26 | f 7/1/7 8/2/8 6/3/6
27 | f 2/1/2 8/2/8 7/3/7
28 | f 1/1/1 6/2/6 8/3/8
29 | f 3/1/3 7/2/7 5/3/5
30 | f 4/1/4 1/2/1 3/3/3
31 | f 1/1/1 4/2/4 6/3/6
32 | f 5/1/5 7/2/7 6/3/6
33 | f 3/1/3 2/2/2 7/3/7
34 | f 2/1/2 1/2/1 8/3/8
35 | f 4/1/4 3/2/3 5/3/5
36 | o Hat_Plane.001
37 | v -0.271342 9.231935 0.500004
38 | v -0.271342 8.731935 0.500003
39 | v -0.271342 8.731935 -1.499997
40 | v -0.271342 9.231935 -1.499996
41 | v 4.228658 9.231935 -1.499996
42 | v 4.228658 9.231935 0.500003
43 | v 4.228658 8.731935 -1.499998
44 | v 4.228658 8.731935 0.500002
45 | v 0.853658 9.488905 0.000004
46 | v 0.853658 9.238905 0.000004
47 | v 0.853658 9.238905 -0.999996
48 | v 0.853658 9.488905 -0.999996
49 | v 3.103658 9.488905 -0.999996
50 | v 3.103658 9.488905 0.000003
51 | v 3.103658 9.238905 -0.999996
52 | v 3.103658 9.238905 0.000004
53 | vt 0.000000 0.000000
54 | vt 1.000000 0.000000
55 | vt 1.000000 1.000000
56 | vn 0.577300 -0.577300 -0.577300
57 | vn 0.577300 0.577300 -0.577300
58 | vn 0.577300 0.577300 0.577300
59 | vn 0.577300 -0.577300 0.577300
60 | vn -0.577300 -0.577300 0.577300
61 | vn -0.577300 -0.577300 -0.577300
62 | vn -0.577300 0.577300 0.577300
63 | vn -0.577300 0.577300 -0.577300
64 | s 1
65 | f 9/4/9 10/5/10 11/6/11
66 | f 12/4/12 13/5/13 14/6/14
67 | f 15/4/15 16/5/16 14/6/14
68 | f 10/4/10 16/5/16 15/6/15
69 | f 9/4/9 14/5/14 16/6/16
70 | f 11/4/11 15/5/15 13/6/13
71 | f 12/4/12 9/5/9 11/6/11
72 | f 9/4/9 12/5/12 14/6/14
73 | f 13/4/13 15/5/15 14/6/14
74 | f 11/4/11 10/5/10 15/6/15
75 | f 10/4/10 9/5/9 16/6/16
76 | f 12/4/12 11/5/11 13/6/13
77 | f 17/4/9 18/5/10 19/6/11
78 | f 20/4/12 21/5/13 22/6/14
79 | f 23/4/15 24/5/16 22/6/14
80 | f 18/4/10 24/5/16 23/6/15
81 | f 17/4/9 22/5/14 24/6/16
82 | f 19/4/11 23/5/15 21/6/13
83 | f 20/4/12 17/5/9 19/6/11
84 | f 17/4/9 20/5/12 22/6/14
85 | f 21/4/13 23/5/15 22/6/14
86 | f 19/4/11 18/5/10 23/6/15
87 | f 18/4/10 17/5/9 24/6/16
88 | f 20/4/12 19/5/11 21/6/13
89 |
--------------------------------------------------------------------------------
/TestData/MonolithMod.yaml:
--------------------------------------------------------------------------------
1 | Type: Mod
2 | Ref: MonolithRef
3 | MeshType: GPUReplacement
4 | MeshPath: MonolithMod.mmobj
5 |
6 |
--------------------------------------------------------------------------------
/TestData/MonolithRef.mmobj:
--------------------------------------------------------------------------------
1 | # Blender v2.73 (sub 0) OBJ File: ''
2 | # www.blender.org
3 | o Plane
4 | v 4.000000 0.000000 0.000000
5 | v 4.000000 0.000000 -1.000000
6 | v 0.000000 0.000000 -1.000000
7 | v 0.000000 0.000000 0.000000
8 | v 0.000000 9.000000 0.000002
9 | v 4.000000 9.000000 0.000002
10 | v 0.000000 9.000000 -0.999997
11 | v 4.000000 9.000000 -0.999997
12 | vt 0.000000 0.000000
13 | vt 1.000000 0.000000
14 | vt 1.000000 1.000000
15 | vn -0.577300 0.577300 -0.577300
16 | vn -0.577300 0.577300 0.577300
17 | vn 0.577300 0.577300 0.577300
18 | vn 0.577300 0.577300 -0.577300
19 | vn 0.577300 -0.577300 -0.577300
20 | vn -0.577300 -0.577300 -0.577300
21 | vn 0.577300 -0.577300 0.577300
22 | vn -0.577300 -0.577300 0.577300
23 | s 1
24 | f 1/1/1 2/2/2 3/3/3
25 | f 4/1/4 5/2/5 6/3/6
26 | f 7/1/7 8/2/8 6/3/6
27 | f 2/1/2 8/2/8 7/3/7
28 | f 1/1/1 6/2/6 8/3/8
29 | f 3/1/3 7/2/7 5/3/5
30 | f 4/1/4 1/2/1 3/3/3
31 | f 1/1/1 4/2/4 6/3/6
32 | f 5/1/5 7/2/7 6/3/6
33 | f 3/1/3 2/2/2 7/3/7
34 | f 2/1/2 1/2/1 8/3/8
35 | f 4/1/4 3/2/3 5/3/5
36 |
--------------------------------------------------------------------------------
/TestData/MonolithRef.yaml:
--------------------------------------------------------------------------------
1 | Type: Reference
2 | MeshPath: MonolithRef.mmobj
3 | VertDeclPath: MonolithRef_VBDecl.dat
4 | ExpectedPrimCount: 12
5 | ExpectedVertCount: 8
6 |
--------------------------------------------------------------------------------
/TestData/MonolithRef_VBDecl.dat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/TestData/MonolithRef_VBDecl.dat
--------------------------------------------------------------------------------
/TestData/Test.yaml:
--------------------------------------------------------------------------------
1 | Something: "Somewhere"
2 | Int: 47
3 | Mapping: {
4 | a: 1,
5 | b: 2
6 | }
7 | Sequence: [1,2,3,4,5]
8 | Bool: true
9 |
--------------------------------------------------------------------------------
/TestData/monolithmod.blend:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/TestData/monolithmod.blend
--------------------------------------------------------------------------------
/TestData/monolithref.blend:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmquigs/ModelMod/2e743d54f8086afb723bc4eaac7dc59d690d2608/TestData/monolithref.blend
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # as of 3/10/2023 appveyor doesn't work well with cargo, cargo is unable to reliably update
2 | # its index due to a SSL connect issue. therefore I am not using appveyor at this time.
3 | # note: if appyveyor appears to be ignoring this file (and only using UI settings to build)
4 | # verify that it is still authorized to access the github repo (in its UI)
5 | environment:
6 | buildenv: appveyor
7 | # unsuccessful attempt to try to fix the cargo issue:
8 | CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
9 |
10 | install:
11 | - curl -sSf -o rustup-init.exe https://win.rustup.rs/
12 | - rustup-init.exe -y --default-host x86_64-pc-windows-msvc
13 | - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
14 | # - if defined MSYS2 set PATH=C:\msys64\mingw%BITS%\bin;%PATH%
15 | - set PATH=C:\msys64\mingw64\bin;%PATH%
16 | # - rustc -V
17 | # - cargo -V
18 |
19 | before_build:
20 | - del "MMManaged\\Dn5-MMManaged.fsproj" # this confuses paket restore, so remove it
21 | - installdeps.bat nopause
22 | # for testing native builds before building all the managed crap
23 | # needs to be done after deps installed though because that is what gets us fake/paket
24 | - build.bat BuildNativeTest nopause
25 | #- dir packages
26 |
27 | build_script: build.bat AppveyorBuild nopause
28 |
29 | test_script: build.bat AppveyorTest nopause
30 |
31 | after_test: build.bat AppveyorPackage nopause
32 |
33 | artifacts:
34 | - path: deploy/*.zip
35 |
--------------------------------------------------------------------------------
/build.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | SET TARGET="FullBuild"
3 |
4 | IF NOT [%1]==[] (set TARGET="%1")
5 |
6 | cls
7 | ".paket\paket.exe" install
8 | "packages\FAKE\tools\Fake.exe" build.fsx "target=%TARGET%"
9 |
10 | if "%2"=="nopause" goto exit
11 | pause
12 | :exit
13 |
--------------------------------------------------------------------------------
/installdeps.bat:
--------------------------------------------------------------------------------
1 | ".paket\paket.bootstrapper.exe"
2 | ".paket\paket.exe" install
3 |
4 | if "%1"=="nopause" goto exit
5 | pause
6 | :exit
7 |
--------------------------------------------------------------------------------
/paket.dependencies:
--------------------------------------------------------------------------------
1 | source https://www.nuget.org/api/v2/
2 |
3 | nuget FSharp.Core 4.6.2 framework: >= net45
4 | nuget Expression.Blend.Sdk 1.0.2 framework: >= net45
5 | nuget FSharp.ViewModule.Core 0.9.9.1 framework: >= net45
6 | nuget FsUnit 1.3.0.1 framework: >= net45
7 | nuget FsXaml.Wpf 0.9.9 framework: >= net45
8 | nuget MonoGame.Framework.WindowsDX 3.3.0.0 framework: >= net45
9 | nuget NUnit 2.6.4 framework: >= net45
10 | nuget YamlDotNet 3.5.1 framework: >= net45
11 | nuget FAKE
12 | nuget NUnit.Runners
--------------------------------------------------------------------------------
/paket.lock:
--------------------------------------------------------------------------------
1 | NUGET
2 | remote: https://www.nuget.org/api/v2
3 | Expression.Blend.Sdk (1.0.2) - restriction: >= net45
4 | FAKE (4.4.6)
5 | FSharp.Core (4.6.2) - restriction: >= net45
6 | FSharp.ViewModule.Core (0.9.9.1) - restriction: >= net45
7 | FsUnit (1.3.0.1) - restriction: >= net45
8 | NUnit (>= 2.6.3)
9 | FsXaml.Wpf (0.9.9) - restriction: >= net45
10 | Expression.Blend.Sdk (>= 1.0.2) - restriction: >= net45
11 | MonoGame.Framework.WindowsDX (3.3) - restriction: >= net45
12 | NUnit (2.6.4) - restriction: >= net45
13 | NUnit.Runners (2.6.4)
14 | YamlDotNet (3.5.1) - restriction: >= net45
15 |
--------------------------------------------------------------------------------
/sign.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | build SignBuild
3 | :exit
4 |
--------------------------------------------------------------------------------
/updateversions.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | build UpdateVersions
3 | :exit
4 |
--------------------------------------------------------------------------------