├── .gitignore ├── .gitmodules ├── Directory.Build.props ├── Directory.Build.targets ├── GraphicsHook.sln ├── LICENSE ├── README.md ├── docs └── supported-libraries.md ├── src ├── Direct3DCapture │ ├── Class1.cs │ └── Direct3DCapture.csproj ├── DirectX.Direct3D.Core │ ├── Direct3DHook.cs │ ├── Direct3DVersion.cs │ ├── DirectX.Direct3D.Core.csproj │ ├── Drawing │ │ ├── FramesPerSecondOverlay.cs │ │ ├── IOverlay.cs │ │ ├── IOverlayElement.cs │ │ ├── ImageOverlay.cs │ │ ├── Overlay.cs │ │ ├── OverlayElement.cs │ │ └── TextOverlay.cs │ ├── IDirect3DHook.cs │ └── Memory │ │ ├── DisposableBase.cs │ │ ├── DisposableComponent.cs │ │ └── DisposableEventArgs.cs ├── DirectX.Direct3D10.Overlay │ └── DirectX.Direct3D10.Overlay.csproj ├── DirectX.Direct3D11.Overlay │ ├── Component.cs │ ├── ComponentBase.cs │ ├── DXFont.cs │ ├── DXImage.cs │ ├── DXSprite.cs │ ├── Direct3DHookModule.cs │ ├── DirectX.Direct3D11.Overlay.csproj │ ├── EntryPoint.cs │ ├── FunctionOrdinals.cs │ ├── IComponent.cs │ ├── OverlayRenderer.cs │ └── SafeHGlobal.cs └── DirectX.Direct3D9.Overlay │ ├── Direct3DHookModule.cs │ ├── DirectX.Direct3D9.Overlay.csproj │ ├── EntryPoint.cs │ ├── FunctionOrdinals.cs │ └── OverlayRenderer.cs └── test └── Direct3DCapture.Tests ├── Direct3DCapture.Tests.csproj └── UnitTest1.cs /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "deps/SharpDX.Desktop"] 2 | path = deps/SharpDX.Desktop 3 | url = git://github.com/unknownv2/SharpDX.Desktop.git 4 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | Release 6 | $(MSBuildThisFileDirectory) 7 | $(ProjectDir)src\ 8 | $(SourceDir)Common\src 9 | $(ProjectDir)bin/ 10 | $(BinDir)$(Configuration)/$(Platform)/ 11 | 12 | 13 | -------------------------------------------------------------------------------- /Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 7 | $(MSBuildProgramFiles32)\dotnet\dotnet 8 | $(ProgramW6432)\dotnet\dotnet 9 | 10 | -------------------------------------------------------------------------------- /GraphicsHook.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.136 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Direct3DCapture", "src\Direct3DCapture\Direct3DCapture.csproj", "{4A14506E-9C5E-43BC-87E4-34C08DEABDC3}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E9D61240-9E2C-4BD5-BEF1-607D3422EAAF}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{2FDEAA0B-9F04-4CB1-89CF-EF668584453A}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Direct3DCapture.Tests", "test\Direct3DCapture.Tests\Direct3DCapture.Tests.csproj", "{39FCDDD4-78AF-4F6F-BA40-724A5D1AE620}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DirectX.Direct3D9.Overlay", "src\DirectX.Direct3D9.Overlay\DirectX.Direct3D9.Overlay.csproj", "{A86B01F8-1FEA-485B-85D7-3941694EC0A4}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DirectX.Direct3D11.Overlay", "src\DirectX.Direct3D11.Overlay\DirectX.Direct3D11.Overlay.csproj", "{96BC579E-FAFD-4152-8AFC-81905D7BF210}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DirectX.Direct3D.Core", "src\DirectX.Direct3D.Core\DirectX.Direct3D.Core.csproj", "{224F9343-46F6-4654-9381-E35239D179F1}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DirectX.Direct3D10.Overlay", "src\DirectX.Direct3D10.Overlay\DirectX.Direct3D10.Overlay.csproj", "{409B3409-61FE-4614-B755-843689E50EF6}" 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpDX.Desktop", "deps\SharpDX.Desktop\SharpDX.Desktop\SharpDX.Desktop.csproj", "{4062A245-60C4-415C-84A2-FA3E5D6B9D3F}" 23 | EndProject 24 | Global 25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 26 | Debug|Any CPU = Debug|Any CPU 27 | Release|Any CPU = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 30 | {4A14506E-9C5E-43BC-87E4-34C08DEABDC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {4A14506E-9C5E-43BC-87E4-34C08DEABDC3}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {4A14506E-9C5E-43BC-87E4-34C08DEABDC3}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {4A14506E-9C5E-43BC-87E4-34C08DEABDC3}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {39FCDDD4-78AF-4F6F-BA40-724A5D1AE620}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {39FCDDD4-78AF-4F6F-BA40-724A5D1AE620}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {39FCDDD4-78AF-4F6F-BA40-724A5D1AE620}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {39FCDDD4-78AF-4F6F-BA40-724A5D1AE620}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {A86B01F8-1FEA-485B-85D7-3941694EC0A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {A86B01F8-1FEA-485B-85D7-3941694EC0A4}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {A86B01F8-1FEA-485B-85D7-3941694EC0A4}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {A86B01F8-1FEA-485B-85D7-3941694EC0A4}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {96BC579E-FAFD-4152-8AFC-81905D7BF210}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {96BC579E-FAFD-4152-8AFC-81905D7BF210}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {96BC579E-FAFD-4152-8AFC-81905D7BF210}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {96BC579E-FAFD-4152-8AFC-81905D7BF210}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {224F9343-46F6-4654-9381-E35239D179F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {224F9343-46F6-4654-9381-E35239D179F1}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {224F9343-46F6-4654-9381-E35239D179F1}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {224F9343-46F6-4654-9381-E35239D179F1}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {409B3409-61FE-4614-B755-843689E50EF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {409B3409-61FE-4614-B755-843689E50EF6}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {409B3409-61FE-4614-B755-843689E50EF6}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {409B3409-61FE-4614-B755-843689E50EF6}.Release|Any CPU.Build.0 = Release|Any CPU 54 | {4062A245-60C4-415C-84A2-FA3E5D6B9D3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 55 | {4062A245-60C4-415C-84A2-FA3E5D6B9D3F}.Debug|Any CPU.Build.0 = Debug|Any CPU 56 | {4062A245-60C4-415C-84A2-FA3E5D6B9D3F}.Release|Any CPU.ActiveCfg = Release|Any CPU 57 | {4062A245-60C4-415C-84A2-FA3E5D6B9D3F}.Release|Any CPU.Build.0 = Release|Any CPU 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | GlobalSection(NestedProjects) = preSolution 63 | {4A14506E-9C5E-43BC-87E4-34C08DEABDC3} = {E9D61240-9E2C-4BD5-BEF1-607D3422EAAF} 64 | {39FCDDD4-78AF-4F6F-BA40-724A5D1AE620} = {2FDEAA0B-9F04-4CB1-89CF-EF668584453A} 65 | {A86B01F8-1FEA-485B-85D7-3941694EC0A4} = {E9D61240-9E2C-4BD5-BEF1-607D3422EAAF} 66 | {96BC579E-FAFD-4152-8AFC-81905D7BF210} = {E9D61240-9E2C-4BD5-BEF1-607D3422EAAF} 67 | {224F9343-46F6-4654-9381-E35239D179F1} = {E9D61240-9E2C-4BD5-BEF1-607D3422EAAF} 68 | {409B3409-61FE-4614-B755-843689E50EF6} = {E9D61240-9E2C-4BD5-BEF1-607D3422EAAF} 69 | {4062A245-60C4-415C-84A2-FA3E5D6B9D3F} = {E9D61240-9E2C-4BD5-BEF1-607D3422EAAF} 70 | EndGlobalSection 71 | GlobalSection(ExtensibilityGlobals) = postSolution 72 | SolutionGuid = {15C4F934-433D-4655-9D2C-5E30E7A936C3} 73 | EndGlobalSection 74 | EndGlobal 75 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Thierry Bizimungu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Graphics Hook Sample 2 | 3 | Example tool for hooking graphics APIs using [CoreHook](https://github.com/unknownv2/CoreHook). 4 | 5 | 6 | Based on [Justin Stenning's Direct3DHook](https://github.com/spazzarama/Direct3DHook). 7 | 8 | ## Requirements 9 | 10 | **[Building the sample requires the .NET Core 3.0 SDK, which can be downloaded here.](https://dotnet.microsoft.com/download/dotnet-core/3.0)** 11 | 12 | The Direct3D10 and Direct3D11 modules require the .NET Windows Form libraries, which are only available with .NET Core 3.0 and above. 13 | 14 | The `deps` folder contains the [`SharpDX.Desktop`](https://github.com/unknownv2/SharpDX.Desktop) library targeting .NET Core 3.0, which is used by the Direct3D10 and Direct3D11 sample modules. 15 | 16 | ## Building 17 | 18 | Clone and build the sample with: 19 | 20 | ``` 21 | git clone --recursive git://github.com/unknownv2/graphics-hook.git 22 | cd graphics-hook 23 | dotnet build 24 | ``` 25 | 26 | ## References 27 | 28 | [Screen Capture and Overlays for Direct3D 9, 10 and 11 using API Hooks](https://spazzarama.com/2011/03/14/c-screen-capture-and-overlays-for-direct3d-9-10-and-11-using-api-hooks/) -------------------------------------------------------------------------------- /docs/supported-libraries.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unknownv2/graphics-hook/2c71826b3e1f89bed43a369c1e74d9e9415f2ddb/docs/supported-libraries.md -------------------------------------------------------------------------------- /src/Direct3DCapture/Class1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Direct3DCapture 4 | { 5 | public class Class1 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Direct3DCapture/Direct3DCapture.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | true 9 | $(OutputDir) 10 | 11 | 12 | 13 | true 14 | $(OutputDir) 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D.Core/Direct3DHook.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using DirectX.Direct3D.Core.Drawing; 3 | using DirectX.Direct3D.Core.Memory; 4 | 5 | namespace DirectX.Direct3D.Core 6 | { 7 | public abstract class Direct3DHook : DisposableComponent, IDirect3DHook 8 | { 9 | protected List Overlays { get; set; } 10 | 11 | protected bool PendingUpdate; 12 | 13 | public abstract void CreateHooks(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D.Core/Direct3DVersion.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DirectX.Direct3D.Core 4 | { 5 | public enum Direct3DVersion 6 | { 7 | Auto, 8 | Direct3D9, 9 | Direct3D10, 10 | Direct3D10_1, 11 | Direct3D11, 12 | Direct3D11_1, 13 | Direct3D12 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D.Core/DirectX.Direct3D.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | $(OutputDir) 9 | 10 | 11 | 12 | $(OutputDir) 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D.Core/Drawing/FramesPerSecondOverlay.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | 4 | namespace DirectX.Direct3D.Core.Drawing 5 | { 6 | public class FramesPerSecondOverlay : TextOverlay 7 | { 8 | private string _fpsText = "{0:N0} FPS"; 9 | 10 | private int _frameCount; 11 | private int _lastTickCount; 12 | private float _lastFrameRate; 13 | public override string Text 14 | { 15 | get => string.Format(_fpsText, GetFramesPerSecond()); 16 | set => _fpsText = value; 17 | } 18 | public FramesPerSecondOverlay(Font font) : base(font) 19 | { 20 | 21 | } 22 | 23 | public override void OnFrame() 24 | { 25 | _frameCount++; 26 | var tickCount = Environment.TickCount; 27 | if (Math.Abs(tickCount - _lastTickCount) > 1000) 28 | { 29 | _lastFrameRate = (float)_frameCount * 1000 / Math.Abs(tickCount - _lastTickCount); 30 | _frameCount = 0; 31 | _lastTickCount = tickCount; 32 | } 33 | } 34 | 35 | public float GetFramesPerSecond() 36 | { 37 | return _lastFrameRate; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D.Core/Drawing/IOverlay.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DirectX.Direct3D.Core.Drawing 4 | { 5 | public interface IOverlay : IOverlayElement 6 | { 7 | List Elements { get; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D.Core/Drawing/IOverlayElement.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DirectX.Direct3D.Core.Drawing 4 | { 5 | public interface IOverlayElement : ICloneable 6 | { 7 | bool Hidden { get; } 8 | 9 | void OnFrame(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D.Core/Drawing/ImageOverlay.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DirectX.Direct3D.Core.Drawing 6 | { 7 | public class ImageOverlay : OverlayElement 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D.Core/Drawing/Overlay.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace DirectX.Direct3D.Core.Drawing 5 | { 6 | [Serializable] 7 | public class Overlay : IOverlay 8 | { 9 | public List Elements { get; } = new List(); 10 | 11 | public bool Hidden { get; set; } 12 | 13 | public object Clone() => MemberwiseClone(); 14 | 15 | public void OnFrame() 16 | { 17 | foreach (var overlayElement in Elements) 18 | { 19 | overlayElement.OnFrame(); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D.Core/Drawing/OverlayElement.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DirectX.Direct3D.Core.Drawing 4 | { 5 | public class OverlayElement : IOverlayElement, IDisposable 6 | { 7 | public virtual bool Hidden { get; set; } 8 | 9 | public object Clone() => MemberwiseClone(); 10 | 11 | public virtual void OnFrame() 12 | { 13 | } 14 | 15 | protected virtual void Dispose(bool disposing) 16 | { 17 | } 18 | 19 | public void Dispose() 20 | { 21 | Dispose(true); 22 | GC.SuppressFinalize(this); 23 | } 24 | 25 | protected void SafeDispose(IDisposable disposableObject) => disposableObject?.Dispose(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D.Core/Drawing/TextOverlay.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DirectX.Direct3D.Core.Drawing 6 | { 7 | public class TextOverlay : OverlayElement 8 | { 9 | public virtual string Text { get; set; } 10 | 11 | public virtual System.Drawing.Font Font { get; set; } = System.Drawing.SystemFonts.DefaultFont; 12 | 13 | public virtual System.Drawing.Color Color { get; set; } = System.Drawing.Color.Black; 14 | 15 | public virtual System.Drawing.Point Location { get; set; } 16 | 17 | public virtual bool AntiAliased { get; set; } = false; 18 | 19 | public TextOverlay() 20 | { 21 | } 22 | 23 | public TextOverlay(System.Drawing.Font font) 24 | { 25 | Font = font; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D.Core/IDirect3DHook.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DirectX.Direct3D.Core 6 | { 7 | public interface IDirect3DHook : IDisposable 8 | { 9 | void CreateHooks(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D.Core/Memory/DisposableBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DirectX.Direct3D.Core.Memory 6 | { 7 | public abstract class DisposableBase : IDisposable 8 | { 9 | public bool IsDisposed { get; private set; } 10 | 11 | public void Dispose() 12 | { 13 | CheckAndDispose(true); 14 | } 15 | 16 | private void CheckAndDispose(bool disposing) 17 | { 18 | if (!IsDisposed) 19 | { 20 | IsDisposed = true; 21 | } 22 | } 23 | 24 | protected abstract void Dispose(bool disposing); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D.Core/Memory/DisposableComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using SharpDX; 5 | 6 | namespace DirectX.Direct3D.Core.Memory 7 | { 8 | public class DisposableComponent : DisposableBase 9 | { 10 | protected DisposeCollector DisposeCollector { get; set; } 11 | 12 | protected override void Dispose(bool disposeManagedResources) 13 | { 14 | 15 | } 16 | 17 | protected internal T ToDispose(T disposable) 18 | { 19 | if (!ReferenceEquals(disposable, null)) 20 | { 21 | if (DisposeCollector == null) 22 | { 23 | DisposeCollector = new DisposeCollector(); 24 | } 25 | 26 | return DisposeCollector.Collect(disposable); 27 | } 28 | 29 | return default(T); 30 | } 31 | 32 | protected internal void RemoveAndDispose(ref T disposable) 33 | { 34 | if (!ReferenceEquals(disposable, null)) 35 | { 36 | DisposeCollector?.RemoveAndDispose(ref disposable); 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D.Core/Memory/DisposableEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DirectX.Direct3D.Core.Memory 4 | { 5 | public class DisposableEventArgs : EventArgs 6 | { 7 | public static readonly DisposableEventArgs DisposingEventArgs = new DisposableEventArgs(true); 8 | 9 | public static readonly DisposableEventArgs NotDisposingEventArgs = new DisposableEventArgs(false); 10 | 11 | public readonly bool Disposing; 12 | 13 | private DisposableEventArgs(bool disposing) 14 | { 15 | Disposing = disposing; 16 | } 17 | 18 | public static DisposableEventArgs Get(bool disposing) 19 | { 20 | return disposing ? DisposingEventArgs : NotDisposingEventArgs; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D10.Overlay/DirectX.Direct3D10.Overlay.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.0 5 | 6 | 7 | 8 | $(OutputDir) 9 | 10 | 11 | 12 | $(OutputDir) 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D11.Overlay/Component.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SharpDX; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DirectX.Direct3D11.Overlay 9 | { 10 | public abstract class Component : ComponentBase, IDisposable 11 | { 12 | /// 13 | /// Gets or sets the disposables. 14 | /// 15 | /// The disposables. 16 | protected DisposeCollector DisposeCollector { get; set; } 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | protected internal Component() 22 | { 23 | } 24 | 25 | /// 26 | /// Initializes a new instance of the class with an immutable name. 27 | /// 28 | /// The name. 29 | protected Component(string name) : base(name) 30 | { 31 | } 32 | 33 | /// 34 | /// Gets or sets a value indicating whether this instance is attached to a collector. 35 | /// 36 | /// 37 | /// true if this instance is attached to a collector; otherwise, false. 38 | /// 39 | internal bool IsAttached { get; set; } 40 | 41 | /// 42 | /// Gets a value indicating whether this instance is disposed. 43 | /// 44 | /// 45 | /// true if this instance is disposed; otherwise, false. 46 | /// 47 | protected internal bool IsDisposed { get; private set; } 48 | 49 | protected internal bool IsDisposing { get; private set; } 50 | 51 | /// 52 | /// Occurs when when Dispose is called. 53 | /// 54 | public event EventHandler Disposing; 55 | 56 | /// 57 | /// Releases unmanaged and - optionally - managed resources 58 | /// 59 | public void Dispose() 60 | { 61 | if (!IsDisposed) 62 | { 63 | IsDisposing = true; 64 | 65 | // Call the disposing event. 66 | var handler = Disposing; 67 | if (handler != null) 68 | { 69 | handler(this, EventArgs.Empty); 70 | } 71 | 72 | Dispose(true); 73 | IsDisposed = true; 74 | } 75 | } 76 | 77 | /// 78 | /// Disposes of object resources. 79 | /// 80 | /// If true, managed resources should be 81 | /// disposed of in addition to unmanaged resources. 82 | protected virtual void Dispose(bool disposeManagedResources) 83 | { 84 | if (disposeManagedResources) 85 | { 86 | // Dispose all ComObjects 87 | if (DisposeCollector != null) 88 | DisposeCollector.Dispose(); 89 | DisposeCollector = null; 90 | } 91 | } 92 | 93 | /// 94 | /// Adds a disposable object to the list of the objects to dispose. 95 | /// 96 | /// To dispose. 97 | protected internal T ToDispose(T toDisposeArg) 98 | { 99 | if (!ReferenceEquals(toDisposeArg, null)) 100 | { 101 | if (DisposeCollector == null) 102 | DisposeCollector = new DisposeCollector(); 103 | return DisposeCollector.Collect(toDisposeArg); 104 | } 105 | return default(T); 106 | } 107 | 108 | /// 109 | /// Dispose a disposable object and set the reference to null. Removes this object from the ToDispose list. 110 | /// 111 | /// Object to dispose. 112 | protected internal void RemoveAndDispose(ref T objectToDispose) 113 | { 114 | if (!ReferenceEquals(objectToDispose, null) && DisposeCollector != null) 115 | DisposeCollector.RemoveAndDispose(ref objectToDispose); 116 | } 117 | 118 | /// 119 | /// Removes a disposable object to the list of the objects to dispose. 120 | /// 121 | /// 122 | /// To dispose. 123 | protected internal void RemoveToDispose(T toDisposeArg) 124 | { 125 | if (!ReferenceEquals(toDisposeArg, null) && DisposeCollector != null) 126 | DisposeCollector.Remove(toDisposeArg); 127 | } 128 | } 129 | } -------------------------------------------------------------------------------- /src/DirectX.Direct3D11.Overlay/ComponentBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | namespace DirectX.Direct3D11.Overlay 8 | { 9 | public abstract class ComponentBase : IComponent, INotifyPropertyChanged 10 | { 11 | /// 12 | /// Occurs while this component is disposing and before it is disposed. 13 | /// 14 | //internal event EventHandler Disposing; 15 | private string name; 16 | 17 | /// 18 | /// Gets or sets a value indicating whether the name of this instance is immutable. 19 | /// 20 | /// true if this instance is name immutable; otherwise, false. 21 | private readonly bool isNameImmutable; 22 | 23 | private object tag; 24 | 25 | /// 26 | /// Initializes a new instance of the class with a mutable name. 27 | /// 28 | protected ComponentBase() 29 | { 30 | } 31 | 32 | /// 33 | /// Initializes a new instance of the class with an immutable name. 34 | /// 35 | /// The name. 36 | protected ComponentBase(string name) 37 | { 38 | if (name != null) 39 | { 40 | this.name = name; 41 | this.isNameImmutable = true; 42 | } 43 | } 44 | 45 | /// 46 | /// Gets the name of this component. 47 | /// 48 | /// The name. 49 | [DefaultValue(null)] 50 | public string Name 51 | { 52 | get { return name; } 53 | set 54 | { 55 | if (isNameImmutable) 56 | throw new ArgumentException("Name property is immutable for this instance", "value"); 57 | if (name == value) return; 58 | name = value; 59 | OnPropertyChanged("Name"); 60 | } 61 | } 62 | 63 | /// 64 | /// Gets or sets the tag associated to this object. 65 | /// 66 | /// The tag. 67 | #if !W8CORE 68 | [Browsable(false)] 69 | #endif 70 | [DefaultValue(null)] 71 | public object Tag 72 | { 73 | get 74 | { 75 | return tag; 76 | } 77 | set 78 | { 79 | if (ReferenceEquals(tag, value)) return; 80 | tag = value; 81 | OnPropertyChanged("Tag"); 82 | } 83 | } 84 | 85 | /// 86 | /// Occurs when a property value changes. 87 | /// 88 | public event PropertyChangedEventHandler PropertyChanged; 89 | 90 | protected virtual void OnPropertyChanged(string propertyName) 91 | { 92 | PropertyChangedEventHandler handler = PropertyChanged; 93 | if (handler != null) 94 | { 95 | handler(this, new PropertyChangedEventArgs(propertyName)); 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D11.Overlay/DXFont.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using SharpDX.Direct3D11; 6 | using SharpDX; 7 | using System.Diagnostics; 8 | 9 | namespace DirectX.Direct3D11.Overlay 10 | { 11 | public class DXFont : IDisposable 12 | { 13 | Device _device; 14 | DeviceContext _deviceContext; 15 | 16 | public DXFont(Device device, DeviceContext deviceContext) 17 | { 18 | _device = device; 19 | _deviceContext = deviceContext; 20 | _initialized = false; 21 | _fontSheetTex = null; 22 | _fontSheetSRV = null; 23 | _texWidth = 1024; 24 | _texHeight = 0; 25 | _spaceWidth = 0; 26 | _charHeight = 0; 27 | } 28 | 29 | public void Dispose() 30 | { 31 | if (_fontSheetTex != null) 32 | _fontSheetTex.Dispose(); 33 | if (_fontSheetSRV != null) 34 | _fontSheetSRV.Dispose(); 35 | 36 | _fontSheetTex = null; 37 | _fontSheetSRV = null; 38 | _device = null; 39 | _deviceContext = null; 40 | } 41 | 42 | enum STYLE 43 | { 44 | STYLE_NORMAL = 0, 45 | STYLE_BOLD = 1, 46 | STYLE_ITALIC = 2, 47 | STYLE_BOLD_ITALIC = 3, 48 | STYLE_UNDERLINE = 4, 49 | STYLE_STRIKEOUT = 8 50 | }; 51 | 52 | bool _initialized; 53 | const char StartChar = (char)33; 54 | const char EndChar = (char)127; 55 | const uint NumChars = EndChar - StartChar; 56 | ShaderResourceView _fontSheetSRV; 57 | Texture2D _fontSheetTex; 58 | int _texWidth, _texHeight; 59 | Rectangle[] _charRects = new Rectangle[NumChars]; 60 | int _spaceWidth, _charHeight; 61 | 62 | public bool Initialize(string FontName, float FontSize, System.Drawing.FontStyle FontStyle, bool AntiAliased) 63 | { 64 | Debug.Assert(!_initialized); 65 | System.Drawing.Font font = new System.Drawing.Font(FontName, FontSize, FontStyle, System.Drawing.GraphicsUnit.Pixel); 66 | 67 | System.Drawing.Text.TextRenderingHint hint = AntiAliased ? System.Drawing.Text.TextRenderingHint.AntiAlias : System.Drawing.Text.TextRenderingHint.SystemDefault; 68 | 69 | int tempSize = (int)(FontSize * 2); 70 | using (System.Drawing.Bitmap charBitmap = new System.Drawing.Bitmap(tempSize, tempSize, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) 71 | { 72 | using (System.Drawing.Graphics charGraphics = System.Drawing.Graphics.FromImage(charBitmap)) 73 | { 74 | charGraphics.PageUnit = System.Drawing.GraphicsUnit.Pixel; 75 | charGraphics.TextRenderingHint = hint; 76 | 77 | MeasureChars(font, charGraphics); 78 | 79 | using (var fontSheetBitmap = new System.Drawing.Bitmap(_texWidth, _texHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) 80 | { 81 | using (var fontSheetGraphics = System.Drawing.Graphics.FromImage(fontSheetBitmap)) 82 | { 83 | fontSheetGraphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy; 84 | fontSheetGraphics.Clear(System.Drawing.Color.FromArgb(0, System.Drawing.Color.Black)); 85 | 86 | BuildFontSheetBitmap(font, charGraphics, charBitmap, fontSheetGraphics); 87 | 88 | if (!BuildFontSheetTexture(fontSheetBitmap)) 89 | { 90 | return false; 91 | } 92 | } 93 | } 94 | } 95 | } 96 | 97 | _initialized = true; 98 | 99 | return true; 100 | } 101 | 102 | private bool BuildFontSheetTexture(System.Drawing.Bitmap fontSheetBitmap) 103 | { 104 | System.Drawing.Imaging.BitmapData bmData; 105 | 106 | bmData = fontSheetBitmap.LockBits(new System.Drawing.Rectangle(0, 0, _texWidth, _texHeight), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); 107 | Texture2DDescription texDesc = new Texture2DDescription(); 108 | texDesc.Width = _texWidth; 109 | texDesc.Height = _texHeight; 110 | texDesc.MipLevels = 1; 111 | texDesc.ArraySize = 1; 112 | texDesc.Format = SharpDX.DXGI.Format.B8G8R8A8_UNorm; 113 | texDesc.SampleDescription.Count = 1; 114 | texDesc.SampleDescription.Quality = 0; 115 | texDesc.Usage = ResourceUsage.Immutable; 116 | texDesc.BindFlags = BindFlags.ShaderResource; 117 | texDesc.CpuAccessFlags = CpuAccessFlags.None; 118 | texDesc.OptionFlags = ResourceOptionFlags.None; 119 | 120 | 121 | SharpDX.DataBox data; 122 | data.DataPointer = bmData.Scan0; 123 | data.RowPitch = _texWidth * 4; 124 | data.SlicePitch = 0; 125 | 126 | _fontSheetTex = new Texture2D(_device, texDesc, new[] { data }); 127 | if (_fontSheetTex == null) 128 | return false; 129 | 130 | ShaderResourceViewDescription srvDesc = new ShaderResourceViewDescription(); 131 | srvDesc.Format = SharpDX.DXGI.Format.B8G8R8A8_UNorm; 132 | srvDesc.Dimension = SharpDX.Direct3D.ShaderResourceViewDimension.Texture2D; 133 | srvDesc.Texture2D.MipLevels = 1; 134 | srvDesc.Texture2D.MostDetailedMip = 0; 135 | 136 | _fontSheetSRV = new ShaderResourceView(_device, _fontSheetTex, srvDesc); 137 | if (_fontSheetSRV == null) 138 | return false; 139 | 140 | fontSheetBitmap.UnlockBits(bmData); 141 | 142 | return true; 143 | } 144 | 145 | void MeasureChars(System.Drawing.Font font, System.Drawing.Graphics charGraphics) 146 | { 147 | char[] allChars = new char[NumChars]; 148 | 149 | for (char i = (char)0; i < NumChars; ++i) 150 | allChars[i] = (char)(StartChar + i); 151 | 152 | System.Drawing.SizeF size; 153 | size = charGraphics.MeasureString(new String(allChars), font, new System.Drawing.PointF(0, 0), System.Drawing.StringFormat.GenericDefault); 154 | 155 | _charHeight = (int)(size.Height + 0.5f); 156 | 157 | int numRows = (int)(size.Width / _texWidth) + 1; 158 | _texHeight = (numRows * _charHeight) + 1; 159 | 160 | System.Drawing.StringFormat sf = System.Drawing.StringFormat.GenericDefault; 161 | sf.FormatFlags |= System.Drawing.StringFormatFlags.MeasureTrailingSpaces; 162 | size = charGraphics.MeasureString(" ", font, 0, sf); 163 | _spaceWidth = (int)(size.Width + 0.5f); 164 | } 165 | 166 | void BuildFontSheetBitmap(System.Drawing.Font font, System.Drawing.Graphics charGraphics, System.Drawing.Bitmap charBitmap, System.Drawing.Graphics fontSheetGraphics) 167 | { 168 | System.Drawing.Brush whiteBrush = System.Drawing.Brushes.White; 169 | int fontSheetX = 0; 170 | int fontSheetY = 0; 171 | 172 | 173 | for (int i = 0; i < NumChars; ++i) 174 | { 175 | charGraphics.Clear(System.Drawing.Color.FromArgb(0, System.Drawing.Color.Black)); 176 | charGraphics.DrawString(((char)(StartChar + i)).ToString(), font, whiteBrush, new System.Drawing.PointF(0.0f, 0.0f)); 177 | 178 | int minX = GetCharMinX(charBitmap); 179 | int maxX = GetCharMaxX(charBitmap); 180 | int charWidth = maxX - minX + 1; 181 | 182 | if (fontSheetX + charWidth >= _texWidth) 183 | { 184 | fontSheetX = 0; 185 | fontSheetY += (int)(_charHeight) + 1; 186 | } 187 | 188 | _charRects[i] = new Rectangle(fontSheetX, fontSheetY, charWidth, _charHeight); 189 | 190 | fontSheetGraphics.DrawImage(charBitmap, fontSheetX, fontSheetY, new System.Drawing.Rectangle(minX, 0, charWidth, _charHeight), System.Drawing.GraphicsUnit.Pixel); 191 | 192 | fontSheetX += charWidth + 1; 193 | } 194 | } 195 | 196 | private int GetCharMaxX(System.Drawing.Bitmap charBitmap) 197 | { 198 | int width = charBitmap.Width; 199 | int height = charBitmap.Height; 200 | 201 | for (int x = width - 1; x >= 0; --x) 202 | { 203 | for (int y = 0; y < height; ++y) 204 | { 205 | System.Drawing.Color color; 206 | 207 | color = charBitmap.GetPixel(x, y); 208 | if (color.A > 0) 209 | return x; 210 | } 211 | } 212 | 213 | return width - 1; 214 | } 215 | 216 | private int GetCharMinX(System.Drawing.Bitmap charBitmap) 217 | { 218 | int width = charBitmap.Width; 219 | int height = charBitmap.Height; 220 | 221 | for (int x = 0; x < width; ++x) 222 | { 223 | for (int y = 0; y < height; ++y) 224 | { 225 | System.Drawing.Color color; 226 | 227 | color = charBitmap.GetPixel(x, y); 228 | if (color.A > 0) 229 | return x; 230 | } 231 | } 232 | 233 | return 0; 234 | } 235 | 236 | public ShaderResourceView GetFontSheetSRV() 237 | { 238 | Debug.Assert(_initialized); 239 | 240 | return _fontSheetSRV; 241 | } 242 | 243 | public Rectangle GetCharRect(char c) 244 | { 245 | Debug.Assert(_initialized); 246 | 247 | return _charRects[c - StartChar]; 248 | } 249 | 250 | public int GetSpaceWidth() 251 | { 252 | Debug.Assert(_initialized); 253 | 254 | return _spaceWidth; 255 | } 256 | 257 | public int GetCharHeight() 258 | { 259 | Debug.Assert(_initialized); 260 | 261 | return _charHeight; 262 | } 263 | 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D11.Overlay/DXImage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using SharpDX.Direct3D11; 6 | using SharpDX; 7 | using System.Diagnostics; 8 | 9 | namespace DirectX.Direct3D11.Overlay 10 | { 11 | public class DXImage : Component 12 | { 13 | Device _device; 14 | DeviceContext _deviceContext; 15 | Texture2D _tex; 16 | ShaderResourceView _texSRV; 17 | int _texWidth, _texHeight; 18 | bool _initialised = false; 19 | 20 | public int Width 21 | { 22 | get 23 | { 24 | return _texWidth; 25 | } 26 | } 27 | 28 | public int Height 29 | { 30 | get 31 | { 32 | return _texHeight; 33 | } 34 | } 35 | 36 | public Device Device 37 | { 38 | get { return _device; } 39 | } 40 | 41 | public DXImage(Device device, DeviceContext deviceContext) : base("DXImage") 42 | { 43 | _device = device; 44 | _deviceContext = deviceContext; 45 | _tex = null; 46 | _texSRV = null; 47 | _texWidth = 0; 48 | _texHeight = 0; 49 | } 50 | 51 | public bool Initialise(System.Drawing.Bitmap bitmap) 52 | { 53 | RemoveAndDispose(ref _tex); 54 | RemoveAndDispose(ref _texSRV); 55 | 56 | //Debug.Assert(bitmap.PixelFormat == System.Drawing.Imaging.PixelFormat.Format32bppArgb); 57 | System.Drawing.Imaging.BitmapData bmData; 58 | 59 | _texWidth = bitmap.Width; 60 | _texHeight = bitmap.Height; 61 | 62 | bmData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, _texWidth, _texHeight), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); 63 | try 64 | { 65 | Texture2DDescription texDesc = new Texture2DDescription(); 66 | texDesc.Width = _texWidth; 67 | texDesc.Height = _texHeight; 68 | texDesc.MipLevels = 1; 69 | texDesc.ArraySize = 1; 70 | texDesc.Format = SharpDX.DXGI.Format.B8G8R8A8_UNorm; 71 | texDesc.SampleDescription.Count = 1; 72 | texDesc.SampleDescription.Quality = 0; 73 | texDesc.Usage = ResourceUsage.Immutable; 74 | texDesc.BindFlags = BindFlags.ShaderResource; 75 | texDesc.CpuAccessFlags = CpuAccessFlags.None; 76 | texDesc.OptionFlags = ResourceOptionFlags.None; 77 | 78 | SharpDX.DataBox data; 79 | data.DataPointer = bmData.Scan0; 80 | data.RowPitch = bmData.Stride;// _texWidth * 4; 81 | data.SlicePitch = 0; 82 | 83 | _tex = ToDispose(new Texture2D(_device, texDesc, new[] { data })); 84 | if (_tex == null) 85 | return false; 86 | 87 | ShaderResourceViewDescription srvDesc = new ShaderResourceViewDescription(); 88 | srvDesc.Format = SharpDX.DXGI.Format.B8G8R8A8_UNorm; 89 | srvDesc.Dimension = SharpDX.Direct3D.ShaderResourceViewDimension.Texture2D; 90 | srvDesc.Texture2D.MipLevels = 1; 91 | srvDesc.Texture2D.MostDetailedMip = 0; 92 | 93 | _texSRV = ToDispose(new ShaderResourceView(_device, _tex, srvDesc)); 94 | if (_texSRV == null) 95 | return false; 96 | } 97 | finally 98 | { 99 | bitmap.UnlockBits(bmData); 100 | } 101 | 102 | _initialised = true; 103 | 104 | return true; 105 | } 106 | 107 | public ShaderResourceView GetSRV() 108 | { 109 | Debug.Assert(_initialised); 110 | return _texSRV; 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D11.Overlay/DXSprite.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using SharpDX.Direct3D11; 6 | using SharpDX; 7 | using System.Diagnostics; 8 | using SharpDX.D3DCompiler; 9 | using System.Runtime.InteropServices; 10 | 11 | namespace DirectX.Direct3D11.Overlay 12 | { 13 | public class DXSprite : Component 14 | { 15 | Device _device; 16 | DeviceContext _deviceContext; 17 | 18 | public DXSprite(Device device, DeviceContext deviceContext) 19 | { 20 | _device = device; 21 | _deviceContext = deviceContext; 22 | } 23 | 24 | [StructLayout(LayoutKind.Sequential)] 25 | internal struct SpriteVertex 26 | { 27 | public Vector3 Pos; 28 | public Vector2 Tex; 29 | public Color4 Color; 30 | } 31 | 32 | [StructLayout(LayoutKind.Sequential)] 33 | internal struct Sprite 34 | { 35 | public Rectangle SrcRect; 36 | public Rectangle DestRect; 37 | public Color4 Color; 38 | public float Z; 39 | public float Angle; 40 | public float Scale; 41 | 42 | public Sprite(Rectangle sourceRect, Rectangle destRect, Color4 color) 43 | { 44 | SrcRect = sourceRect; 45 | DestRect = destRect; 46 | Color = color; 47 | Z = 0.0f; 48 | Angle = 0.0f; 49 | Scale = 1.0f; 50 | } 51 | } 52 | 53 | bool _initialized; 54 | BlendState _transparentBS; 55 | EffectTechnique _spriteTech; 56 | EffectShaderResourceVariable _spriteMap; 57 | ShaderResourceView _batchTexSRV; 58 | InputLayout _inputLayout; 59 | SharpDX.Direct3D11.Buffer _VB; 60 | SharpDX.Direct3D11.Buffer _IB; 61 | int _texWidth; 62 | int _texHeight; 63 | List _spriteList = new List(128); 64 | float _screenWidth; 65 | float _screenHeight; 66 | CompilationResult _compiledFX; 67 | Effect _effect; 68 | 69 | SafeHGlobal _indexBuffer = null; 70 | public bool Initialize() 71 | { 72 | Debug.Assert(!_initialized); 73 | 74 | #region Shaders 75 | string SpriteFX = @"Texture2D SpriteTex; 76 | SamplerState samLinear { 77 | Filter = MIN_MAG_MIP_LINEAR; 78 | AddressU = WRAP; 79 | AddressV = WRAP; 80 | }; 81 | struct VertexIn { 82 | float3 PosNdc : POSITION; 83 | float2 Tex : TEXCOORD; 84 | float4 Color : COLOR; 85 | }; 86 | struct VertexOut { 87 | float4 PosNdc : SV_POSITION; 88 | float2 Tex : TEXCOORD; 89 | float4 Color : COLOR; 90 | }; 91 | VertexOut VS(VertexIn vin) { 92 | VertexOut vout; 93 | vout.PosNdc = float4(vin.PosNdc, 1.0f); 94 | vout.Tex = vin.Tex; 95 | vout.Color = vin.Color; 96 | return vout; 97 | }; 98 | float4 PS(VertexOut pin) : SV_Target { 99 | return pin.Color*SpriteTex.Sample(samLinear, pin.Tex); 100 | }; 101 | technique11 SpriteTech { 102 | pass P0 { 103 | SetVertexShader( CompileShader( vs_5_0, VS() ) ); 104 | SetHullShader( NULL ); 105 | SetDomainShader( NULL ); 106 | SetGeometryShader( NULL ); 107 | SetPixelShader( CompileShader( ps_5_0, PS() ) ); 108 | } 109 | };"; 110 | #endregion 111 | 112 | _compiledFX = ToDispose(ShaderBytecode.Compile(SpriteFX, "SpriteTech", "fx_5_0")); 113 | { 114 | 115 | if (_compiledFX.HasErrors) 116 | return false; 117 | 118 | _effect = ToDispose(new Effect(_device, _compiledFX)); 119 | { 120 | _spriteTech = ToDispose(_effect.GetTechniqueByName("SpriteTech")); 121 | _spriteMap = ToDispose(_effect.GetVariableByName("SpriteTex").AsShaderResource()); 122 | 123 | using (var pass = _spriteTech.GetPassByIndex(0)) 124 | { 125 | InputElement[] layoutDesc = { 126 | new InputElement("POSITION", 0, SharpDX.DXGI.Format.R32G32B32_Float, 0, 0, InputClassification.PerVertexData, 0), 127 | new InputElement("TEXCOORD", 0, SharpDX.DXGI.Format.R32G32_Float, 12, 0, InputClassification.PerVertexData, 0), 128 | new InputElement("COLOR", 0, SharpDX.DXGI.Format.R32G32B32A32_Float, 20, 0, InputClassification.PerVertexData, 0) 129 | }; 130 | 131 | _inputLayout = ToDispose(new InputLayout(_device, pass.Description.Signature, layoutDesc)); 132 | } 133 | // Create Vertex Buffer 134 | BufferDescription vbd = new BufferDescription 135 | { 136 | SizeInBytes = 2048 * Marshal.SizeOf(typeof(SpriteVertex)), 137 | Usage = ResourceUsage.Dynamic, 138 | BindFlags = BindFlags.VertexBuffer, 139 | CpuAccessFlags = CpuAccessFlags.Write, 140 | OptionFlags = ResourceOptionFlags.None, 141 | StructureByteStride = 0 142 | }; 143 | 144 | _VB = ToDispose(new SharpDX.Direct3D11.Buffer(_device, vbd)); 145 | 146 | // Create and initialise Index Buffer 147 | 148 | short[] indices = new short[3072]; 149 | 150 | for (ushort i = 0; i < 512; ++i) 151 | { 152 | indices[i * 6] = (short)(i * 4); 153 | indices[i * 6 + 1] = (short)(i * 4 + 1); 154 | indices[i * 6 + 2] = (short)(i * 4 + 2); 155 | indices[i * 6 + 3] = (short)(i * 4); 156 | indices[i * 6 + 4] = (short)(i * 4 + 2); 157 | indices[i * 6 + 5] = (short)(i * 4 + 3); 158 | } 159 | 160 | _indexBuffer = ToDispose(new SafeHGlobal(indices.Length * Marshal.SizeOf(indices[0]))); 161 | Marshal.Copy(indices, 0, _indexBuffer.DangerousGetHandle(), indices.Length); 162 | 163 | BufferDescription ibd = new BufferDescription 164 | { 165 | SizeInBytes = 3072 * Marshal.SizeOf(typeof(short)), 166 | Usage = ResourceUsage.Immutable, 167 | BindFlags = BindFlags.IndexBuffer, 168 | CpuAccessFlags = CpuAccessFlags.None, 169 | OptionFlags = ResourceOptionFlags.None, 170 | StructureByteStride = 0 171 | }; 172 | 173 | _IB = ToDispose(new SharpDX.Direct3D11.Buffer(_device, _indexBuffer.DangerousGetHandle(), ibd)); 174 | 175 | BlendStateDescription transparentDesc = new BlendStateDescription() 176 | { 177 | AlphaToCoverageEnable = false, 178 | IndependentBlendEnable = false, 179 | }; 180 | transparentDesc.RenderTarget[0].IsBlendEnabled = true; 181 | transparentDesc.RenderTarget[0].SourceBlend = BlendOption.SourceAlpha; 182 | transparentDesc.RenderTarget[0].DestinationBlend = BlendOption.InverseSourceAlpha; 183 | transparentDesc.RenderTarget[0].BlendOperation = BlendOperation.Add; 184 | transparentDesc.RenderTarget[0].SourceAlphaBlend = BlendOption.One; 185 | transparentDesc.RenderTarget[0].DestinationAlphaBlend = BlendOption.Zero; 186 | transparentDesc.RenderTarget[0].AlphaBlendOperation = BlendOperation.Add; 187 | transparentDesc.RenderTarget[0].RenderTargetWriteMask = ColorWriteMaskFlags.All; 188 | 189 | _transparentBS = ToDispose(new BlendState(_device, transparentDesc)); 190 | } 191 | } 192 | 193 | _initialized = true; 194 | 195 | return true; 196 | } 197 | 198 | internal static Color4 ToColor4(System.Drawing.Color color) 199 | { 200 | Vector4 Vec = new Vector4(color.R > 0 ? (float)(color.R / 255.0f) : 0.0f, color.G > 0 ? (float)(color.G / 255.0f) : 0.0f, color.B > 0 ? (float)(color.B / 255.0f) : 0.0f, color.A > 0 ? (float)(color.A / 255.0f) : 0.0f); 201 | return new Color4(Vec); 202 | } 203 | 204 | public void DrawImage(int x, int y, float scale, float angle, System.Drawing.Color? color, DXImage image) 205 | { 206 | Debug.Assert(_initialized); 207 | 208 | Color4 blendFactor = new Color4(1.0f); 209 | SharpDX.Mathematics.Interop.RawColor4 backupBlendFactor; 210 | int backupMask; 211 | using (var backupBlendState = _deviceContext.OutputMerger.GetBlendState(out backupBlendFactor, out backupMask)) 212 | { 213 | _deviceContext.OutputMerger.SetBlendState(_transparentBS, blendFactor); 214 | 215 | BeginBatch(image.GetSRV()); 216 | 217 | Draw(new Rectangle(x, y, (int)(scale * image.Width), (int)(scale * image.Height)), new Rectangle(0, 0, image.Width, image.Height), color.HasValue ? ToColor4(color.Value) : Color4.White, 1.0f, angle); 218 | 219 | EndBatch(); 220 | _deviceContext.OutputMerger.SetBlendState(backupBlendState, backupBlendFactor, backupMask); 221 | } 222 | } 223 | 224 | public void DrawString(int X, int Y, string text, System.Drawing.Color color, DXFont F) 225 | { 226 | Color4 blendFactor = new Color4(1.0f); 227 | SharpDX.Mathematics.Interop.RawColor4 backupBlendFactor; 228 | int backupMask; 229 | using (var backupBlendState = _deviceContext.OutputMerger.GetBlendState(out backupBlendFactor, out backupMask)) 230 | { 231 | _deviceContext.OutputMerger.SetBlendState(_transparentBS, blendFactor); 232 | 233 | BeginBatch(F.GetFontSheetSRV()); 234 | 235 | 236 | int length = text.Length; 237 | 238 | int posX = X; 239 | int posY = Y; 240 | 241 | Color4 color4 = ToColor4(color); 242 | 243 | for (int i = 0; i < length; ++i) 244 | { 245 | char character = text[i]; 246 | 247 | if (character == ' ') 248 | posX += F.GetSpaceWidth(); 249 | else if (character == '\n') 250 | { 251 | posX = X; 252 | posY += F.GetCharHeight(); 253 | } 254 | else 255 | { 256 | Rectangle charRect = F.GetCharRect(character); 257 | 258 | int width = charRect.Right - charRect.Left; 259 | int height = charRect.Bottom - charRect.Top; 260 | 261 | Draw(new Rectangle(posX, posY, width, height), charRect, color4); 262 | 263 | posX += width + 1; 264 | } 265 | } 266 | 267 | EndBatch(); 268 | _deviceContext.OutputMerger.SetBlendState(backupBlendState, backupBlendFactor, backupMask); 269 | } 270 | } 271 | 272 | public void BeginBatch(ShaderResourceView texSRV) 273 | { 274 | Debug.Assert(_initialized); 275 | 276 | _batchTexSRV = texSRV; 277 | 278 | Texture2D tex = _batchTexSRV.ResourceAs(); 279 | { 280 | 281 | Texture2DDescription texDesc = tex.Description; 282 | _texWidth = texDesc.Width; 283 | _texHeight = texDesc.Height; 284 | } 285 | _spriteList.Clear(); 286 | } 287 | 288 | public void EndBatch() 289 | { 290 | Debug.Assert(_initialized); 291 | 292 | ViewportF[] vp = _deviceContext.Rasterizer.GetViewports(); 293 | 294 | _screenWidth = vp[0].Width; 295 | _screenHeight = vp[0].Height; 296 | 297 | int stride = Marshal.SizeOf(typeof(SpriteVertex)); 298 | int offset = 0; 299 | _deviceContext.InputAssembler.InputLayout = _inputLayout; 300 | _deviceContext.InputAssembler.SetIndexBuffer(_IB, SharpDX.DXGI.Format.R16_UInt, 0); 301 | _deviceContext.InputAssembler.SetVertexBuffers(0, new[] { _VB }, new[] { stride }, new[] { offset }); 302 | _deviceContext.InputAssembler.PrimitiveTopology = SharpDX.Direct3D.PrimitiveTopology.TriangleList; 303 | _spriteMap.SetResource(_batchTexSRV); 304 | 305 | using (EffectPass pass = _spriteTech.GetPassByIndex(0)) 306 | { 307 | pass.Apply(_deviceContext); 308 | var spritesToDraw = _spriteList.Count; 309 | int startIndex = 0; 310 | while (spritesToDraw > 0) 311 | { 312 | if (spritesToDraw <= 512) 313 | { 314 | DrawBatch(startIndex, spritesToDraw); 315 | spritesToDraw = 0; 316 | } 317 | else 318 | { 319 | DrawBatch(startIndex, 512); 320 | startIndex += 512; 321 | spritesToDraw -= 512; 322 | } 323 | } 324 | } 325 | _batchTexSRV = null; 326 | } 327 | 328 | public void Draw(Rectangle destinationRect, Rectangle sourceRect, Color4 color, float scale = 1.0f, float angle = 0f, float z = 0f) 329 | { 330 | Sprite sprite = new Sprite( 331 | sourceRect, 332 | destinationRect, 333 | color 334 | ) 335 | { 336 | Scale = scale, 337 | Angle = angle, 338 | Z = z 339 | }; 340 | 341 | _spriteList.Add(sprite); 342 | } 343 | 344 | void DrawBatch(int startSpriteIndex, int spriteCount) 345 | { 346 | DataBox mappedData = _deviceContext.MapSubresource(_VB, 0, MapMode.WriteDiscard, MapFlags.None); 347 | 348 | // Update the vertices 349 | unsafe 350 | { 351 | SpriteVertex* v = (SpriteVertex*)mappedData.DataPointer.ToPointer(); 352 | 353 | for (int i = 0; i < spriteCount; ++i) 354 | { 355 | Sprite sprite = _spriteList[startSpriteIndex + i]; 356 | 357 | SpriteVertex[] quad = new SpriteVertex[4]; 358 | 359 | BuildSpriteQuad(sprite, ref quad); 360 | 361 | v[i * 4] = quad[0]; 362 | v[i * 4 + 1] = quad[1]; 363 | v[i * 4 + 2] = quad[2]; 364 | v[i * 4 + 3] = quad[3]; 365 | } 366 | } 367 | 368 | _deviceContext.UnmapSubresource(_VB, 0); 369 | 370 | _deviceContext.DrawIndexed(spriteCount * 6, 0, 0); 371 | } 372 | 373 | Vector3 PointToNdc(int x, int y, float z) 374 | { 375 | Vector3 p; 376 | 377 | p.X = 2.0f * (float)x / _screenWidth - 1.0f; 378 | p.Y = 1.0f - 2.0f * (float)y / _screenHeight; 379 | p.Z = z; 380 | 381 | return p; 382 | } 383 | 384 | void BuildSpriteQuad(Sprite sprite, ref SpriteVertex[] v) 385 | { 386 | if (v.Length < 4) 387 | throw new ArgumentException("must have 4 sprite vertices", "v"); 388 | 389 | Rectangle dest = sprite.DestRect; 390 | Rectangle src = sprite.SrcRect; 391 | 392 | v[0].Pos = PointToNdc(dest.Left, dest.Bottom, sprite.Z); 393 | v[1].Pos = PointToNdc(dest.Left, dest.Top, sprite.Z); 394 | v[2].Pos = PointToNdc(dest.Right, dest.Top, sprite.Z); 395 | v[3].Pos = PointToNdc(dest.Right, dest.Bottom, sprite.Z); 396 | 397 | v[0].Tex = new Vector2((float)src.Left / _texWidth, (float)src.Bottom / _texHeight); 398 | v[1].Tex = new Vector2((float)src.Left / _texWidth, (float)src.Top / _texHeight); 399 | v[2].Tex = new Vector2((float)src.Right / _texWidth, (float)src.Top / _texHeight); 400 | v[3].Tex = new Vector2((float)src.Right / _texWidth, (float)src.Bottom / _texHeight); 401 | 402 | v[0].Color = sprite.Color; 403 | v[1].Color = sprite.Color; 404 | v[2].Color = sprite.Color; 405 | v[3].Color = sprite.Color; 406 | 407 | float tx = 0.5f * (v[0].Pos.X + v[3].Pos.X); 408 | float ty = 0.5f * (v[0].Pos.Y + v[1].Pos.Y); 409 | 410 | Vector2 origin = new Vector2(tx, ty); 411 | Vector2 translation = new Vector2(0.0f, 0.0f); 412 | 413 | Matrix T = Matrix.AffineTransformation2D(sprite.Scale, origin, sprite.Angle, translation); 414 | 415 | for (int i = 0; i < 4; ++i) 416 | { 417 | Vector3 p = v[i].Pos; 418 | p = Vector3.TransformCoordinate(p, T); 419 | v[i].Pos = p; 420 | } 421 | } 422 | } 423 | } -------------------------------------------------------------------------------- /src/DirectX.Direct3D11.Overlay/Direct3DHookModule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.InteropServices; 4 | using System.Drawing; 5 | using CoreHook; 6 | using DirectX.Direct3D.Core.Drawing; 7 | using DirectX.Direct3D.Core; 8 | using SharpDX.Direct3D; 9 | using SharpDX.Direct3D11; 10 | using SharpDX.DXGI; 11 | using Device = SharpDX.Direct3D11.Device; 12 | 13 | namespace DirectX.Direct3D11.Overlay 14 | { 15 | internal class Direct3DHookModule : Direct3DHook 16 | { 17 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] 18 | delegate int DXGISwapChain_PresentDelegate(IntPtr swapChain, int syncInterval, PresentFlags flags); 19 | 20 | private IHook _d3DPresentHook; 21 | private List _d3DDeviceFunctions = new List(); 22 | private OverlayRenderer _overlayRenderer; 23 | 24 | public const int DXGI_SWAPCHAIN_METHOD_COUNT = 18; 25 | Device _device; 26 | SwapChain _swapChain; 27 | 28 | private IntPtr _swapChainPtr; 29 | 30 | private static SwapChainDescription CreateSwapChainDescription(IntPtr windowHandle) 31 | { 32 | return new SwapChainDescription 33 | { 34 | BufferCount = 1, 35 | Flags = SwapChainFlags.None, 36 | IsWindowed = true, 37 | ModeDescription = new ModeDescription(100, 100, new Rational(60, 1), Format.R8G8B8A8_UNorm), 38 | OutputHandle = windowHandle, 39 | SampleDescription = new SampleDescription(1, 0), 40 | SwapEffect = SwapEffect.Discard, 41 | Usage = Usage.RenderTargetOutput 42 | }; 43 | } 44 | 45 | public override void CreateHooks() 46 | { 47 | var renderForm = new SharpDX.Windows.RenderForm(); 48 | Device.CreateWithSwapChain( 49 | DriverType.Hardware, 50 | DeviceCreationFlags.BgraSupport, 51 | CreateSwapChainDescription(renderForm.Handle), 52 | out _device, 53 | out _swapChain); 54 | 55 | if (_swapChain != null) 56 | { 57 | _d3DDeviceFunctions.AddRange(ReadVTableAddresses(_swapChain.NativePointer, DXGI_SWAPCHAIN_METHOD_COUNT)); 58 | } 59 | 60 | _d3DPresentHook = HookFactory.CreateHook( 61 | _d3DDeviceFunctions[(int)FunctionOrdinals.Present], 62 | Detour_Present, 63 | this); 64 | 65 | Overlays = new List 66 | { 67 | // Add the Frames Per Second overlay 68 | new Direct3D.Core.Drawing.Overlay 69 | { 70 | Elements = 71 | { 72 | new FramesPerSecondOverlay(new Font("Arial", 16, FontStyle.Bold)) 73 | { 74 | Location = new Point(25, 25), 75 | Color = Color.Red, 76 | AntiAliased = true, 77 | Text = "{0:N0} FPS" 78 | } 79 | }, 80 | Hidden = false 81 | } 82 | }; 83 | 84 | _d3DPresentHook.Enabled = true; 85 | } 86 | 87 | private static IEnumerable ReadVTableAddresses(IntPtr vTableAddress, int vTableFunctionCount) 88 | { 89 | IntPtr[] addresses = new IntPtr[vTableFunctionCount]; 90 | IntPtr vTable = Marshal.ReadIntPtr(vTableAddress); 91 | for (var i = 0; i < vTableFunctionCount; ++i) 92 | { 93 | addresses[i] = Marshal.ReadIntPtr(vTable, i * IntPtr.Size); 94 | } 95 | return addresses; 96 | } 97 | 98 | private int Detour_Present(IntPtr swapChainPtr, int syncInterval, SharpDX.DXGI.PresentFlags flags) 99 | { 100 | SwapChain swapChain = (SwapChain)swapChainPtr; 101 | 102 | DrawFramesPerSecond(swapChain); 103 | 104 | return _d3DPresentHook.Original(swapChainPtr, syncInterval, flags); 105 | } 106 | 107 | private void DrawFramesPerSecond(SwapChain swapChain) 108 | { 109 | Capture(swapChain); 110 | } 111 | 112 | private void Capture(SwapChain swapChain) 113 | { 114 | 115 | try 116 | { 117 | // Draw any overlays 118 | var displayOverlays = Overlays; 119 | 120 | if (_overlayRenderer == null || 121 | _swapChainPtr != swapChain.NativePointer || 122 | PendingUpdate) 123 | { 124 | if (_overlayRenderer != null) 125 | { 126 | _overlayRenderer.Dispose(); 127 | } 128 | 129 | _swapChainPtr = swapChain.NativePointer; 130 | 131 | _overlayRenderer = ToDispose((new OverlayRenderer())); 132 | _overlayRenderer.Overlays.AddRange(displayOverlays); 133 | _overlayRenderer.Initialize(swapChain); 134 | PendingUpdate = false; 135 | } 136 | 137 | if (_overlayRenderer != null) 138 | { 139 | foreach (var overlay in _overlayRenderer.Overlays) 140 | { 141 | overlay.OnFrame(); 142 | } 143 | 144 | _overlayRenderer.DrawFrame(); 145 | } 146 | } 147 | catch (Exception e) 148 | { 149 | System.Diagnostics.Debug.WriteLine(e.ToString()); 150 | } 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D11.Overlay/DirectX.Direct3D11.Overlay.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.0 5 | 6 | 7 | 8 | true 9 | $(OutputDir) 10 | 11 | 12 | 13 | true 14 | $(OutputDir) 15 | 16 | 17 | 18 | false 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D11.Overlay/EntryPoint.cs: -------------------------------------------------------------------------------- 1 | using CoreHook; 2 | using DirectX.Direct3D.Core; 3 | 4 | namespace DirectX.Direct3D11.Overlay 5 | { 6 | public class EntryPoint : IEntryPoint 7 | { 8 | private Direct3DHook _direct3DHook; 9 | 10 | public EntryPoint(IContext context) { } 11 | 12 | public void Run(IContext context) 13 | { 14 | InitializeDeviceHook(); 15 | while (true) 16 | { 17 | System.Threading.Thread.Sleep(30000); 18 | } 19 | } 20 | 21 | private void InitializeDeviceHook() 22 | { 23 | _direct3DHook = new Direct3DHookModule(); 24 | _direct3DHook.CreateHooks(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D11.Overlay/FunctionOrdinals.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DirectX.Direct3D11.Overlay 6 | { 7 | public enum FunctionOrdinals : short 8 | { 9 | // IUnknown 10 | QueryInterface = 0, 11 | AddRef = 1, 12 | Release = 2, 13 | 14 | // IDXGIObject 15 | SetPrivateData = 3, 16 | SetPrivateDataInterface = 4, 17 | GetPrivateData = 5, 18 | GetParent = 6, 19 | 20 | // IDXGIDeviceSubObject 21 | GetDevice = 7, 22 | 23 | // IDXGISwapChain 24 | Present = 8, 25 | GetBuffer = 9, 26 | SetFullscreenState = 10, 27 | GetFullscreenState = 11, 28 | GetDesc = 12, 29 | ResizeBuffers = 13, 30 | ResizeTarget = 14, 31 | GetContainingOutput = 15, 32 | GetFrameStatistics = 16, 33 | GetLastPresentCount = 17, 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D11.Overlay/IComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DirectX.Direct3D11.Overlay 6 | { 7 | 8 | public interface IComponent 9 | { 10 | /// 11 | /// Gets the name of this component. 12 | /// 13 | /// The name. 14 | string Name { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/DirectX.Direct3D11.Overlay/OverlayRenderer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using DirectX.Direct3D.Core.Drawing; 5 | using DirectX.Direct3D.Core.Memory; 6 | using SharpDX; 7 | using SharpDX.Direct3D11; 8 | 9 | namespace DirectX.Direct3D11.Overlay 10 | { 11 | internal class OverlayRenderer : DisposableComponent 12 | { 13 | public List Overlays { get; set; } = new List(); 14 | private Device _device; 15 | private Texture2D _renderTarget; 16 | private RenderTargetView _renderTargetView; 17 | private DXSprite _spriteEngine; 18 | Dictionary _fontCache = new Dictionary(); 19 | private DeviceContext _deviceContext; 20 | //private readonly Dictionary _fontCache = new Dictionary(); 21 | public bool DeferredContext 22 | { 23 | get => _deviceContext.TypeInfo == DeviceContextType.Deferred; 24 | } 25 | 26 | 27 | 28 | public Device Device => _device; 29 | 30 | private bool _isInitialized; 31 | private bool _isInitializing; 32 | 33 | internal OverlayRenderer() 34 | { 35 | } 36 | 37 | private void EnsureInitialized() 38 | { 39 | System.Diagnostics.Debug.Assert(_isInitialized); 40 | } 41 | 42 | internal bool Initialize(SharpDX.DXGI.SwapChain swapChain) 43 | { 44 | return Initialize(swapChain.GetDevice(), swapChain.GetBackBuffer(0)); 45 | } 46 | 47 | internal bool Initialize(Device device, Texture2D renderTarget) 48 | { 49 | if (_isInitializing) 50 | { 51 | return false; 52 | } 53 | 54 | _isInitializing = true; 55 | 56 | try 57 | { 58 | _device = device; 59 | _renderTarget = renderTarget; 60 | try 61 | { 62 | _deviceContext = ToDispose(new DeviceContext(_device)); 63 | } 64 | catch(SharpDXException) 65 | { 66 | _deviceContext = _device.ImmediateContext; 67 | } 68 | 69 | _renderTargetView = ToDispose(new RenderTargetView(_device, _renderTarget)); 70 | _spriteEngine = new DXSprite(_device, _deviceContext); 71 | if(!_spriteEngine.Initialize()) 72 | { 73 | return false; 74 | } 75 | 76 | InitializeResources(); 77 | 78 | _isInitialized = true; 79 | } 80 | finally 81 | { 82 | _isInitializing = true; 83 | } 84 | return true; 85 | } 86 | 87 | private void InitializeResources() 88 | { 89 | foreach (var overlay in Overlays) 90 | { 91 | foreach (var overlayElement in overlay.Elements) 92 | { 93 | if (overlayElement is TextOverlay textOverlay) 94 | { 95 | GetOverlayFont(textOverlay); 96 | } 97 | } 98 | } 99 | } 100 | 101 | private DXFont GetOverlayFont(TextOverlay textOverlay) 102 | { 103 | string fontKey = 104 | $"{textOverlay.Font.Name}{textOverlay.Font.Size}{textOverlay.Font.Style}{textOverlay.AntiAliased}"; 105 | 106 | if (!_fontCache.TryGetValue(fontKey, out DXFont overlayFont)) 107 | { 108 | overlayFont = ToDispose(new DXFont(_device, _deviceContext)); 109 | overlayFont.Initialize(textOverlay.Font.Name, textOverlay.Font.Size, textOverlay.Font.Style, textOverlay.AntiAliased); 110 | _fontCache[fontKey] = overlayFont; 111 | } 112 | return overlayFont; 113 | } 114 | 115 | public void DrawFrame() 116 | { 117 | EnsureInitialized(); 118 | 119 | BeginFrame(); 120 | 121 | foreach (var overlay in Overlays) 122 | { 123 | foreach (var overlayElement in overlay.Elements) 124 | { 125 | if (overlayElement.Hidden) 126 | { 127 | continue; 128 | } 129 | 130 | if (overlayElement is TextOverlay textOverlay) 131 | { 132 | var font = GetOverlayFont(textOverlay); 133 | if (font != null && !string.IsNullOrEmpty(textOverlay.Text)) 134 | { 135 | _spriteEngine.DrawString(textOverlay.Location.X, textOverlay.Location.Y, textOverlay.Text, 136 | textOverlay.Color, font); 137 | } 138 | } 139 | } 140 | } 141 | 142 | EndFrame(); 143 | } 144 | 145 | private void BeginFrame() 146 | { 147 | SharpDX.Mathematics.Interop.RawViewportF[] viewport = 148 | { 149 | new ViewportF(0, 0, _renderTarget.Description.Width, _renderTarget.Description.Height, 0, 1) 150 | }; 151 | _deviceContext.Rasterizer.SetViewports(viewport); 152 | _deviceContext.OutputMerger.SetTargets(_renderTargetView); 153 | } 154 | 155 | private void EndFrame() 156 | { 157 | if(DeferredContext) 158 | { 159 | var commands = _deviceContext.FinishCommandList(true); 160 | _device.ImmediateContext.ExecuteCommandList(commands, true); 161 | commands.Dispose(); 162 | } 163 | } 164 | protected override void Dispose(bool disposing) 165 | { 166 | _device = null; 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D11.Overlay/SafeHGlobal.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | 7 | namespace DirectX.Direct3D11.Overlay 8 | { 9 | /// 10 | /// Provides a safe handle around a block of unmanaged memory. 11 | /// 12 | public class SafeHGlobal : SafeHandle 13 | { 14 | /// 15 | /// When overridden in a derived class, gets a value indicating whether the handle value is invalid. 16 | /// 17 | /// true if the handle value is invalid; otherwise, false. 18 | public override bool IsInvalid 19 | { 20 | get { return handle == IntPtr.Zero; } 21 | } 22 | 23 | /// 24 | /// Initializes a new instance of the class. 25 | /// 26 | /// The size of the block of memory to allocate, in bytes. 27 | public SafeHGlobal(int sizeInBytes) 28 | : base(Marshal.AllocHGlobal(sizeInBytes), true) 29 | { 30 | } 31 | 32 | /// 33 | /// When overridden in a derived class, executes the code required to free the handle. 34 | /// 35 | /// 36 | /// true if the handle is released successfully; otherwise, in the event of a catastrophic failure, false. In this case, it generates a releaseHandleFailed MDA Managed Debugging Assistant. 37 | /// 38 | protected override bool ReleaseHandle() 39 | { 40 | Marshal.FreeHGlobal(handle); 41 | return true; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D9.Overlay/Direct3DHookModule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Runtime.InteropServices; 5 | using DirectX.Direct3D.Core; 6 | using CoreHook; 7 | using DirectX.Direct3D.Core.Drawing; 8 | using SharpDX; 9 | using SharpDX.Direct3D9; 10 | using Color = System.Drawing.Color; 11 | using Font = SharpDX.Direct3D9.Font; 12 | using Rectangle = SharpDX.Rectangle; 13 | 14 | namespace DirectX.Direct3D9.Overlay 15 | { 16 | internal class Direct3DHookModule : Direct3DHook 17 | { 18 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] 19 | unsafe delegate int IDirect3DDevice9_PresentDelegate(IntPtr device, Rectangle* sourceRectangle, 20 | Rectangle* destRectangle, IntPtr destWindowOverride, IntPtr dirtyRegion); 21 | 22 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] 23 | private delegate int IDirect3DDevice9_EndSceneDelegate(IntPtr device); 24 | 25 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] 26 | private delegate int IDirect3DDevice9_ResetDelegate(IntPtr device, ref PresentParameters parameters); 27 | 28 | private IHook _d3DPresentHook; 29 | private IHook _d3DEndSceneHook; 30 | private IHook _d3DResetHook; 31 | 32 | private OverlayRenderer _overlayRenderer; 33 | private List _d3DDeviceFunctions = new List(); 34 | private const int D3DDevice9FunctionCount = 119; 35 | private bool _isUsingPresentHook = false; 36 | 37 | public override unsafe void CreateHooks() 38 | { 39 | _d3DDeviceFunctions = new List(); 40 | 41 | using (var direct3D = new SharpDX.Direct3D9.Direct3D()) 42 | { 43 | using (var device = new Device(direct3D, 0, DeviceType.NullReference, IntPtr.Zero, 44 | CreateFlags.HardwareVertexProcessing, 45 | new PresentParameters { BackBufferWidth = 1, BackBufferHeight = 1, DeviceWindowHandle = IntPtr.Zero })) 46 | { 47 | _d3DDeviceFunctions.AddRange(ReadVTableAddresses(device.NativePointer, D3DDevice9FunctionCount)); 48 | } 49 | } 50 | 51 | // Create the hooks for our target Direct3D Device functions. 52 | _d3DEndSceneHook = HookFactory.CreateHook( 53 | _d3DDeviceFunctions[(int)FunctionOrdinals.EndScene], 54 | Detour_EndScene, 55 | this); 56 | 57 | _d3DPresentHook = HookFactory.CreateHook( 58 | _d3DDeviceFunctions[(int) FunctionOrdinals.Present], 59 | Detour_Present, 60 | this); 61 | 62 | _d3DResetHook = HookFactory.CreateHook( 63 | _d3DDeviceFunctions[(int)FunctionOrdinals.Reset], 64 | Detour_Reset, 65 | this); 66 | 67 | // Add the Frames Per Second overlay. 68 | Overlays = new List 69 | { 70 | new Direct3D.Core.Drawing.Overlay 71 | { 72 | Elements = 73 | { 74 | new FramesPerSecondOverlay(new System.Drawing.Font("Arial", 16, FontStyle.Bold)) 75 | { 76 | Location = new System.Drawing.Point(25, 25), 77 | Color = Color.Red, 78 | AntiAliased = true, 79 | Text = "{0:N0} FPS" 80 | } 81 | }, 82 | Hidden = false 83 | } 84 | }; 85 | 86 | // Enable the hooks for all threads except the current thread. 87 | _d3DEndSceneHook.ThreadACL.SetExclusiveACL(new int[1]); 88 | _d3DPresentHook.ThreadACL.SetExclusiveACL(new int[1]); 89 | _d3DResetHook.ThreadACL.SetExclusiveACL(new int[1]); 90 | } 91 | 92 | private static IEnumerable ReadVTableAddresses(IntPtr vTableAddress, int vTableFunctionCount) 93 | { 94 | IntPtr[] addresses = new IntPtr[vTableFunctionCount]; 95 | IntPtr vTable = Marshal.ReadIntPtr(vTableAddress); 96 | for (var i = 0; i < vTableFunctionCount; ++i) 97 | { 98 | addresses[i] = Marshal.ReadIntPtr(vTable, i * IntPtr.Size); 99 | } 100 | return addresses; 101 | } 102 | 103 | private unsafe int Detour_Present( 104 | IntPtr device, 105 | Rectangle* sourceRectangle, 106 | Rectangle* destRectangle, 107 | IntPtr destWindowOverride, 108 | IntPtr dirtyRegion) 109 | { 110 | _isUsingPresentHook = true; 111 | 112 | Device d3Device = (Device)device; 113 | DrawFramesPerSecond(d3Device); 114 | 115 | return _d3DPresentHook.Original(device, sourceRectangle, destRectangle, destWindowOverride, dirtyRegion); 116 | } 117 | 118 | private int Detour_EndScene(IntPtr direct3DDevice) 119 | { 120 | Device device = (Device)direct3DDevice; 121 | 122 | if (!_isUsingPresentHook) 123 | { 124 | DrawFramesPerSecond(device); 125 | } 126 | 127 | device.EndScene(); 128 | 129 | return Result.Ok.Code; 130 | } 131 | 132 | private int Detour_Reset(IntPtr direct3DDevice, ref PresentParameters parameters) 133 | { 134 | _overlayRenderer?.ResetDeviceResources(); 135 | 136 | return _d3DResetHook.Original(direct3DDevice, ref parameters); 137 | } 138 | 139 | private void DrawFramesPerSecond(Device device) 140 | { 141 | Capture(device); 142 | } 143 | 144 | private void Capture(Device device) 145 | { 146 | try 147 | { 148 | // Draw any overlays that have been added to the global list. 149 | var displayOverlays = Overlays; 150 | if (_overlayRenderer == null || 151 | _overlayRenderer.Device.NativePointer != device.NativePointer || 152 | PendingUpdate) 153 | { 154 | if (_overlayRenderer != null) 155 | { 156 | RemoveAndDispose(ref _overlayRenderer); 157 | } 158 | 159 | _overlayRenderer = ToDispose((new OverlayRenderer())); 160 | _overlayRenderer.Overlays.AddRange(displayOverlays); 161 | _overlayRenderer.Initialize(device); 162 | PendingUpdate = false; 163 | } 164 | 165 | if (_overlayRenderer != null) 166 | { 167 | foreach (var overlay in _overlayRenderer.Overlays) 168 | { 169 | overlay.OnFrame(); 170 | } 171 | 172 | _overlayRenderer.DrawFrame(); 173 | } 174 | } 175 | catch (Exception e) 176 | { 177 | System.Diagnostics.Debug.WriteLine($"{e}"); 178 | } 179 | } 180 | 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D9.Overlay/DirectX.Direct3D9.Overlay.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | true 9 | $(OutputDir) 10 | 11 | 12 | 13 | true 14 | $(OutputDir) 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D9.Overlay/EntryPoint.cs: -------------------------------------------------------------------------------- 1 | using CoreHook; 2 | using DirectX.Direct3D.Core; 3 | 4 | namespace DirectX.Direct3D9.Overlay 5 | { 6 | public class EntryPoint : IEntryPoint 7 | { 8 | private Direct3DHook _direct3DHook; 9 | 10 | public EntryPoint(IContext context) { } 11 | 12 | public void Run(IContext context) 13 | { 14 | InitializeDeviceHook(); 15 | while (true) 16 | { 17 | System.Threading.Thread.Sleep(30000); 18 | } 19 | } 20 | 21 | public void InitializeDeviceHook() 22 | { 23 | _direct3DHook = new Direct3DHookModule(); 24 | _direct3DHook.CreateHooks(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D9.Overlay/FunctionOrdinals.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DirectX.Direct3D9.Overlay 6 | { 7 | public enum FunctionOrdinals : short 8 | { 9 | QueryInterface = 0, 10 | AddRef = 1, 11 | Release = 2, 12 | TestCooperativeLevel = 3, 13 | GetAvailableTextureMem = 4, 14 | EvictManagedResources = 5, 15 | GetDirect3D = 6, 16 | GetDeviceCaps = 7, 17 | GetDisplayMode = 8, 18 | GetCreationParameters = 9, 19 | SetCursorProperties = 10, 20 | SetCursorPosition = 11, 21 | ShowCursor = 12, 22 | CreateAdditionalSwapChain = 13, 23 | GetSwapChain = 14, 24 | GetNumberOfSwapChains = 15, 25 | Reset = 16, 26 | Present = 17, 27 | GetBackBuffer = 18, 28 | GetRasterStatus = 19, 29 | SetDialogBoxMode = 20, 30 | SetGammaRamp = 21, 31 | GetGammaRamp = 22, 32 | CreateTexture = 23, 33 | CreateVolumeTexture = 24, 34 | CreateCubeTexture = 25, 35 | CreateVertexBuffer = 26, 36 | CreateIndexBuffer = 27, 37 | CreateRenderTarget = 28, 38 | CreateDepthStencilSurface = 29, 39 | UpdateSurface = 30, 40 | UpdateTexture = 31, 41 | GetRenderTargetData = 32, 42 | GetFrontBufferData = 33, 43 | StretchRect = 34, 44 | ColorFill = 35, 45 | CreateOffscreenPlainSurface = 36, 46 | SetRenderTarget = 37, 47 | GetRenderTarget = 38, 48 | SetDepthStencilSurface = 39, 49 | GetDepthStencilSurface = 40, 50 | BeginScene = 41, 51 | EndScene = 42, 52 | Clear = 43, 53 | SetTransform = 44, 54 | GetTransform = 45, 55 | MultiplyTransform = 46, 56 | SetViewport = 47, 57 | GetViewport = 48, 58 | SetMaterial = 49, 59 | GetMaterial = 50, 60 | SetLight = 51, 61 | GetLight = 52, 62 | LightEnable = 53, 63 | GetLightEnable = 54, 64 | SetClipPlane = 55, 65 | GetClipPlane = 56, 66 | SetRenderState = 57, 67 | GetRenderState = 58, 68 | CreateStateBlock = 59, 69 | BeginStateBlock = 60, 70 | EndStateBlock = 61, 71 | SetClipStatus = 62, 72 | GetClipStatus = 63, 73 | GetTexture = 64, 74 | SetTexture = 65, 75 | GetTextureStageState = 66, 76 | SetTextureStageState = 67, 77 | GetSamplerState = 68, 78 | SetSamplerState = 69, 79 | ValidateDevice = 70, 80 | SetPaletteEntries = 71, 81 | GetPaletteEntries = 72, 82 | SetCurrentTexturePalette = 73, 83 | GetCurrentTexturePalette = 74, 84 | SetScissorRect = 75, 85 | GetScissorRect = 76, 86 | SetSoftwareVertexProcessing = 77, 87 | GetSoftwareVertexProcessing = 78, 88 | SetNPatchMode = 79, 89 | GetNPatchMode = 80, 90 | DrawPrimitive = 81, 91 | DrawIndexedPrimitive = 82, 92 | DrawPrimitiveUP = 83, 93 | DrawIndexedPrimitiveUP = 84, 94 | ProcessVertices = 85, 95 | CreateVertexDeclaration = 86, 96 | SetVertexDeclaration = 87, 97 | GetVertexDeclaration = 88, 98 | SetFVF = 89, 99 | GetFVF = 90, 100 | CreateVertexShader = 91, 101 | SetVertexShader = 92, 102 | GetVertexShader = 93, 103 | SetVertexShaderConstantF = 94, 104 | GetVertexShaderConstantF = 95, 105 | SetVertexShaderConstantI = 96, 106 | GetVertexShaderConstantI = 97, 107 | SetVertexShaderConstantB = 98, 108 | GetVertexShaderConstantB = 99, 109 | SetStreamSource = 100, 110 | GetStreamSource = 101, 111 | SetStreamSourceFreq = 102, 112 | GetStreamSourceFreq = 103, 113 | SetIndices = 104, 114 | GetIndices = 105, 115 | CreatePixelShader = 106, 116 | SetPixelShader = 107, 117 | GetPixelShader = 108, 118 | SetPixelShaderConstantF = 109, 119 | GetPixelShaderConstantF = 110, 120 | SetPixelShaderConstantI = 111, 121 | GetPixelShaderConstantI = 112, 122 | SetPixelShaderConstantB = 113, 123 | GetPixelShaderConstantB = 114, 124 | DrawRectPatch = 115, 125 | DrawTriPatch = 116, 126 | DeletePatch = 117, 127 | CreateQuery = 118 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/DirectX.Direct3D9.Overlay/OverlayRenderer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using DirectX.Direct3D.Core.Drawing; 3 | using DirectX.Direct3D.Core.Memory; 4 | using SharpDX; 5 | using SharpDX.Direct3D9; 6 | 7 | namespace DirectX.Direct3D9.Overlay 8 | { 9 | internal class OverlayRenderer : DisposableComponent 10 | { 11 | public List Overlays { get; set; } = new List(); 12 | private readonly Dictionary _fontCache = new Dictionary(); 13 | 14 | private Device _device; 15 | private Sprite _sprite; 16 | 17 | public Device Device => _device; 18 | 19 | private bool _isInitialized; 20 | private bool _isInitializing; 21 | 22 | internal OverlayRenderer() 23 | { 24 | } 25 | 26 | private void EnsureInitialized() 27 | { 28 | System.Diagnostics.Debug.Assert(_isInitialized); 29 | } 30 | 31 | internal bool Initialize(Device device) 32 | { 33 | if (_isInitializing) 34 | { 35 | return false; 36 | } 37 | 38 | _isInitializing = true; 39 | 40 | try 41 | { 42 | _device = device; 43 | 44 | _sprite = ToDispose(new Sprite(device)); 45 | 46 | InitializeResources(); 47 | 48 | _isInitialized = true; 49 | } 50 | finally 51 | { 52 | _isInitializing = true; 53 | } 54 | return true; 55 | } 56 | 57 | private void InitializeResources() 58 | { 59 | foreach (var overlay in Overlays) 60 | { 61 | foreach (var overlayElement in overlay.Elements) 62 | { 63 | if(overlayElement is TextOverlay textOverlay) 64 | { 65 | GetOverlayFont(textOverlay); 66 | } 67 | } 68 | } 69 | } 70 | 71 | public void DrawFrame() 72 | { 73 | EnsureInitialized(); 74 | 75 | BeginFrame(); 76 | 77 | foreach (var overlay in Overlays) 78 | { 79 | foreach (var overlayElement in overlay.Elements) 80 | { 81 | if (overlayElement is TextOverlay textOverlay) 82 | { 83 | var font = GetOverlayFont(textOverlay); 84 | if (font != null && !string.IsNullOrEmpty(textOverlay.Text)) 85 | { 86 | font.DrawText(_sprite, textOverlay.Text, textOverlay.Location.X, textOverlay.Location.Y, 87 | new ColorBGRA(textOverlay.Color.R, textOverlay.Color.G, textOverlay.Color.B, 88 | textOverlay.Color.A)); 89 | } 90 | } 91 | } 92 | } 93 | 94 | EndFrame(); 95 | } 96 | 97 | private void BeginFrame() 98 | { 99 | _sprite.Begin(SpriteFlags.AlphaBlend); 100 | } 101 | 102 | private void EndFrame() 103 | { 104 | _sprite.End(); 105 | } 106 | 107 | private Font GetOverlayFont(TextOverlay textOverlay) 108 | { 109 | string fontKey = 110 | $"{textOverlay.Font.Name}{textOverlay.Font.Size}{textOverlay.Font.Style}{textOverlay.AntiAliased}"; 111 | 112 | if (!_fontCache.TryGetValue(fontKey, out Font overlayFont)) 113 | { 114 | overlayFont = ToDispose(new Font(_device, new FontDescription() 115 | { 116 | FaceName = textOverlay.Font.Name, 117 | Italic = (textOverlay.Font.Style & System.Drawing.FontStyle.Italic) == System.Drawing.FontStyle.Italic, 118 | Quality = (textOverlay.AntiAliased ? FontQuality.Antialiased : FontQuality.Default), 119 | Weight = ((textOverlay.Font.Style & System.Drawing.FontStyle.Bold) == System.Drawing.FontStyle.Bold) ? FontWeight.Bold : FontWeight.Normal, 120 | Height = (int)textOverlay.Font.SizeInPoints 121 | })); 122 | _fontCache[fontKey] = overlayFont; 123 | } 124 | return overlayFont; 125 | } 126 | 127 | public void ResetDeviceResources() 128 | { 129 | try 130 | { 131 | foreach (var font in _fontCache) 132 | { 133 | font.Value.OnLostDevice(); 134 | } 135 | 136 | _sprite?.OnLostDevice(); 137 | } 138 | catch { } 139 | } 140 | 141 | protected override void Dispose(bool disposing) 142 | { 143 | _device = null; 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /test/Direct3DCapture.Tests/Direct3DCapture.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.1 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /test/Direct3DCapture.Tests/UnitTest1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace Direct3DCapture.Tests 5 | { 6 | public class UnitTest1 7 | { 8 | [Fact] 9 | public void Test1() 10 | { 11 | 12 | } 13 | } 14 | } 15 | --------------------------------------------------------------------------------