├── .gitattributes ├── .github ├── FUNDING.yml └── workflows │ ├── build-and-publish-beta.yml │ ├── build-and-publish-release.yml │ └── validate-pull-request.yml ├── .gitignore ├── .gitmodules ├── Directory.Build.props ├── LICENSE.txt ├── README.md ├── build ├── NvgSharp.FNA.Core.sln ├── NvgSharp.FNA.sln ├── NvgSharp.MonoGame.sln └── NvgSharp.sln ├── images └── screenshot.png ├── samples ├── Assets │ ├── Roboto-Bold.ttf │ ├── Roboto-Light.ttf │ ├── Roboto-Regular.ttf │ ├── entypo.ttf │ ├── images.txt │ └── images │ │ ├── image1.jpg │ │ ├── image10.jpg │ │ ├── image11.jpg │ │ ├── image12.jpg │ │ ├── image2.jpg │ │ ├── image3.jpg │ │ ├── image4.jpg │ │ ├── image5.jpg │ │ ├── image6.jpg │ │ ├── image7.jpg │ │ ├── image8.jpg │ │ └── image9.jpg ├── NvgSharp.Samples.Demo │ ├── Demo.cs │ ├── Game1.cs │ ├── Icon.ico │ ├── NvgExtensions.cs │ ├── NvgSharp.Samples.Demo.FNA.Core.csproj │ ├── NvgSharp.Samples.Demo.FNA.csproj │ ├── NvgSharp.Samples.Demo.MonoGame.csproj │ ├── PerfGraph.cs │ ├── Program.cs │ └── Utility.cs ├── NvgSharp.Samples.OpenTK │ ├── BufferObject.cs │ ├── GLUtility.cs │ ├── NvgSharp.Samples.OpenTK.csproj │ ├── Platform │ │ └── Renderer.cs │ ├── Program.cs │ ├── Shader.cs │ ├── Texture.cs │ ├── VertexArrayObject.cs │ ├── Window.cs │ ├── shader.frag │ └── shader.vert └── NvgSharp.Samples.Silk.NET │ ├── BufferObject.cs │ ├── Env.cs │ ├── GLUtility.cs │ ├── NvgSharp.Samples.Silk.NET.csproj │ ├── Platform │ └── Renderer.cs │ ├── Program.cs │ ├── Shader.cs │ ├── Texture.cs │ ├── VertexArrayObject.cs │ ├── shader.frag │ └── shader.vert └── src ├── NvgSharp.Text ├── NvgSharp.Text.FNA.Core.csproj ├── NvgSharp.Text.FNA.csproj ├── NvgSharp.Text.MonoGame.csproj ├── NvgSharp.Text.csproj ├── NvgText.cs └── TextSource.cs ├── NvgSharp ├── ArrayBuffer.cs ├── AssemblyInfo.cs ├── Bounds.cs ├── Command.cs ├── Enums.cs ├── INvgRenderer.cs ├── NvgContext.cs ├── NvgContextState.cs ├── NvgPoint.cs ├── NvgSharp.csproj ├── NvgUtility.cs ├── Paint.cs ├── Path.cs ├── RenderCache.cs ├── Scissor.cs ├── Transform.cs └── Vertex.cs └── XNA ├── NvgSharp.FNA.Core.csproj ├── NvgSharp.FNA.csproj ├── NvgSharp.MonoGame.csproj ├── Resources.cs ├── Resources ├── Effect.dx11.mgfxo ├── Effect.fx ├── Effect.fxb ├── Effect.ogl.mgfxo ├── Effect_AA.dx11.mgfxo ├── Effect_AA.fxb ├── Effect_AA.ogl.mgfxo ├── Macros.fxh └── build.bat └── XNARenderer.cs /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: rds1983 2 | custom: https://boosty.to/rds1983 -------------------------------------------------------------------------------- /.github/workflows/build-and-publish-beta.yml: -------------------------------------------------------------------------------- 1 | name: Build & Publish Beta 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'src/**' 7 | - 'build/**' 8 | - 'samples/**' 9 | workflow_dispatch: 10 | 11 | jobs: 12 | BuildAndPublish: 13 | runs-on: windows-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | with: 18 | submodules: recursive 19 | - name: Setup .NET Core 20 | uses: actions/setup-dotnet@v1 21 | with: 22 | dotnet-version: '6.0.x' 23 | - name: Build NvgSharp 24 | run: dotnet build build\NvgSharp.sln --configuration Release 25 | - name: Build NvgSharp.MonoGame 26 | run: dotnet build build\NvgSharp.MonoGame.sln --configuration Release 27 | - name: Test 28 | run: dotnet test build\NvgSharp.MonoGame.sln 29 | - name: Install NuGet 30 | uses: NuGet/setup-nuget@v1 -------------------------------------------------------------------------------- /.github/workflows/build-and-publish-release.yml: -------------------------------------------------------------------------------- 1 | name: Build & Publish Release 2 | 3 | on: [workflow_dispatch] 4 | 5 | jobs: 6 | BuildAndPublish: 7 | runs-on: windows-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v2 11 | with: 12 | submodules: recursive 13 | - name: Setup .NET Core 14 | uses: actions/setup-dotnet@v1 15 | with: 16 | dotnet-version: '6.0.x' 17 | - name: Build NvgSharp 18 | run: dotnet build build\NvgSharp.sln --configuration Release 19 | - name: Build NvgSharp.MonoGame 20 | run: dotnet build build\NvgSharp.MonoGame.sln --configuration Release 21 | - name: Test 22 | run: dotnet test build\NvgSharp.MonoGame.sln 23 | - name: Install NuGet 24 | uses: NuGet/setup-nuget@v1 25 | - name: Publish NvgSharp.Text.MonoGame to NuGet 26 | run: nuget.exe push src\NvgSharp.Text\bin\MonoGame\Release\NvgSharp.Text.MonoGame.*.nupkg ${{secrets.NUGET_APIKEY}} -Source https://api.nuget.org/v3/index.json 27 | - name: Publish NvgSharp.Text to NuGet 28 | run: nuget.exe push src\NvgSharp.Text\bin\Release\NvgSharp.Text.*.nupkg ${{secrets.NUGET_APIKEY}} -Source https://api.nuget.org/v3/index.json 29 | - name: Publish NvgSharp.MonoGame to NuGet 30 | run: nuget.exe push src\XNA\bin\MonoGame\Release\NvgSharp.MonoGame.*.nupkg ${{secrets.NUGET_APIKEY}} -Source https://api.nuget.org/v3/index.json 31 | - name: Publish NvgSharp to NuGet 32 | run: nuget.exe push src\NvgSharp\bin\Release\NvgSharp.*.nupkg ${{secrets.NUGET_APIKEY}} -Source https://api.nuget.org/v3/index.json 33 | -------------------------------------------------------------------------------- /.github/workflows/validate-pull-request.yml: -------------------------------------------------------------------------------- 1 | name: Validate Pull Request 2 | 3 | on: [pull_request, workflow_dispatch] 4 | 5 | jobs: 6 | BuildAndPublish: 7 | runs-on: windows-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v2 11 | with: 12 | submodules: recursive 13 | - name: Setup .NET Core 14 | uses: actions/setup-dotnet@v1 15 | with: 16 | dotnet-version: '6.0.x' 17 | - name: Build NvgSharp 18 | run: dotnet build build\NvgSharp.sln --configuration Release 19 | - name: Build NvgSharp.MonoGame 20 | run: dotnet build build\NvgSharp.MonoGame.sln --configuration Release 21 | - name: Test 22 | run: dotnet test build\NvgSharp.MonoGame.sln -------------------------------------------------------------------------------- /.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: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/.gitmodules -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | NvgSharpTeam 4 | NvgSharp 5 | Zlib 6 | https://github.com/rds1983/NvgSharp 7 | NvgSharp 8 | 0.6.3 9 | 1.2.8 10 | 11 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Mikko Mononen memon@inside.org 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 2. Altered source versions must be plainly marked as such, and must not be 16 | misrepresented as being the original software. 17 | 3. This notice may not be removed or altered from any source distribution. 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NvgSharp 2 | [![NuGet](https://img.shields.io/nuget/v/NvgSharp.MonoGame.svg)](https://www.nuget.org/packages/NvgSharp.MonoGame/) [![Build status](https://ci.appveyor.com/api/projects/status/r4cd8vcao5i84xo7?svg=true)](https://ci.appveyor.com/project/RomanShapiro/nvgsharp) 3 | [![Chat](https://img.shields.io/discord/628186029488340992.svg)](https://discord.gg/ZeHxhCY) 4 | 5 | NvgSharp is 2D vector graphics library in pure C#. 6 | 7 | # Usage 8 | [Using NvgSharp in MonoGame or FNA](https://github.com/rds1983/NvgSharp/wiki/Using-NvgSharp-in-MonoGame-or-FNA) 9 | 10 | [Using NvgSharp in Generic Game Engine](https://github.com/rds1983/NvgSharp/wiki/Using-NvgSharp-in-Generic-Game-Engine) 11 | 12 | [Text Rendering](https://github.com/rds1983/NvgSharp/wiki/Text-Rendering) 13 | 14 | ## Support 15 | [Discord](https://discord.gg/ZeHxhCY) 16 | 17 | ## Building From Source Code 18 | 1. Clone this repo. 19 | 2. Open a solution from the "build" folder. 20 | 21 | ## Sponsor 22 | https://www.patreon.com/rds1983 23 | 24 | https://boosty.to/rds1983 25 | 26 | bitcoin: 3GeKFcv8X1cn8WqH1mr8i7jgPBkQjQuyN1 27 | 28 | # Screenshot 29 | ![](/images/screenshot.png) 30 | 31 | ## Credits 32 | * [nanovg](https://github.com/memononen/nanovg) 33 | * [MonoGame](http://www.monogame.net/) 34 | * [FNA](https://github.com/FNA-XNA/FNA) 35 | * [OpenTK](https://github.com/opentk/opentk) 36 | * [Silk.NET](https://github.com/dotnet/Silk.NET) 37 | * [stb](https://github.com/nothings/stb) 38 | -------------------------------------------------------------------------------- /build/NvgSharp.FNA.Core.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32328.378 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{578F4E7E-3DB4-4111-B6FD-831713726E4E}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FNA.Core", "..\..\FNA\FNA.Core.csproj", "{F724B17F-09FB-46C2-A8E3-407FC7B0591F}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FontStashSharp.FNA.Core", "..\..\FontStashSharp\src\XNA\FontStashSharp.FNA.Core.csproj", "{30A915B3-D36B-42DE-8F1A-96808C5F9948}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NvgSharp.FNA.Core", "..\src\XNA\NvgSharp.FNA.Core.csproj", "{267F26C4-E68A-443D-9794-689619F640AD}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NvgSharp.Text.FNA.Core", "..\src\NvgSharp.Text\NvgSharp.Text.FNA.Core.csproj", "{F81AF955-0126-4B2F-9120-D011B53B5F49}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NvgSharp.Samples.Demo.FNA.Core", "..\samples\NvgSharp.Samples.Demo\NvgSharp.Samples.Demo.FNA.Core.csproj", "{A213D290-ED16-4E5F-9181-8B5DD453E558}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {F724B17F-09FB-46C2-A8E3-407FC7B0591F}.Debug|Any CPU.ActiveCfg = Debug|x64 25 | {F724B17F-09FB-46C2-A8E3-407FC7B0591F}.Debug|Any CPU.Build.0 = Debug|x64 26 | {F724B17F-09FB-46C2-A8E3-407FC7B0591F}.Release|Any CPU.ActiveCfg = Release|x64 27 | {F724B17F-09FB-46C2-A8E3-407FC7B0591F}.Release|Any CPU.Build.0 = Release|x64 28 | {30A915B3-D36B-42DE-8F1A-96808C5F9948}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {30A915B3-D36B-42DE-8F1A-96808C5F9948}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {30A915B3-D36B-42DE-8F1A-96808C5F9948}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {30A915B3-D36B-42DE-8F1A-96808C5F9948}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {267F26C4-E68A-443D-9794-689619F640AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {267F26C4-E68A-443D-9794-689619F640AD}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {267F26C4-E68A-443D-9794-689619F640AD}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {267F26C4-E68A-443D-9794-689619F640AD}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {F81AF955-0126-4B2F-9120-D011B53B5F49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {F81AF955-0126-4B2F-9120-D011B53B5F49}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {F81AF955-0126-4B2F-9120-D011B53B5F49}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {F81AF955-0126-4B2F-9120-D011B53B5F49}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {A213D290-ED16-4E5F-9181-8B5DD453E558}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {A213D290-ED16-4E5F-9181-8B5DD453E558}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {A213D290-ED16-4E5F-9181-8B5DD453E558}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {A213D290-ED16-4E5F-9181-8B5DD453E558}.Release|Any CPU.Build.0 = Release|Any CPU 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(NestedProjects) = preSolution 49 | {A213D290-ED16-4E5F-9181-8B5DD453E558} = {578F4E7E-3DB4-4111-B6FD-831713726E4E} 50 | EndGlobalSection 51 | GlobalSection(ExtensibilityGlobals) = postSolution 52 | SolutionGuid = {A9C9D369-EE58-4E9D-B9FE-63023B644741} 53 | EndGlobalSection 54 | GlobalSection(MonoDevelopProperties) = preSolution 55 | StartupItem = Myra.UIEditor\Myra.UIEditor.csproj 56 | EndGlobalSection 57 | EndGlobal 58 | -------------------------------------------------------------------------------- /build/NvgSharp.FNA.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32328.378 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FNA", "..\..\FNA\FNA.csproj", "{35253CE1-C864-4CD3-8249-4D1319748E8F}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{ADFCD11E-96DF-4C72-A428-D96BA161223E}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NvgSharp.Samples.Demo.FNA", "..\samples\NvgSharp.Samples.Demo\NvgSharp.Samples.Demo.FNA.csproj", "{63C60C7F-3E6F-4026-A801-8E3AD2CEE9C3}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FontStashSharp.FNA", "..\..\FontStashSharp\src\XNA\FontStashSharp.FNA.csproj", "{4200A37F-4272-48EA-8CA7-BA5FE0BD6790}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NvgSharp.Text.FNA", "..\src\NvgSharp.Text\NvgSharp.Text.FNA.csproj", "{A62DFB9E-0A89-4347-AA7A-2891C1C3D206}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NvgSharp.FNA", "..\src\XNA\NvgSharp.FNA.csproj", "{94601022-412B-46BD-BA20-44A8A91E2022}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {35253CE1-C864-4CD3-8249-4D1319748E8F}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {35253CE1-C864-4CD3-8249-4D1319748E8F}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {63C60C7F-3E6F-4026-A801-8E3AD2CEE9C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {63C60C7F-3E6F-4026-A801-8E3AD2CEE9C3}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {63C60C7F-3E6F-4026-A801-8E3AD2CEE9C3}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {63C60C7F-3E6F-4026-A801-8E3AD2CEE9C3}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {4200A37F-4272-48EA-8CA7-BA5FE0BD6790}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {4200A37F-4272-48EA-8CA7-BA5FE0BD6790}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {4200A37F-4272-48EA-8CA7-BA5FE0BD6790}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {4200A37F-4272-48EA-8CA7-BA5FE0BD6790}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {A62DFB9E-0A89-4347-AA7A-2891C1C3D206}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {A62DFB9E-0A89-4347-AA7A-2891C1C3D206}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {A62DFB9E-0A89-4347-AA7A-2891C1C3D206}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {A62DFB9E-0A89-4347-AA7A-2891C1C3D206}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {94601022-412B-46BD-BA20-44A8A91E2022}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {94601022-412B-46BD-BA20-44A8A91E2022}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {94601022-412B-46BD-BA20-44A8A91E2022}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {94601022-412B-46BD-BA20-44A8A91E2022}.Release|Any CPU.Build.0 = Release|Any CPU 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(NestedProjects) = preSolution 49 | {63C60C7F-3E6F-4026-A801-8E3AD2CEE9C3} = {ADFCD11E-96DF-4C72-A428-D96BA161223E} 50 | EndGlobalSection 51 | GlobalSection(ExtensibilityGlobals) = postSolution 52 | SolutionGuid = {A9C9D369-EE58-4E9D-B9FE-63023B644741} 53 | EndGlobalSection 54 | GlobalSection(MonoDevelopProperties) = preSolution 55 | StartupItem = Myra.UIEditor\Myra.UIEditor.csproj 56 | EndGlobalSection 57 | EndGlobal 58 | -------------------------------------------------------------------------------- /build/NvgSharp.MonoGame.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32328.378 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{ADFCD11E-96DF-4C72-A428-D96BA161223E}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NvgSharp.MonoGame", "..\src\XNA\NvgSharp.MonoGame.csproj", "{6AFF5FD8-43AE-4144-918B-6D37C570BFA4}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NvgSharp.Samples.Demo.MonoGame", "..\samples\NvgSharp.Samples.Demo\NvgSharp.Samples.Demo.MonoGame.csproj", "{7D2336D8-D4A4-4CF0-A86C-4B904B3EF428}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NvgSharp.Text.MonoGame", "..\src\NvgSharp.Text\NvgSharp.Text.MonoGame.csproj", "{29F04FB2-43D8-4BC8-A92F-07E62F4934E1}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {6AFF5FD8-43AE-4144-918B-6D37C570BFA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {6AFF5FD8-43AE-4144-918B-6D37C570BFA4}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {6AFF5FD8-43AE-4144-918B-6D37C570BFA4}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {6AFF5FD8-43AE-4144-918B-6D37C570BFA4}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {7D2336D8-D4A4-4CF0-A86C-4B904B3EF428}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {7D2336D8-D4A4-4CF0-A86C-4B904B3EF428}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {7D2336D8-D4A4-4CF0-A86C-4B904B3EF428}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {7D2336D8-D4A4-4CF0-A86C-4B904B3EF428}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {29F04FB2-43D8-4BC8-A92F-07E62F4934E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {29F04FB2-43D8-4BC8-A92F-07E62F4934E1}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {29F04FB2-43D8-4BC8-A92F-07E62F4934E1}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {29F04FB2-43D8-4BC8-A92F-07E62F4934E1}.Release|Any CPU.Build.0 = Release|Any CPU 32 | EndGlobalSection 33 | GlobalSection(SolutionProperties) = preSolution 34 | HideSolutionNode = FALSE 35 | EndGlobalSection 36 | GlobalSection(NestedProjects) = preSolution 37 | {7D2336D8-D4A4-4CF0-A86C-4B904B3EF428} = {ADFCD11E-96DF-4C72-A428-D96BA161223E} 38 | EndGlobalSection 39 | GlobalSection(ExtensibilityGlobals) = postSolution 40 | SolutionGuid = {A9C9D369-EE58-4E9D-B9FE-63023B644741} 41 | EndGlobalSection 42 | GlobalSection(MonoDevelopProperties) = preSolution 43 | StartupItem = Myra.UIEditor\Myra.UIEditor.csproj 44 | EndGlobalSection 45 | EndGlobal 46 | -------------------------------------------------------------------------------- /build/NvgSharp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32328.378 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{ADFCD11E-96DF-4C72-A428-D96BA161223E}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NvgSharp", "..\src\NvgSharp\NvgSharp.csproj", "{E7D9D1C9-51C6-4EDC-B21A-5B4C7E87B663}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NvgSharp.Samples.Silk.NET", "..\samples\NvgSharp.Samples.Silk.NET\NvgSharp.Samples.Silk.NET.csproj", "{48B8A551-6457-4E8A-9725-EE481FEC659C}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NvgSharp.Samples.OpenTK", "..\samples\NvgSharp.Samples.OpenTK\NvgSharp.Samples.OpenTK.csproj", "{9D43A56B-7AFB-434F-83A5-335848FCA1D9}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NvgSharp.Text", "..\src\NvgSharp.Text\NvgSharp.Text.csproj", "{2CD25B57-790B-413D-9005-FF4DA59F4D13}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {E7D9D1C9-51C6-4EDC-B21A-5B4C7E87B663}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {E7D9D1C9-51C6-4EDC-B21A-5B4C7E87B663}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {E7D9D1C9-51C6-4EDC-B21A-5B4C7E87B663}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {E7D9D1C9-51C6-4EDC-B21A-5B4C7E87B663}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {48B8A551-6457-4E8A-9725-EE481FEC659C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {48B8A551-6457-4E8A-9725-EE481FEC659C}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {48B8A551-6457-4E8A-9725-EE481FEC659C}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {48B8A551-6457-4E8A-9725-EE481FEC659C}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {9D43A56B-7AFB-434F-83A5-335848FCA1D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {9D43A56B-7AFB-434F-83A5-335848FCA1D9}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {9D43A56B-7AFB-434F-83A5-335848FCA1D9}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {9D43A56B-7AFB-434F-83A5-335848FCA1D9}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {2CD25B57-790B-413D-9005-FF4DA59F4D13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {2CD25B57-790B-413D-9005-FF4DA59F4D13}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {2CD25B57-790B-413D-9005-FF4DA59F4D13}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {2CD25B57-790B-413D-9005-FF4DA59F4D13}.Release|Any CPU.Build.0 = Release|Any CPU 38 | EndGlobalSection 39 | GlobalSection(SolutionProperties) = preSolution 40 | HideSolutionNode = FALSE 41 | EndGlobalSection 42 | GlobalSection(NestedProjects) = preSolution 43 | {48B8A551-6457-4E8A-9725-EE481FEC659C} = {ADFCD11E-96DF-4C72-A428-D96BA161223E} 44 | {9D43A56B-7AFB-434F-83A5-335848FCA1D9} = {ADFCD11E-96DF-4C72-A428-D96BA161223E} 45 | EndGlobalSection 46 | GlobalSection(ExtensibilityGlobals) = postSolution 47 | SolutionGuid = {A9C9D369-EE58-4E9D-B9FE-63023B644741} 48 | EndGlobalSection 49 | GlobalSection(MonoDevelopProperties) = preSolution 50 | StartupItem = Myra.UIEditor\Myra.UIEditor.csproj 51 | EndGlobalSection 52 | EndGlobal 53 | -------------------------------------------------------------------------------- /images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/images/screenshot.png -------------------------------------------------------------------------------- /samples/Assets/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/Assets/Roboto-Bold.ttf -------------------------------------------------------------------------------- /samples/Assets/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/Assets/Roboto-Light.ttf -------------------------------------------------------------------------------- /samples/Assets/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/Assets/Roboto-Regular.ttf -------------------------------------------------------------------------------- /samples/Assets/entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/Assets/entypo.ttf -------------------------------------------------------------------------------- /samples/Assets/images.txt: -------------------------------------------------------------------------------- 1 | Image credits 2 | http://cuteoverload.com/2013/11/05/mom-taxi-xvi-birthday-party/ 3 | http://cuteoverload.com/2013/11/05/benson-hedges-private-eye-in-the-case-of-the-crafty-craftsman/ 4 | http://cuteoverload.com/2013/11/05/no-underwater-ballets/ 5 | http://cuteoverload.com/2013/11/05/every-nose-has-a-story/ 6 | http://cuteoverload.com/2013/11/04/nosevember-nozzle-nose/ 7 | http://cuteoverload.com/2013/11/04/this-just-in-super-strength-cute/ 8 | http://cuteoverload.com/2013/11/03/have-a-bunderful-sunday/ 9 | http://cuteoverload.com/2013/11/02/caturday-sense-a-common-theme-here/ 10 | http://cuteoverload.com/2013/11/01/nosevember-1st-24-hours-of-noses-1148pm-pt/ 11 | http://cuteoverload.com/2013/04/02/there-might-be-something-cuter-than-this/ 12 | http://cuteoverload.com/2013/07/17/snorting-micro-peeg-gets-belleh-rubs-interwebs-explode/ 13 | http://cuteoverload.com/2013/08/07/bark-in-the-park-v3-0/ -------------------------------------------------------------------------------- /samples/Assets/images/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/Assets/images/image1.jpg -------------------------------------------------------------------------------- /samples/Assets/images/image10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/Assets/images/image10.jpg -------------------------------------------------------------------------------- /samples/Assets/images/image11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/Assets/images/image11.jpg -------------------------------------------------------------------------------- /samples/Assets/images/image12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/Assets/images/image12.jpg -------------------------------------------------------------------------------- /samples/Assets/images/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/Assets/images/image2.jpg -------------------------------------------------------------------------------- /samples/Assets/images/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/Assets/images/image3.jpg -------------------------------------------------------------------------------- /samples/Assets/images/image4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/Assets/images/image4.jpg -------------------------------------------------------------------------------- /samples/Assets/images/image5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/Assets/images/image5.jpg -------------------------------------------------------------------------------- /samples/Assets/images/image6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/Assets/images/image6.jpg -------------------------------------------------------------------------------- /samples/Assets/images/image7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/Assets/images/image7.jpg -------------------------------------------------------------------------------- /samples/Assets/images/image8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/Assets/images/image8.jpg -------------------------------------------------------------------------------- /samples/Assets/images/image9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/Assets/images/image9.jpg -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Demo/Demo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using FontStashSharp; 4 | 5 | #if MONOGAME || FNA 6 | using Microsoft.Xna.Framework; 7 | using Microsoft.Xna.Framework.Graphics; 8 | #elif STRIDE 9 | using Stride.Core.Mathematics; 10 | #else 11 | using StbImageSharp; 12 | using System.Drawing; 13 | using Texture2D = NvgSharp.Samples.Texture; 14 | #endif 15 | 16 | namespace NvgSharp.Samples 17 | { 18 | public class Demo 19 | { 20 | private static readonly string ICON_SEARCH = char.ConvertFromUtf32(0x1F50D); 21 | private static readonly string ICON_CIRCLED_CROSS = char.ConvertFromUtf32(0x2716); 22 | private static readonly string ICON_CHEVRON_RIGHT = char.ConvertFromUtf32(0xE75E); 23 | private static readonly string ICON_CHECK = char.ConvertFromUtf32(0x2713); 24 | private static readonly string ICON_LOGIN = char.ConvertFromUtf32(0xE740); 25 | private static readonly string ICON_TRASH = char.ConvertFromUtf32(0xE729); 26 | 27 | public FontSystem fontSystemNormal, fontSystemBold, fontSystemIcons; 28 | SpriteFontBase fontSans18, fontSans20, fontBold18, fontBold20; 29 | Texture2D[] images = new Texture2D[12]; 30 | 31 | static float clampf(float a, float mn, float mx) 32 | { 33 | return a < mn ? mn : (a > mx ? mx : a); 34 | } 35 | 36 | // Returns 1 if col.rgba is 0.0f,0.0f,0.0f,0.0f, 0 otherwise 37 | public static bool isBlack(Color col) 38 | { 39 | return col == Color.Transparent; 40 | } 41 | 42 | public Demo(NvgContext vg) 43 | { 44 | for (var i = 0; i < images.Length; i++) 45 | { 46 | var path = "Assets/images/image" + (i + 1).ToString() + ".jpg"; 47 | 48 | #if MONOGAME || FNA || STRIDE 49 | using (var stream = File.OpenRead(path)) 50 | { 51 | images[i] = Texture2D.FromStream(vg.GraphicsDevice, stream); 52 | } 53 | #else 54 | ImageResult imageResult; 55 | using (var stream = File.OpenRead(path)) 56 | { 57 | imageResult = ImageResult.FromStream(stream, ColorComponents.RedGreenBlueAlpha); 58 | } 59 | 60 | var texture = new Texture(imageResult.Width, imageResult.Height); 61 | texture.SetData(new Rectangle(0, 0, imageResult.Width, imageResult.Height), imageResult.Data); 62 | images[i] = texture; 63 | #endif 64 | } 65 | 66 | fontSystemIcons = LoadFont("Assets/entypo.ttf"); 67 | fontSystemNormal = LoadFont("Assets/Roboto-Regular.ttf"); 68 | fontSystemBold = LoadFont("Assets/Roboto-Bold.ttf"); 69 | 70 | fontSans18 = fontSystemNormal.GetFont(18); 71 | fontSans20 = fontSystemNormal.GetFont(20); 72 | 73 | fontBold18 = fontSystemBold.GetFont(18); 74 | fontBold20 = fontSystemBold.GetFont(20); 75 | } 76 | 77 | public void drawWindow(NvgContext vg, string title, float x, float y, float w, float h) 78 | { 79 | float cornerRadius = 3.0f; 80 | Paint shadowPaint; 81 | Paint headerPaint; 82 | 83 | vg.SaveState(); 84 | 85 | // Window 86 | vg.BeginPath(); 87 | vg.RoundedRect(x, y, w, h, cornerRadius); 88 | vg.FillColor(Utility.FromRGBA(28, 30, 34, 192)); 89 | // vg.FillColor(GLUtility.FromRGBA(0,0,0,128)); 90 | vg.Fill(); 91 | 92 | // Drop shadow 93 | shadowPaint = vg.BoxGradient(x, y + 2, w, h, cornerRadius * 2, 10, Utility.FromRGBA(0, 0, 0, 128), Utility.FromRGBA(0, 0, 0, 0)); 94 | vg.BeginPath(); 95 | vg.Rect(x - 10, y - 10, w + 20, h + 30); 96 | vg.RoundedRect(x, y, w, h, cornerRadius); 97 | vg.PathWinding(Solidity.Hole); 98 | vg.FillPaint(shadowPaint); 99 | vg.Fill(); 100 | 101 | // Header 102 | headerPaint = vg.LinearGradient(x, y, x, y + 15, Utility.FromRGBA(255, 255, 255, 8), Utility.FromRGBA(0, 0, 0, 16)); 103 | vg.BeginPath(); 104 | vg.RoundedRect(x + 1, y + 1, w - 2, 30, cornerRadius - 1); 105 | vg.FillPaint(headerPaint); 106 | vg.Fill(); 107 | vg.BeginPath(); 108 | vg.MoveTo(x + 0.5f, y + 0.5f + 30); 109 | vg.LineTo(x + 0.5f + w - 1, y + 0.5f + 30); 110 | vg.StrokeColor(Utility.FromRGBA(0, 0, 0, 32)); 111 | vg.Stroke(); 112 | 113 | vg.FillColor(Utility.FromRGBA(0, 0, 0, 128)); 114 | vg.TextAligned(fontBold18, title, x + w / 2, y + 16 + 1, TextHorizontalAlignment.Center, TextVerticalAlignment.Center); 115 | 116 | vg.FillColor(Utility.FromRGBA(220, 220, 220, 160)); 117 | vg.TextAligned(fontBold18, title, x + w / 2, y + 16, TextHorizontalAlignment.Center, TextVerticalAlignment.Center); 118 | 119 | vg.RestoreState(); 120 | } 121 | 122 | public void drawSearchBox(NvgContext vg, string text, float x, float y, float w, float h) 123 | { 124 | Paint bg; 125 | float cornerRadius = h / 2 - 1; 126 | 127 | // Edit 128 | bg = vg.BoxGradient(x, y + 1.5f, w, h, h / 2, 5, Utility.FromRGBA(0, 0, 0, 16), Utility.FromRGBA(0, 0, 0, 92)); 129 | vg.BeginPath(); 130 | vg.RoundedRect(x, y, w, h, cornerRadius); 131 | vg.FillPaint(bg); 132 | vg.Fill(); 133 | 134 | var fontIcons = fontSystemIcons.GetFont((int)(h * 1.3f)); 135 | 136 | vg.FillColor(Utility.FromRGBA(255, 255, 255, 64)); 137 | vg.TextAligned(fontIcons, ICON_SEARCH, x + h * 0.55f, y + h * 0.55f, TextHorizontalAlignment.Center, TextVerticalAlignment.Center); 138 | 139 | vg.FillColor(Utility.FromRGBA(255, 255, 255, 32)); 140 | vg.TextAligned(fontSans20, text, x + h * 1.05f, y + h * 0.5f, TextHorizontalAlignment.Left, TextVerticalAlignment.Center); 141 | 142 | vg.FillColor(Utility.FromRGBA(255, 255, 255, 32)); 143 | vg.TextAligned(fontIcons, ICON_CIRCLED_CROSS, x + w - h * 0.55f, y + h * 0.55f, TextHorizontalAlignment.Center, TextVerticalAlignment.Center); 144 | } 145 | 146 | public void drawDropDown(NvgContext vg, string text, float x, float y, float w, float h) 147 | { 148 | Paint bg; 149 | float cornerRadius = 4.0f; 150 | 151 | bg = vg.LinearGradient(x, y, x, y + h, Utility.FromRGBA(255, 255, 255, 16), Utility.FromRGBA(0, 0, 0, 16)); 152 | vg.BeginPath(); 153 | vg.RoundedRect(x + 1, y + 1, w - 2, h - 2, cornerRadius - 1); 154 | vg.FillPaint(bg); 155 | vg.Fill(); 156 | 157 | vg.BeginPath(); 158 | vg.RoundedRect(x + 0.5f, y + 0.5f, w - 1, h - 1, cornerRadius - 0.5f); 159 | vg.StrokeColor(Utility.FromRGBA(0, 0, 0, 48)); 160 | vg.Stroke(); 161 | 162 | vg.FillColor(Utility.FromRGBA(255, 255, 255, 160)); 163 | vg.TextAligned(fontSans20, text, x + h * 0.3f, y + h * 0.5f, TextHorizontalAlignment.Left, TextVerticalAlignment.Center); 164 | 165 | var fontIcons = fontSystemIcons.GetFont((int)(h * 1.3f)); 166 | vg.FillColor(Utility.FromRGBA(255, 255, 255, 64)); 167 | vg.TextAligned(fontIcons, ICON_CHEVRON_RIGHT, x + w - h * 0.5f, y + h * 0.5f, TextHorizontalAlignment.Center, TextVerticalAlignment.Center); 168 | } 169 | 170 | public void drawLabel(NvgContext vg, string text, float x, float y, float w, float h) 171 | { 172 | vg.FillColor(Utility.FromRGBA(255, 255, 255, 128)); 173 | vg.TextAligned(fontSans18, text, x, y + h * 0.5f, TextHorizontalAlignment.Left, TextVerticalAlignment.Center); 174 | } 175 | 176 | public static void drawEditBoxBase(NvgContext vg, float x, float y, float w, float h) 177 | { 178 | Paint bg; 179 | // Edit 180 | bg = vg.BoxGradient(x + 1, y + 1 + 1.5f, w - 2, h - 2, 3, 4, Utility.FromRGBA(255, 255, 255, 32), Utility.FromRGBA(32, 32, 32, 32)); 181 | vg.BeginPath(); 182 | vg.RoundedRect(x + 1, y + 1, w - 2, h - 2, 4 - 1); 183 | vg.FillPaint(bg); 184 | vg.Fill(); 185 | 186 | vg.BeginPath(); 187 | vg.RoundedRect(x + 0.5f, y + 0.5f, w - 1, h - 1, 4 - 0.5f); 188 | vg.StrokeColor(Utility.FromRGBA(0, 0, 0, 48)); 189 | vg.Stroke(); 190 | } 191 | 192 | public void drawEditBox(NvgContext vg, string text, float x, float y, float w, float h) 193 | { 194 | drawEditBoxBase(vg, x, y, w, h); 195 | 196 | vg.FillColor(Utility.FromRGBA(255, 255, 255, 64)); 197 | vg.TextAligned(fontSans20, text, x + h * 0.3f, y + h * 0.5f, TextHorizontalAlignment.Left, TextVerticalAlignment.Center); 198 | } 199 | 200 | public void drawEditBoxNum(NvgContext vg, string text, string units, float x, float y, float w, float h) 201 | { 202 | drawEditBoxBase(vg, x, y, w, h); 203 | 204 | var sz = fontSans18.MeasureString(units); 205 | 206 | vg.FillColor(Utility.FromRGBA(255, 255, 255, 64)); 207 | vg.TextAligned(fontSans18, units, x + w - h * 0.3f, y + h * 0.5f, TextHorizontalAlignment.Right, TextVerticalAlignment.Center); 208 | 209 | vg.FillColor(Utility.FromRGBA(255, 255, 255, 128)); 210 | vg.TextAligned(fontSans20, text, x + w - sz.X - h * 0.5f, y + h * 0.5f, TextHorizontalAlignment.Right, TextVerticalAlignment.Center); 211 | } 212 | 213 | public void drawCheckBox(NvgContext vg, string text, float x, float y, float w, float h) 214 | { 215 | Paint bg; 216 | 217 | vg.FillColor(Utility.FromRGBA(255, 255, 255, 160)); 218 | vg.TextAligned(fontSans18, text, x + 28, y + h * 0.5f, TextHorizontalAlignment.Left, TextVerticalAlignment.Center); 219 | 220 | bg = vg.BoxGradient(x + 1, y + (int)(h * 0.5f) - 9 + 1, 18, 18, 3, 3, Utility.FromRGBA(0, 0, 0, 32), Utility.FromRGBA(0, 0, 0, 92)); 221 | vg.BeginPath(); 222 | vg.RoundedRect(x + 1, y + (int)(h * 0.5f) - 9, 18, 18, 3); 223 | vg.FillPaint(bg); 224 | vg.Fill(); 225 | 226 | var fontIcons = fontSystemIcons.GetFont(40); 227 | vg.FillColor(Utility.FromRGBA(255, 255, 255, 128)); 228 | vg.TextAligned(fontIcons, ICON_CHECK, x + 9 + 2, y + h * 0.5f, TextHorizontalAlignment.Center, TextVerticalAlignment.Center); 229 | } 230 | 231 | public void drawButton(NvgContext vg, string preicon, string text, float x, float y, float w, float h, Color col) 232 | { 233 | Paint bg; 234 | float cornerRadius = 4.0f; 235 | float tw = 0, iw = 0; 236 | 237 | bg = vg.LinearGradient(x, y, x, y + h, Utility.FromRGBA(255, 255, 255, isBlack(col) ? (byte)16 : (byte)32), 238 | Utility.FromRGBA(0, 0, 0, isBlack(col) ? (byte)16 : (byte)32)); 239 | vg.BeginPath(); 240 | vg.RoundedRect(x + 1, y + 1, w - 2, h - 2, cornerRadius - 1); 241 | if (!isBlack(col)) 242 | { 243 | vg.FillColor(col); 244 | vg.Fill(); 245 | } 246 | vg.FillPaint(bg); 247 | vg.Fill(); 248 | 249 | vg.BeginPath(); 250 | vg.RoundedRect(x + 0.5f, y + 0.5f, w - 1, h - 1, cornerRadius - 0.5f); 251 | vg.StrokeColor(Utility.FromRGBA(0, 0, 0, 48)); 252 | vg.Stroke(); 253 | 254 | var sz = fontBold20.MeasureString(text); 255 | tw = sz.X; 256 | if (!string.IsNullOrEmpty(preicon)) 257 | { 258 | var fontIcons = fontSystemIcons.GetFont((int)(h * 1.3f)); 259 | sz = fontIcons.MeasureString(preicon); 260 | iw = sz.X; 261 | iw += h * 0.15f; 262 | 263 | vg.FillColor(Utility.FromRGBA(255, 255, 255, 96)); 264 | vg.TextAligned(fontIcons, preicon, x + w * 0.5f - tw * 0.5f - iw * 0.75f, y + h * 0.5f, TextHorizontalAlignment.Left, TextVerticalAlignment.Center); 265 | } 266 | 267 | vg.FillColor(Utility.FromRGBA(0, 0, 0, 160)); 268 | vg.TextAligned(fontBold20, text, x + w * 0.5f - tw * 0.5f + iw * 0.25f, y + h * 0.5f - 1, TextHorizontalAlignment.Left, TextVerticalAlignment.Center); 269 | vg.FillColor(Utility.FromRGBA(255, 255, 255, 160)); 270 | vg.TextAligned(fontBold20, text, x + w * 0.5f - tw * 0.5f + iw * 0.25f, y + h * 0.5f, TextHorizontalAlignment.Left, TextVerticalAlignment.Center); 271 | } 272 | 273 | public static void drawSlider(NvgContext vg, float pos, float x, float y, float w, float h) 274 | { 275 | Paint bg, knob; 276 | float cy = y + (int)(h * 0.5f); 277 | float kr = (int)(h * 0.25f); 278 | 279 | vg.SaveState(); 280 | // ClearState(vg); 281 | 282 | // Slot 283 | bg = vg.BoxGradient(x, cy - 2 + 1, w, 4, 2, 2, Utility.FromRGBA(0, 0, 0, 32), Utility.FromRGBA(0, 0, 0, 128)); 284 | vg.BeginPath(); 285 | vg.RoundedRect(x, cy - 2, w, 4, 2); 286 | vg.FillPaint(bg); 287 | vg.Fill(); 288 | 289 | // Knob Shadow 290 | bg = vg.RadialGradient(x + (int)(pos * w), cy + 1, kr - 3, kr + 3, Utility.FromRGBA(0, 0, 0, 64), Utility.FromRGBA(0, 0, 0, 0)); 291 | vg.BeginPath(); 292 | vg.Rect(x + (int)(pos * w) - kr - 5, cy - kr - 5, kr * 2 + 5 + 5, kr * 2 + 5 + 5 + 3); 293 | vg.Circle(x + (int)(pos * w), cy, kr); 294 | vg.PathWinding(Solidity.Hole); 295 | vg.FillPaint(bg); 296 | vg.Fill(); 297 | 298 | // Knob 299 | knob = vg.LinearGradient(x, cy - kr, x, cy + kr, Utility.FromRGBA(255, 255, 255, 16), Utility.FromRGBA(0, 0, 0, 16)); 300 | vg.BeginPath(); 301 | vg.Circle(x + (int)(pos * w), cy, kr - 1); 302 | vg.FillColor(Utility.FromRGBA(40, 43, 48, 255)); 303 | vg.Fill(); 304 | vg.FillPaint(knob); 305 | vg.Fill(); 306 | 307 | vg.BeginPath(); 308 | vg.Circle(x + (int)(pos * w), cy, kr - 0.5f); 309 | vg.StrokeColor(Utility.FromRGBA(0, 0, 0, 92)); 310 | vg.Stroke(); 311 | 312 | vg.RestoreState(); 313 | } 314 | 315 | public static void drawEyes(NvgContext vg, float x, float y, float w, float h, float mx, float my, float t) 316 | { 317 | Paint gloss, bg; 318 | float ex = w * 0.23f; 319 | float ey = h * 0.5f; 320 | float lx = x + ex; 321 | float ly = y + ey; 322 | float rx = x + w - ex; 323 | float ry = y + ey; 324 | float dx, dy, d; 325 | float br = (ex < ey ? ex : ey) * 0.5f; 326 | float blink = 1 - (float)(Math.Pow(Math.Sin(t * 0.5f), 200) * 0.8f); 327 | 328 | bg = vg.LinearGradient(x, y + h * 0.5f, x + w * 0.1f, y + h, Utility.FromRGBA(0, 0, 0, 32), Utility.FromRGBA(0, 0, 0, 16)); 329 | vg.BeginPath(); 330 | vg.Ellipse(lx + 3.0f, ly + 16.0f, ex, ey); 331 | vg.Ellipse(rx + 3.0f, ry + 16.0f, ex, ey); 332 | vg.FillPaint(bg); 333 | vg.Fill(); 334 | 335 | bg = vg.LinearGradient(x, y + h * 0.25f, x + w * 0.1f, y + h, Utility.FromRGBA(220, 220, 220, 255), Utility.FromRGBA(128, 128, 128, 255)); 336 | vg.BeginPath(); 337 | vg.Ellipse(lx, ly, ex, ey); 338 | vg.Ellipse(rx, ry, ex, ey); 339 | vg.FillPaint(bg); 340 | vg.Fill(); 341 | 342 | dx = (mx - rx) / (ex * 10); 343 | dy = (my - ry) / (ey * 10); 344 | d = (float)Math.Sqrt(dx * dx + dy * dy); 345 | if (d > 1.0f) 346 | { 347 | dx /= d; 348 | dy /= d; 349 | } 350 | dx *= ex * 0.4f; 351 | dy *= ey * 0.5f; 352 | vg.BeginPath(); 353 | vg.Ellipse(lx + dx, ly + dy + ey * 0.25f * (1 - blink), br, br * blink); 354 | vg.FillColor(Utility.FromRGBA(32, 32, 32, 255)); 355 | vg.Fill(); 356 | 357 | dx = (mx - rx) / (ex * 10); 358 | dy = (my - ry) / (ey * 10); 359 | d = (float)Math.Sqrt(dx * dx + dy * dy); 360 | if (d > 1.0f) 361 | { 362 | dx /= d; 363 | dy /= d; 364 | } 365 | dx *= ex * 0.4f; 366 | dy *= ey * 0.5f; 367 | vg.BeginPath(); 368 | vg.Ellipse(rx + dx, ry + dy + ey * 0.25f * (1 - blink), br, br * blink); 369 | vg.FillColor(Utility.FromRGBA(32, 32, 32, 255)); 370 | vg.Fill(); 371 | 372 | gloss = vg.RadialGradient(lx - ex * 0.25f, ly - ey * 0.5f, ex * 0.1f, ex * 0.75f, Utility.FromRGBA(255, 255, 255, 128), Utility.FromRGBA(255, 255, 255, 0)); 373 | vg.BeginPath(); 374 | vg.Ellipse(lx, ly, ex, ey); 375 | vg.FillPaint(gloss); 376 | vg.Fill(); 377 | 378 | gloss = vg.RadialGradient(rx - ex * 0.25f, ry - ey * 0.5f, ex * 0.1f, ex * 0.75f, Utility.FromRGBA(255, 255, 255, 128), Utility.FromRGBA(255, 255, 255, 0)); 379 | vg.BeginPath(); 380 | vg.Ellipse(rx, ry, ex, ey); 381 | vg.FillPaint(gloss); 382 | vg.Fill(); 383 | } 384 | 385 | public static void drawGraph(NvgContext vg, float x, float y, float w, float h, float t) 386 | { 387 | Paint bg; 388 | float[] samples = new float[6]; 389 | float[] sx = new float[6], sy = new float[6]; 390 | float dx = w / 5.0f; 391 | int i; 392 | 393 | samples[0] = (1 + (float)Math.Sin(t * 1.2345f + (float)Math.Cos(t * 0.33457f) * 0.44f)) * 0.5f; 394 | samples[1] = (1 + (float)Math.Sin(t * 0.68363f + (float)Math.Cos(t * 1.3f) * 1.55f)) * 0.5f; 395 | samples[2] = (1 + (float)Math.Sin(t * 1.1642f + (float)Math.Cos(t * 0.33457) * 1.24f)) * 0.5f; 396 | samples[3] = (1 + (float)Math.Sin(t * 0.56345f + (float)Math.Cos(t * 1.63f) * 0.14f)) * 0.5f; 397 | samples[4] = (1 + (float)Math.Sin(t * 1.6245f + (float)Math.Cos(t * 0.254f) * 0.3f)) * 0.5f; 398 | samples[5] = (1 + (float)Math.Sin(t * 0.345f + (float)Math.Cos(t * 0.03f) * 0.6f)) * 0.5f; 399 | 400 | for (i = 0; i < 6; i++) 401 | { 402 | sx[i] = x + i * dx; 403 | sy[i] = y + h * samples[i] * 0.8f; 404 | } 405 | 406 | // Graph background 407 | bg = vg.LinearGradient(x, y, x, y + h, Utility.FromRGBA(0, 160, 192, 0), Utility.FromRGBA(0, 160, 192, 64)); 408 | vg.BeginPath(); 409 | vg.MoveTo(sx[0], sy[0]); 410 | for (i = 1; i < 6; i++) 411 | vg.BezierTo(sx[i - 1] + dx * 0.5f, sy[i - 1], sx[i] - dx * 0.5f, sy[i], sx[i], sy[i]); 412 | vg.LineTo(x + w, y + h); 413 | vg.LineTo(x, y + h); 414 | vg.FillPaint(bg); 415 | vg.Fill(); 416 | 417 | // Graph line 418 | vg.BeginPath(); 419 | vg.MoveTo(sx[0], sy[0] + 2); 420 | for (i = 1; i < 6; i++) 421 | vg.BezierTo(sx[i - 1] + dx * 0.5f, sy[i - 1] + 2, sx[i] - dx * 0.5f, sy[i] + 2, sx[i], sy[i] + 2); 422 | vg.StrokeColor(Utility.FromRGBA(0, 0, 0, 32)); 423 | vg.StrokeWidth(3.0f); 424 | vg.Stroke(); 425 | 426 | vg.BeginPath(); 427 | vg.MoveTo(sx[0], sy[0]); 428 | for (i = 1; i < 6; i++) 429 | vg.BezierTo(sx[i - 1] + dx * 0.5f, sy[i - 1], sx[i] - dx * 0.5f, sy[i], sx[i], sy[i]); 430 | vg.StrokeColor(Utility.FromRGBA(0, 160, 192, 255)); 431 | vg.StrokeWidth(3.0f); 432 | vg.Stroke(); 433 | 434 | // Graph sample pos 435 | for (i = 0; i < 6; i++) 436 | { 437 | bg = vg.RadialGradient(sx[i], sy[i] + 2, 3.0f, 8.0f, Utility.FromRGBA(0, 0, 0, 32), Utility.FromRGBA(0, 0, 0, 0)); 438 | vg.BeginPath(); 439 | vg.Rect(sx[i] - 10, sy[i] - 10 + 2, 20, 20); 440 | vg.FillPaint(bg); 441 | vg.Fill(); 442 | } 443 | 444 | vg.BeginPath(); 445 | for (i = 0; i < 6; i++) 446 | vg.Circle(sx[i], sy[i], 4.0f); 447 | vg.FillColor(Utility.FromRGBA(0, 160, 192, 255)); 448 | vg.Fill(); 449 | vg.BeginPath(); 450 | for (i = 0; i < 6; i++) 451 | vg.Circle(sx[i], sy[i], 2.0f); 452 | vg.FillColor(Utility.FromRGBA(220, 220, 220, 255)); 453 | vg.Fill(); 454 | 455 | vg.StrokeWidth(1.0f); 456 | } 457 | 458 | public static void drawSpinner(NvgContext vg, float cx, float cy, float r, float t) 459 | { 460 | float a0 = 0.0f + t * 6; 461 | float a1 = (float)Math.PI + t * 6; 462 | float r0 = r; 463 | float r1 = r * 0.75f; 464 | float ax, ay, bx, by; 465 | Paint paint; 466 | 467 | vg.SaveState(); 468 | 469 | vg.BeginPath(); 470 | vg.Arc(cx, cy, r0, a0, a1, Winding.ClockWise); 471 | vg.Arc(cx, cy, r1, a1, a0, Winding.CounterClockWise); 472 | vg.ClosePath(); 473 | ax = cx + (float)Math.Cos(a0) * (r0 + r1) * 0.5f; 474 | ay = cy + (float)Math.Sin(a0) * (r0 + r1) * 0.5f; 475 | bx = cx + (float)Math.Cos(a1) * (r0 + r1) * 0.5f; 476 | by = cy + (float)Math.Sin(a1) * (r0 + r1) * 0.5f; 477 | paint = vg.LinearGradient(ax, ay, bx, by, Utility.FromRGBA(0, 0, 0, 0), Utility.FromRGBA(0, 0, 0, 128)); 478 | vg.FillPaint(paint); 479 | vg.Fill(); 480 | 481 | vg.RestoreState(); 482 | } 483 | 484 | public static void drawThumbnails(NvgContext vg, float x, float y, float w, float h, Texture2D[] images, float t) 485 | { 486 | float cornerRadius = 3.0f; 487 | Paint shadowPaint, imgPaint, fadePaint; 488 | float ix, iy, iw, ih; 489 | float thumb = 60.0f; 490 | float arry = 30.5f; 491 | int imgw, imgh; 492 | float stackh = (images.Length / 2) * (thumb + 10) + 10; 493 | int i; 494 | float u = (1 + (float)Math.Cos(t * 0.5f)) * 0.5f; 495 | float u2 = (1 - (float)Math.Cos(t * 0.2f)) * 0.5f; 496 | float scrollh, dv; 497 | 498 | vg.SaveState(); 499 | // ClearState(vg); 500 | 501 | // Drop shadow 502 | shadowPaint = vg.BoxGradient(x, y + 4, w, h, cornerRadius * 2, 20, Utility.FromRGBA(0, 0, 0, 128), Utility.FromRGBA(0, 0, 0, 0)); 503 | vg.BeginPath(); 504 | vg.Rect(x - 10, y - 10, w + 20, h + 30); 505 | vg.RoundedRect(x, y, w, h, cornerRadius); 506 | vg.PathWinding(Solidity.Hole); 507 | vg.FillPaint(shadowPaint); 508 | vg.Fill(); 509 | 510 | // Window 511 | vg.BeginPath(); 512 | vg.RoundedRect(x, y, w, h, cornerRadius); 513 | vg.MoveTo(x - 10, y + arry); 514 | vg.LineTo(x + 1, y + arry - 11); 515 | vg.LineTo(x + 1, y + arry + 11); 516 | vg.FillColor(Utility.FromRGBA(200, 200, 200, 255)); 517 | vg.Fill(); 518 | 519 | vg.SaveState(); 520 | vg.Scissor(x, y, w, h); 521 | vg.Translate(0, -(stackh - h) * u); 522 | 523 | dv = 1.0f / (images.Length - 1); 524 | 525 | for (i = 0; i < images.Length; i++) 526 | { 527 | float tx, ty, v, a; 528 | tx = x + 10; 529 | ty = y + 10; 530 | tx += (i % 2) * (thumb + 10); 531 | ty += (i / 2) * (thumb + 10); 532 | 533 | imgw = images[i].Width; 534 | imgh = images[i].Height; 535 | 536 | if (imgw < imgh) 537 | { 538 | iw = thumb; 539 | ih = iw * imgh / imgw; 540 | ix = 0; 541 | iy = -(ih - thumb) * 0.5f; 542 | } 543 | else 544 | { 545 | ih = thumb; 546 | iw = ih * imgw / imgh; 547 | ix = -(iw - thumb) * 0.5f; 548 | iy = 0; 549 | } 550 | 551 | v = i * dv; 552 | a = clampf((u2 - v) / dv, 0, 1); 553 | 554 | if (a < 1.0f) 555 | drawSpinner(vg, tx + thumb / 2, ty + thumb / 2, thumb * 0.25f, t); 556 | 557 | imgPaint = vg.ImagePattern(tx + ix, ty + iy, iw, ih, 0.0f / 180.0f * (float)Math.PI, images[i], a); 558 | vg.BeginPath(); 559 | vg.RoundedRect(tx, ty, thumb, thumb, 5); 560 | vg.FillPaint(imgPaint); 561 | vg.Fill(); 562 | 563 | shadowPaint = vg.BoxGradient(tx - 1, ty, thumb + 2, thumb + 2, 5, 3, Utility.FromRGBA(0, 0, 0, 128), Utility.FromRGBA(0, 0, 0, 0)); 564 | vg.BeginPath(); 565 | vg.Rect(tx - 5, ty - 5, thumb + 10, thumb + 10); 566 | vg.RoundedRect(tx, ty, thumb, thumb, 6); 567 | vg.PathWinding(Solidity.Hole); 568 | vg.FillPaint(shadowPaint); 569 | vg.Fill(); 570 | 571 | vg.BeginPath(); 572 | vg.RoundedRect(tx + 0.5f, ty + 0.5f, thumb - 1, thumb - 1, 4 - 0.5f); 573 | vg.StrokeWidth(1.0f); 574 | vg.StrokeColor(Utility.FromRGBA(255, 255, 255, 192)); 575 | vg.Stroke(); 576 | } 577 | vg.RestoreState(); 578 | 579 | // Hide fades 580 | fadePaint = vg.LinearGradient(x, y, x, y + 6, Utility.FromRGBA(200, 200, 200, 255), Utility.FromRGBA(200, 200, 200, 0)); 581 | vg.BeginPath(); 582 | vg.Rect(x + 4, y, w - 8, 6); 583 | vg.FillPaint(fadePaint); 584 | vg.Fill(); 585 | 586 | fadePaint = vg.LinearGradient(x, y + h, x, y + h - 6, Utility.FromRGBA(200, 200, 200, 255), Utility.FromRGBA(200, 200, 200, 0)); 587 | vg.BeginPath(); 588 | vg.Rect(x + 4, y + h - 6, w - 8, 6); 589 | vg.FillPaint(fadePaint); 590 | vg.Fill(); 591 | 592 | // Scroll bar 593 | shadowPaint = vg.BoxGradient(x + w - 12 + 1, y + 4 + 1, 8, h - 8, 3, 4, Utility.FromRGBA(0, 0, 0, 32), Utility.FromRGBA(0, 0, 0, 92)); 594 | vg.BeginPath(); 595 | vg.RoundedRect(x + w - 12, y + 4, 8, h - 8, 3); 596 | vg.FillPaint(shadowPaint); 597 | // vg.FillColor(GLUtility.FromRGBA(255,0,0,128)); 598 | vg.Fill(); 599 | 600 | scrollh = (h / stackh) * (h - 8); 601 | shadowPaint = vg.BoxGradient(x + w - 12 - 1, y + 4 + (h - 8 - scrollh) * u - 1, 8, scrollh, 3, 4, Utility.FromRGBA(220, 220, 220, 255), Utility.FromRGBA(128, 128, 128, 255)); 602 | vg.BeginPath(); 603 | vg.RoundedRect(x + w - 12 + 1, y + 4 + 1 + (h - 8 - scrollh) * u, 8 - 2, scrollh - 2, 2); 604 | vg.FillPaint(shadowPaint); 605 | // vg.FillColor(GLUtility.FromRGBA(0,0,0,128)); 606 | vg.Fill(); 607 | 608 | vg.RestoreState(); 609 | } 610 | 611 | public static void drawColorwheel(NvgContext vg, float x, float y, float w, float h, float t) 612 | { 613 | int i; 614 | float r0, r1, ax, ay, bx, by, cx, cy, aeps, r; 615 | float hue = (float)Math.Sin(t * 0.12f); 616 | Paint paint; 617 | 618 | vg.SaveState(); 619 | 620 | /* vg.BeginPath(); 621 | vg.Rect(x,y,w,h); 622 | vg.FillColor(GLUtility.FromRGBA(255,0,0,128)); 623 | vg.Fill();*/ 624 | 625 | cx = x + w * 0.5f; 626 | cy = y + h * 0.5f; 627 | r1 = (w < h ? w : h) * 0.5f - 5.0f; 628 | r0 = r1 - 20.0f; 629 | aeps = 0.5f / r1; // half a pixel arc length in radians (2pi cancels out). 630 | 631 | for (i = 0; i < 6; i++) 632 | { 633 | float a0 = (float)i / 6.0f * (float)Math.PI * 2.0f - aeps; 634 | float a1 = (float)(i + 1.0f) / 6.0f * (float)Math.PI * 2.0f + aeps; 635 | vg.BeginPath(); 636 | vg.Arc(cx, cy, r0, a0, a1, Winding.ClockWise); 637 | vg.Arc(cx, cy, r1, a1, a0, Winding.CounterClockWise); 638 | vg.ClosePath(); 639 | ax = cx + (float)Math.Cos(a0) * (r0 + r1) * 0.5f; 640 | ay = cy + (float)Math.Sin(a0) * (r0 + r1) * 0.5f; 641 | bx = cx + (float)Math.Cos(a1) * (r0 + r1) * 0.5f; 642 | by = cy + (float)Math.Sin(a1) * (r0 + r1) * 0.5f; 643 | paint = vg.LinearGradient(ax, ay, bx, by, Utility.HSLA(a0 / ((float)Math.PI * 2), 1.0f, 0.55f, 255), Utility.HSLA(a1 / ((float)Math.PI * 2), 1.0f, 0.55f, 255)); 644 | vg.FillPaint(paint); 645 | vg.Fill(); 646 | } 647 | 648 | vg.BeginPath(); 649 | vg.Circle(cx, cy, r0 - 0.5f); 650 | vg.Circle(cx, cy, r1 + 0.5f); 651 | vg.StrokeColor(Utility.FromRGBA(0, 0, 0, 64)); 652 | vg.StrokeWidth(1.0f); 653 | vg.Stroke(); 654 | 655 | // Selector 656 | vg.SaveState(); 657 | vg.Translate(cx, cy); 658 | vg.Rotate(hue * (float)Math.PI * 2); 659 | 660 | // Marker on 661 | vg.StrokeWidth(2.0f); 662 | vg.BeginPath(); 663 | vg.Rect(r0 - 1, -3, r1 - r0 + 2, 6); 664 | vg.StrokeColor(Utility.FromRGBA(255, 255, 255, 192)); 665 | vg.Stroke(); 666 | 667 | paint = vg.BoxGradient(r0 - 3, -5, r1 - r0 + 6, 10, 2, 4, Utility.FromRGBA(0, 0, 0, 128), Utility.FromRGBA(0, 0, 0, 0)); 668 | vg.BeginPath(); 669 | vg.Rect(r0 - 2 - 10, -4 - 10, r1 - r0 + 4 + 20, 8 + 20); 670 | vg.Rect(r0 - 2, -4, r1 - r0 + 4, 8); 671 | vg.PathWinding(Solidity.Hole); 672 | vg.FillPaint(paint); 673 | vg.Fill(); 674 | 675 | // Center triangle 676 | r = r0 - 6; 677 | ax = (float)Math.Cos(120.0f / 180.0f * (float)Math.PI) * r; 678 | ay = (float)Math.Sin(120.0f / 180.0f * (float)Math.PI) * r; 679 | bx = (float)Math.Cos(-120.0f / 180.0f * (float)Math.PI) * r; 680 | by = (float)Math.Sin(-120.0f / 180.0f * (float)Math.PI) * r; 681 | vg.BeginPath(); 682 | vg.MoveTo(r, 0); 683 | vg.LineTo(ax, ay); 684 | vg.LineTo(bx, by); 685 | vg.ClosePath(); 686 | paint = vg.LinearGradient(r, 0, ax, ay, Utility.HSLA(hue, 1.0f, 0.5f, 255), Utility.FromRGBA(255, 255, 255, 255)); 687 | vg.FillPaint(paint); 688 | vg.Fill(); 689 | paint = vg.LinearGradient((r + ax) * 0.5f, (0 + ay) * 0.5f, bx, by, Utility.FromRGBA(0, 0, 0, 0), Utility.FromRGBA(0, 0, 0, 255)); 690 | vg.FillPaint(paint); 691 | vg.Fill(); 692 | vg.StrokeColor(Utility.FromRGBA(0, 0, 0, 64)); 693 | vg.Stroke(); 694 | 695 | // Select circle on triangle 696 | ax = (float)Math.Cos(120.0f / 180.0f * (float)Math.PI) * r * 0.3f; 697 | ay = (float)Math.Sin(120.0f / 180.0f * (float)Math.PI) * r * 0.4f; 698 | vg.StrokeWidth(2.0f); 699 | vg.BeginPath(); 700 | vg.Circle(ax, ay, 5); 701 | vg.StrokeColor(Utility.FromRGBA(255, 255, 255, 192)); 702 | vg.Stroke(); 703 | 704 | paint = vg.RadialGradient(ax, ay, 7, 9, Utility.FromRGBA(0, 0, 0, 64), Utility.FromRGBA(0, 0, 0, 0)); 705 | vg.BeginPath(); 706 | vg.Rect(ax - 20, ay - 20, 40, 40); 707 | vg.Circle(ax, ay, 7); 708 | vg.PathWinding(Solidity.Hole); 709 | vg.FillPaint(paint); 710 | vg.Fill(); 711 | 712 | vg.RestoreState(); 713 | 714 | vg.RestoreState(); 715 | } 716 | 717 | public static void drawLines(NvgContext vg, float x, float y, float w, float h, float t) 718 | { 719 | int i, j; 720 | float pad = 5.0f, s = w / 9.0f - pad * 2; 721 | float[] pts = new float[4 * 2]; 722 | float fx, fy; 723 | LineCap[] joins = new LineCap[] { LineCap.Miter, LineCap.Round, LineCap.Bevel }; 724 | LineCap[] caps = new LineCap[] { LineCap.Butt, LineCap.Round, LineCap.Square }; 725 | 726 | vg.SaveState(); 727 | pts[0] = -s * 0.25f + (float)Math.Cos(t * 0.3f) * s * 0.5f; 728 | pts[1] = (float)Math.Sin(t * 0.3f) * s * 0.5f; 729 | pts[2] = -s * 0.25f; 730 | pts[3] = 0; 731 | pts[4] = s * 0.25f; 732 | pts[5] = 0; 733 | pts[6] = s * 0.25f + (float)Math.Cos(-t * 0.3f) * s * 0.5f; 734 | pts[7] = (float)Math.Sin(-t * 0.3f) * s * 0.5f; 735 | 736 | for (i = 0; i < 3; i++) 737 | { 738 | for (j = 0; j < 3; j++) 739 | { 740 | fx = x + s * 0.5f + (i * 3 + j) / 9.0f * w + pad; 741 | fy = y - s * 0.5f + pad; 742 | 743 | vg.LineCap(caps[i]); 744 | vg.LineJoin(joins[j]); 745 | 746 | vg.StrokeWidth(s * 0.3f); 747 | vg.StrokeColor(Utility.FromRGBA(0, 0, 0, 160)); 748 | vg.BeginPath(); 749 | vg.MoveTo(fx + pts[0], fy + pts[1]); 750 | vg.LineTo(fx + pts[2], fy + pts[3]); 751 | vg.LineTo(fx + pts[4], fy + pts[5]); 752 | vg.LineTo(fx + pts[6], fy + pts[7]); 753 | vg.Stroke(); 754 | 755 | vg.LineCap(LineCap.Butt); 756 | vg.LineJoin(LineCap.Bevel); 757 | 758 | vg.StrokeWidth(1.0f); 759 | vg.StrokeColor(Utility.FromRGBA(0, 192, 255, 255)); 760 | vg.BeginPath(); 761 | vg.MoveTo(fx + pts[0], fy + pts[1]); 762 | vg.LineTo(fx + pts[2], fy + pts[3]); 763 | vg.LineTo(fx + pts[4], fy + pts[5]); 764 | vg.LineTo(fx + pts[6], fy + pts[7]); 765 | vg.Stroke(); 766 | } 767 | } 768 | 769 | vg.RestoreState(); 770 | } 771 | 772 | private static FontSystem LoadFont(string path) 773 | { 774 | var result = new FontSystem(); 775 | using (var stream = File.OpenRead(path)) 776 | { 777 | result.AddFont(stream); 778 | } 779 | 780 | return result; 781 | } 782 | 783 | public static void drawWidths(NvgContext vg, float x, float y, float width) 784 | { 785 | int i; 786 | 787 | vg.SaveState(); 788 | 789 | vg.StrokeColor(Utility.FromRGBA(0, 0, 0, 255)); 790 | 791 | for (i = 0; i < 20; i++) 792 | { 793 | float w = (i + 0.5f) * 0.1f; 794 | vg.StrokeWidth(w); 795 | vg.BeginPath(); 796 | vg.MoveTo(x, y); 797 | vg.LineTo(x + width, y + width * 0.3f); 798 | vg.Stroke(); 799 | y += 10; 800 | } 801 | 802 | vg.RestoreState(); 803 | } 804 | 805 | public static void drawCaps(NvgContext vg, float x, float y, float width) 806 | { 807 | int i; 808 | LineCap[] caps = new[] { LineCap.Butt, LineCap.Round, LineCap.Square }; 809 | float lineWidth = 8.0f; 810 | 811 | vg.SaveState(); 812 | 813 | vg.BeginPath(); 814 | vg.Rect(x - lineWidth / 2, y, width + lineWidth, 40); 815 | vg.FillColor(Utility.FromRGBA(255, 255, 255, 32)); 816 | vg.Fill(); 817 | 818 | vg.BeginPath(); 819 | vg.Rect(x, y, width, 40); 820 | vg.FillColor(Utility.FromRGBA(255, 255, 255, 32)); 821 | vg.Fill(); 822 | 823 | vg.StrokeWidth(lineWidth); 824 | for (i = 0; i < 3; i++) 825 | { 826 | vg.LineCap(caps[i]); 827 | vg.StrokeColor(Utility.FromRGBA(0, 0, 0, 255)); 828 | vg.BeginPath(); 829 | vg.MoveTo(x, y + i * 10 + 5); 830 | vg.LineTo(x + width, y + i * 10 + 5); 831 | vg.Stroke(); 832 | } 833 | 834 | vg.RestoreState(); 835 | } 836 | 837 | public static void drawScissor(NvgContext vg, float x, float y, float t) 838 | { 839 | vg.SaveState(); 840 | 841 | // Draw first rect and set scissor to it's area. 842 | vg.Translate(x, y); 843 | vg.Rotate(Utility.DegToRad(5)); 844 | vg.BeginPath(); 845 | vg.Rect(-20, -20, 60, 40); 846 | vg.FillColor(Utility.FromRGBA(255, 0, 0, 255)); 847 | vg.Fill(); 848 | vg.Scissor(-20, -20, 60, 40); 849 | 850 | // Draw second rectangle with offset and rotation. 851 | vg.Translate(40, 0); 852 | vg.Rotate(t); 853 | 854 | // Draw the intended second rectangle without any scissoring. 855 | vg.SaveState(); 856 | vg.ResetScissor(); 857 | vg.BeginPath(); 858 | vg.Rect(-20, -10, 60, 30); 859 | vg.FillColor(Utility.FromRGBA(255, 128, 0, 64)); 860 | vg.Fill(); 861 | vg.RestoreState(); 862 | 863 | // Draw second rectangle with combined scissoring. 864 | vg.IntersectScissor(-20, -10, 60, 30); 865 | vg.BeginPath(); 866 | vg.Rect(-20, -10, 60, 30); 867 | vg.FillColor(Utility.FromRGBA(255, 128, 0, 255)); 868 | vg.Fill(); 869 | 870 | vg.RestoreState(); 871 | } 872 | 873 | public void renderDemo(NvgContext vg, float mx, float my, float width, float height, 874 | float t, bool blowup) 875 | { 876 | float x, y, popy; 877 | 878 | drawEyes(vg, width - 250, 50, 150, 100, mx, my, t); 879 | drawGraph(vg, 0, height / 2, width, height / 2, t); 880 | drawColorwheel(vg, width - 300, height - 300, 250.0f, 250.0f, t); 881 | 882 | // Line joints 883 | drawLines(vg, 120, height - 50, 600, 50, t); 884 | 885 | // Line caps 886 | drawWidths(vg, 10, 50, 30); 887 | 888 | // Line caps 889 | drawCaps(vg, 10, 300, 30); 890 | 891 | drawScissor(vg, 50, height - 80, t); 892 | 893 | vg.SaveState(); 894 | if (blowup) 895 | { 896 | vg.Rotate((float)Math.Sin(t * 0.3f) * 5.0f / 180.0f * (float)Math.PI); 897 | vg.Scale(2.0f, 2.0f); 898 | } 899 | 900 | // Widgets 901 | drawWindow(vg, "Widgets `n Stuff", 50, 50, 300, 400); 902 | x = 60; 903 | y = 95; 904 | drawSearchBox(vg, "Search", x, y, 280, 25); 905 | y += 40; 906 | drawDropDown(vg, "Effects", x, y, 280, 28); 907 | popy = y + 14; 908 | y += 45; 909 | 910 | // Form 911 | drawLabel(vg, "Login", x, y, 280, 20); 912 | y += 25; 913 | drawEditBox(vg, "Email", x, y, 280, 28); 914 | y += 35; 915 | drawEditBox(vg, "Password", x, y, 280, 28); 916 | y += 38; 917 | drawCheckBox(vg, "Remember me", x, y, 140, 28); 918 | drawButton(vg, ICON_LOGIN, "Sign in", x + 138, y, 140, 28, Utility.FromRGBA(0, 96, 128, 255)); 919 | y += 45; 920 | 921 | // Slider 922 | drawLabel(vg, "Diameter", x, y, 280, 20); 923 | y += 25; 924 | drawEditBoxNum(vg, "123.00", "px", x + 180, y, 100, 28); 925 | drawSlider(vg, 0.4f, x, y, 170, 28); 926 | y += 55; 927 | 928 | drawButton(vg, ICON_TRASH, "Delete", x, y, 160, 28, Utility.FromRGBA(128, 16, 8, 255)); 929 | drawButton(vg, null, "Cancel", x + 170, y, 110, 28, Utility.FromRGBA(0, 0, 0, 0)); 930 | 931 | // Thumbnails box 932 | drawThumbnails(vg, 365, popy - 30, 160, 300, images, t); 933 | 934 | vg.RestoreState(); 935 | } 936 | } 937 | } -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Demo/Game1.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using Microsoft.Xna.Framework.Graphics; 3 | using Microsoft.Xna.Framework.Input; 4 | using System; 5 | using System.Diagnostics; 6 | 7 | namespace NvgSharp.Samples.XNA 8 | { 9 | /// 10 | /// This is the main type for your game. 11 | /// 12 | public class Game1 : Game 13 | { 14 | GraphicsDeviceManager _graphics; 15 | 16 | private NvgContext _context; 17 | private SpriteBatch _spriteBatch; 18 | private Demo _demo; 19 | private PerfGraph _perfGraph; 20 | 21 | public Game1() 22 | { 23 | _graphics = new GraphicsDeviceManager(this) 24 | { 25 | PreferredBackBufferWidth = 1200, 26 | PreferredBackBufferHeight = 800, 27 | PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8 28 | }; 29 | 30 | Content.RootDirectory = "Content"; 31 | IsMouseVisible = true; 32 | Window.AllowUserResizing = true; 33 | IsFixedTimeStep = false; 34 | _graphics.SynchronizeWithVerticalRetrace = false; 35 | } 36 | 37 | /// 38 | /// LoadContent will be called once per game and is the place to load 39 | /// all of your content. 40 | /// 41 | protected override void LoadContent() 42 | { 43 | _context = new NvgContext(GraphicsDevice, true); 44 | 45 | _demo = new Demo(_context); 46 | 47 | _spriteBatch = new SpriteBatch(GraphicsDevice); 48 | _perfGraph = new PerfGraph(PerfGraph.Style.GRAPH_RENDER_FPS, "Frame Time", _demo.fontSystemNormal); 49 | } 50 | 51 | /// 52 | /// UnloadContent will be called once per game and is the place to unload 53 | /// game-specific content. 54 | /// 55 | protected override void UnloadContent() 56 | { 57 | // TODO: Unload any non ContentManager content here 58 | } 59 | 60 | protected override void Update(GameTime gameTime) 61 | { 62 | base.Update(gameTime); 63 | 64 | _perfGraph.Update((float)gameTime.ElapsedGameTime.TotalSeconds); 65 | 66 | if (dt == null) 67 | { 68 | dt = DateTime.Now; 69 | } 70 | else if ((DateTime.Now - dt.Value).TotalSeconds >= 1) 71 | { 72 | Trace.WriteLine("FPS: " + 1.0f / _perfGraph.GetAverage()); 73 | dt = DateTime.Now; 74 | } 75 | } 76 | 77 | DateTime? dt; 78 | 79 | /// 80 | /// This is called when the game should draw itself. 81 | /// 82 | /// Provides a snapshot of timing values. 83 | protected override void Draw(GameTime gameTime) 84 | { 85 | GraphicsDevice.Clear(new Color(0.3f, 0.3f, 0.3f)); 86 | 87 | if (_graphics.PreferredBackBufferWidth != Window.ClientBounds.Width || 88 | _graphics.PreferredBackBufferHeight != Window.ClientBounds.Height) 89 | { 90 | _graphics.PreferredBackBufferWidth = Window.ClientBounds.Width; 91 | _graphics.PreferredBackBufferHeight = Window.ClientBounds.Height; 92 | _graphics.ApplyChanges(); 93 | } 94 | 95 | // TODO: Add your drawing code here 96 | 97 | var mouseState = Mouse.GetState(); 98 | 99 | _context.ResetState(); 100 | 101 | var t = (float)gameTime.TotalGameTime.TotalSeconds; 102 | _demo.renderDemo(_context, 103 | mouseState.X, 104 | mouseState.Y, 105 | _graphics.PreferredBackBufferWidth, 106 | _graphics.PreferredBackBufferHeight, 107 | t, 108 | false); 109 | 110 | _perfGraph.Render(_context, 5, 5); 111 | 112 | _context.Flush(); 113 | 114 | /* var texture = ((XNARenderer)_context._renderer)._textures[8]; 115 | 116 | _spriteBatch.Begin(); 117 | _spriteBatch.Draw(texture, Vector2.Zero, Color.White); 118 | _spriteBatch.End();*/ 119 | 120 | base.Draw(gameTime); 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Demo/Icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/samples/NvgSharp.Samples.Demo/Icon.ico -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Demo/NvgExtensions.cs: -------------------------------------------------------------------------------- 1 | using FontStashSharp; 2 | using System.Text; 3 | 4 | namespace NvgSharp 5 | { 6 | public enum TextHorizontalAlignment 7 | { 8 | /// 9 | /// Default, align text horizontally to left 10 | /// 11 | Left, 12 | 13 | /// 14 | /// Align text horizontally to center 15 | /// 16 | Center, 17 | 18 | /// 19 | /// Align text horizontally to right 20 | /// 21 | Right 22 | } 23 | 24 | public enum TextVerticalAlignment 25 | { 26 | /// 27 | /// Default, Align text vertically to top 28 | /// 29 | Top, 30 | 31 | /// 32 | /// Align text vertically to middle 33 | /// 34 | Center, 35 | 36 | /// 37 | /// Align text vertically to bottom 38 | /// 39 | Bottom 40 | } 41 | 42 | internal static class NvgExtensions 43 | { 44 | public static void TextAligned(this NvgContext context, SpriteFontBase font, string text, float x, float y, 45 | TextHorizontalAlignment horizontalAlignment = TextHorizontalAlignment.Left, TextVerticalAlignment verticalAlignment = TextVerticalAlignment.Top, 46 | float layerDepth = 0.0f, float characterSpacing = 0.0f, float lineSpacing = 0.0f) 47 | { 48 | if (string.IsNullOrEmpty(text)) 49 | { 50 | return; 51 | } 52 | 53 | if (horizontalAlignment != TextHorizontalAlignment.Left) 54 | { 55 | var sz = font.MeasureString(text); 56 | if (horizontalAlignment == TextHorizontalAlignment.Center) 57 | { 58 | x -= sz.X / 2.0f; 59 | } 60 | else if (horizontalAlignment == TextHorizontalAlignment.Right) 61 | { 62 | x -= sz.X; 63 | } 64 | } 65 | 66 | if (verticalAlignment == TextVerticalAlignment.Center) 67 | { 68 | y -= font.LineHeight / 2.0f; 69 | } 70 | else if (verticalAlignment == TextVerticalAlignment.Bottom) 71 | { 72 | y -= font.LineHeight; 73 | } 74 | 75 | context.Text(font, text, x, y, layerDepth, characterSpacing, lineSpacing); 76 | } 77 | 78 | public static void TextAligned(this NvgContext context, SpriteFontBase font, StringBuilder text, float x, float y, 79 | TextHorizontalAlignment horizontalAlignment = TextHorizontalAlignment.Left, TextVerticalAlignment verticalAlignment = TextVerticalAlignment.Top, 80 | float layerDepth = 0.0f, float characterSpacing = 0.0f, float lineSpacing = 0.0f) 81 | { 82 | if (text == null || text.Length == 0) 83 | { 84 | return; 85 | } 86 | 87 | if (horizontalAlignment != TextHorizontalAlignment.Left) 88 | { 89 | var sz = font.MeasureString(text); 90 | if (horizontalAlignment == TextHorizontalAlignment.Center) 91 | { 92 | x -= sz.X / 2.0f; 93 | } 94 | else if (horizontalAlignment == TextHorizontalAlignment.Right) 95 | { 96 | x -= sz.X; 97 | } 98 | } 99 | 100 | if (verticalAlignment == TextVerticalAlignment.Center) 101 | { 102 | y -= font.LineHeight / 2.0f; 103 | } 104 | else if (verticalAlignment == TextVerticalAlignment.Bottom) 105 | { 106 | y -= font.LineHeight; 107 | } 108 | 109 | context.Text(font, text, x, y, layerDepth, characterSpacing, lineSpacing); 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Demo/NvgSharp.Samples.Demo.FNA.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net6.0 5 | bin\FNA.Core\$(Configuration) 6 | $(DefineConstants);FNA 7 | 8 | 9 | 10 | PreserveNewest 11 | 12 | 13 | PreserveNewest 14 | 15 | 16 | PreserveNewest 17 | 18 | 19 | PreserveNewest 20 | 21 | 22 | PreserveNewest 23 | 24 | 25 | PreserveNewest 26 | 27 | 28 | PreserveNewest 29 | 30 | 31 | PreserveNewest 32 | 33 | 34 | PreserveNewest 35 | 36 | 37 | PreserveNewest 38 | 39 | 40 | PreserveNewest 41 | 42 | 43 | PreserveNewest 44 | 45 | 46 | 47 | 48 | 49 | PreserveNewest 50 | 51 | 52 | PreserveNewest 53 | 54 | 55 | PreserveNewest 56 | 57 | 58 | PreserveNewest 59 | 60 | 61 | PreserveNewest 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Demo/NvgSharp.Samples.Demo.FNA.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | WinExe 4 | net461 5 | bin\FNA\$(Configuration) 6 | $(DefineConstants);FNA 7 | 8 | 9 | 10 | PreserveNewest 11 | 12 | 13 | PreserveNewest 14 | 15 | 16 | PreserveNewest 17 | 18 | 19 | PreserveNewest 20 | 21 | 22 | PreserveNewest 23 | 24 | 25 | PreserveNewest 26 | 27 | 28 | PreserveNewest 29 | 30 | 31 | PreserveNewest 32 | 33 | 34 | PreserveNewest 35 | 36 | 37 | PreserveNewest 38 | 39 | 40 | PreserveNewest 41 | 42 | 43 | PreserveNewest 44 | 45 | 46 | 47 | 48 | 49 | PreserveNewest 50 | 51 | 52 | PreserveNewest 53 | 54 | 55 | PreserveNewest 56 | 57 | 58 | PreserveNewest 59 | 60 | 61 | PreserveNewest 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Demo/NvgSharp.Samples.Demo.MonoGame.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | WinExe 4 | net6.0 5 | bin\MonoGame\$(Configuration) 6 | $(DefineConstants);MONOGAME 7 | 8 | 9 | 10 | PreserveNewest 11 | 12 | 13 | PreserveNewest 14 | 15 | 16 | PreserveNewest 17 | 18 | 19 | PreserveNewest 20 | 21 | 22 | PreserveNewest 23 | 24 | 25 | PreserveNewest 26 | 27 | 28 | PreserveNewest 29 | 30 | 31 | PreserveNewest 32 | 33 | 34 | PreserveNewest 35 | 36 | 37 | PreserveNewest 38 | 39 | 40 | PreserveNewest 41 | 42 | 43 | PreserveNewest 44 | 45 | 46 | 47 | 48 | 49 | PreserveNewest 50 | 51 | 52 | PreserveNewest 53 | 54 | 55 | PreserveNewest 56 | 57 | 58 | PreserveNewest 59 | 60 | 61 | PreserveNewest 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Demo/PerfGraph.cs: -------------------------------------------------------------------------------- 1 | using FontStashSharp; 2 | 3 | #if MONOGAME || FNA 4 | using Microsoft.Xna.Framework; 5 | #elif STRIDE 6 | using Stride.Core.Mathematics; 7 | #else 8 | using System.Drawing; 9 | using Texture2D = System.Object; 10 | #endif 11 | 12 | namespace NvgSharp.Samples 13 | { 14 | public class PerfGraph 15 | { 16 | public enum Style 17 | { 18 | GRAPH_RENDER_FPS, 19 | GRAPH_RENDER_MS, 20 | GRAPH_RENDER_PERCENT, 21 | }; 22 | 23 | private Style _style; 24 | private string _name; 25 | private float[] _values = new float[100]; 26 | private int _head; 27 | private readonly FontSystem _fontSystem; 28 | 29 | public PerfGraph(Style style, string name, FontSystem fontSystem) 30 | { 31 | _style = style; 32 | _name = name; 33 | _fontSystem = fontSystem; 34 | } 35 | 36 | public void Update(float frameTime) 37 | { 38 | _head = (_head + 1) % _values.Length; 39 | _values[_head] = frameTime; 40 | } 41 | 42 | public float GetAverage() 43 | { 44 | float avg = 0; 45 | for (var i = 0; i < _values.Length; i++) 46 | { 47 | avg += _values[i]; 48 | } 49 | return avg / _values.Length; 50 | } 51 | 52 | public void Render(NvgContext vg, float x, float y) 53 | { 54 | int i; 55 | float avg, w, h; 56 | string str; 57 | 58 | avg = GetAverage(); 59 | 60 | w = 200; 61 | h = 35; 62 | 63 | vg.BeginPath(); 64 | vg.Rect(x, y, w, h); 65 | vg.FillColor(Utility.FromRGBA(0, 0, 0, 128)); 66 | vg.Fill(); 67 | 68 | vg.BeginPath(); 69 | vg.MoveTo(x, y + h); 70 | if (_style == Style.GRAPH_RENDER_FPS) 71 | { 72 | for (i = 0; i < _values.Length; i++) 73 | { 74 | float v = 1.0f / (0.00001f + _values[(_head + i) % _values.Length]); 75 | float vx, vy; 76 | if (v > 80.0f) 77 | v = 80.0f; 78 | vx = x + ((float)i / (_values.Length - 1)) * w; 79 | vy = y + h - ((v / 80.0f) * h); 80 | vg.LineTo(vx, vy); 81 | } 82 | } 83 | else if (_style == Style.GRAPH_RENDER_PERCENT) 84 | { 85 | for (i = 0; i < _values.Length; i++) 86 | { 87 | float v = _values[(_head + i) % _values.Length] * 1.0f; 88 | float vx, vy; 89 | if (v > 100.0f) 90 | v = 100.0f; 91 | vx = x + ((float)i / (_values.Length - 1)) * w; 92 | vy = y + h - ((v / 100.0f) * h); 93 | vg.LineTo(vx, vy); 94 | } 95 | } 96 | else 97 | { 98 | for (i = 0; i < _values.Length; i++) 99 | { 100 | float v = _values[(_head + i) % _values.Length] * 1000.0f; 101 | float vx, vy; 102 | if (v > 20.0f) 103 | v = 20.0f; 104 | vx = x + ((float)i / (_values.Length - 1)) * w; 105 | vy = y + h - ((v / 20.0f) * h); 106 | vg.LineTo(vx, vy); 107 | } 108 | } 109 | vg.LineTo(x + w, y + h); 110 | vg.FillColor(Utility.FromRGBA(255, 192, 0, 128)); 111 | vg.Fill(); 112 | 113 | if (!string.IsNullOrEmpty(_name)) 114 | { 115 | var font = _fontSystem.GetFont(14); 116 | vg.FillColor(Utility.FromRGBA(240, 240, 240, 192)); 117 | vg.TextAligned(font, _name, x + 3, y + 1, TextHorizontalAlignment.Left, TextVerticalAlignment.Top); 118 | } 119 | 120 | if (_style == Style.GRAPH_RENDER_FPS) 121 | { 122 | var font = _fontSystem.GetFont(18); 123 | vg.FillColor(Utility.FromRGBA(240, 240, 240, 255)); 124 | str = string.Format("{0:0.00} FPS", 1.0f / avg); 125 | vg.TextAligned(font, str, x + w - 3, y + 1, TextHorizontalAlignment.Right, TextVerticalAlignment.Top); 126 | 127 | font = _fontSystem.GetFont(15); 128 | vg.FillColor(Utility.FromRGBA(240, 240, 240, 160)); 129 | str = string.Format("{0:0.00} ms", avg * 1000.0f); 130 | vg.TextAligned(font, str, x + w - 3, y + h - 1, TextHorizontalAlignment.Right, TextVerticalAlignment.Bottom); 131 | } 132 | else if (_style == Style.GRAPH_RENDER_PERCENT) 133 | { 134 | var font = _fontSystem.GetFont(18); 135 | vg.FillColor(Utility.FromRGBA(240, 240, 240, 255)); 136 | str = string.Format("{0:0.00} %%", avg); 137 | vg.TextAligned(font, str, x + w - 3, y + 1, TextHorizontalAlignment.Right, TextVerticalAlignment.Top); 138 | } 139 | else 140 | { 141 | var font = _fontSystem.GetFont(18); 142 | vg.FillColor(Utility.FromRGBA(240, 240, 240, 255)); 143 | str = string.Format("{0:0.00} ms", avg * 1000.0f); 144 | vg.TextAligned(font, str, x + w - 3, y + 1, TextHorizontalAlignment.Right, TextVerticalAlignment.Top); 145 | } 146 | } 147 | 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Demo/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NvgSharp.Samples.XNA 4 | { 5 | /// 6 | /// The main class. 7 | /// 8 | public static class Program 9 | { 10 | /// 11 | /// The main entry point for the application. 12 | /// 13 | [STAThread] 14 | static void Main() 15 | { 16 | using (var game = new Game1()) 17 | game.Run(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Demo/Utility.cs: -------------------------------------------------------------------------------- 1 | #if MONOGAME || FNA 2 | using Microsoft.Xna.Framework; 3 | #elif STRIDE 4 | using Stride.Core.Mathematics; 5 | #else 6 | using System.Drawing; 7 | #endif 8 | 9 | namespace NvgSharp.Samples 10 | { 11 | internal static class Utility 12 | { 13 | public static float Mod(float a, float b) 14 | { 15 | return (float)(a % b); 16 | } 17 | 18 | public static float Clamp(float a, float mn, float mx) 19 | { 20 | return (float)((a) < (mn) ? mn : ((a) > (mx) ? mx : a)); 21 | } 22 | 23 | public static float Hue(float h, float m1, float m2) 24 | { 25 | if ((h) < (0)) 26 | h += (float)(1); 27 | if ((h) > (1)) 28 | h -= (float)(1); 29 | if ((h) < (1.0f / 6.0f)) 30 | return (float)(m1 + (m2 - m1) * h * 6.0f); 31 | else if ((h) < (3.0f / 6.0f)) 32 | return (float)(m2); 33 | else if ((h) < (4.0f / 6.0f)) 34 | return (float)(m1 + (m2 - m1) * (2.0f / 3.0f - h) * 6.0f); 35 | return (float)(m1); 36 | } 37 | 38 | public static Color HSLA(float h, float s, float l, byte a) 39 | { 40 | h = (float)(Mod((float)(h), (float)(1.0f))); 41 | if ((h) < (0.0f)) 42 | h += (float)(1.0f); 43 | s = (float)(Clamp((float)(s), (float)(0.0f), (float)(1.0f))); 44 | l = (float)(Clamp((float)(l), (float)(0.0f), (float)(1.0f))); 45 | var m2 = (float)(l <= 0.5f ? (l * (1 + s)) : (l + s - l * s)); 46 | var m1 = (float)(2 * l - m2); 47 | 48 | float fr = (float)(Clamp((float)(Hue((float)(h + 1.0f / 3.0f), (float)(m1), (float)(m2))), (float)(0.0f), (float)(1.0f))); 49 | float fg = (float)(Clamp((float)(Hue((float)(h), (float)(m1), (float)(m2))), (float)(0.0f), (float)(1.0f))); 50 | float fb = (float)(Clamp((float)(Hue((float)(h - 1.0f / 3.0f), (float)(m1), (float)(m2))), (float)(0.0f), (float)(1.0f))); 51 | float fa = (float)(a / 255.0f); 52 | 53 | return FromRGBA((byte)(int)(fr * 255), (byte)(int)(fg * 255), (byte)(int)(fb * 255), (byte)(int)(fa * 255)); 54 | } 55 | 56 | public static float DegToRad(float deg) 57 | { 58 | return (float)(deg / 180.0f * 3.14159274); 59 | } 60 | 61 | public static float RadToDeg(float rad) 62 | { 63 | return (float)(rad / 3.14159274 * 180.0f); 64 | } 65 | 66 | public static Color FromRGBA(byte r, byte g, byte b, byte a) 67 | { 68 | #if MONOGAME || FNA || STRIDE 69 | return new Color(r, g, b, a); 70 | #else 71 | return Color.FromArgb(a, r, g, b); 72 | #endif 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.OpenTK/BufferObject.cs: -------------------------------------------------------------------------------- 1 | using OpenTK.Graphics.OpenGL4; 2 | using System; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace NvgSharp.Samples 6 | { 7 | public class BufferObject : IDisposable where T : unmanaged 8 | { 9 | private readonly int _handle; 10 | private readonly BufferTarget _bufferType; 11 | private readonly int _size; 12 | 13 | public int Size => _size; 14 | 15 | public unsafe BufferObject(int size, BufferTarget bufferType, bool isDynamic) 16 | { 17 | _bufferType = bufferType; 18 | _size = size; 19 | 20 | _handle = GL.GenBuffer(); 21 | GLUtility.CheckError(); 22 | 23 | Bind(); 24 | 25 | var elementSizeInBytes = Marshal.SizeOf(); 26 | GL.BufferData(bufferType, size * elementSizeInBytes, IntPtr.Zero, isDynamic ? BufferUsageHint.StreamDraw : BufferUsageHint.StaticDraw); 27 | GLUtility.CheckError(); 28 | } 29 | 30 | public void Bind() 31 | { 32 | GL.BindBuffer(_bufferType, _handle); 33 | GLUtility.CheckError(); 34 | } 35 | 36 | public void Dispose() 37 | { 38 | GL.DeleteBuffer(_handle); 39 | GLUtility.CheckError(); 40 | } 41 | 42 | public unsafe void SetData(T[] data, int startIndex, int elementCount) 43 | { 44 | Bind(); 45 | 46 | fixed(T* dataPtr = &data[startIndex]) 47 | { 48 | var elementSizeInBytes = sizeof(T); 49 | 50 | GL.BufferSubData(_bufferType, IntPtr.Zero, elementCount * elementSizeInBytes, new IntPtr(dataPtr)); 51 | GLUtility.CheckError(); 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.OpenTK/GLUtility.cs: -------------------------------------------------------------------------------- 1 | using OpenTK.Graphics.OpenGL4; 2 | using System; 3 | 4 | 5 | namespace NvgSharp.Samples 6 | { 7 | internal static class GLUtility 8 | { 9 | public static void CheckError() 10 | { 11 | var error = GL.GetError(); 12 | if (error != ErrorCode.NoError) 13 | throw new Exception("GL.GetError() returned " + error.ToString()); 14 | } 15 | 16 | public static void DrawStroke(this FillStrokeInfo fillStrokeInfo, PrimitiveType primitiveType) 17 | { 18 | if (fillStrokeInfo.StrokeCount <= 0) 19 | { 20 | return; 21 | } 22 | 23 | GL.DrawArrays(primitiveType, fillStrokeInfo.StrokeOffset, fillStrokeInfo.StrokeCount); 24 | CheckError(); 25 | } 26 | 27 | public static void DrawFill(this FillStrokeInfo fillStrokeInfo, PrimitiveType primitiveType) 28 | { 29 | if (fillStrokeInfo.FillCount <= 0) 30 | { 31 | return; 32 | } 33 | 34 | GL.DrawArrays(primitiveType, fillStrokeInfo.FillOffset, fillStrokeInfo.FillCount); 35 | CheckError(); 36 | } 37 | 38 | public static void DrawTriangles(this CallInfo callInfo, PrimitiveType primitiveType) 39 | { 40 | if (callInfo.TriangleCount <= 0) 41 | { 42 | return; 43 | } 44 | 45 | GL.DrawArrays(primitiveType, callInfo.TriangleOffset, callInfo.TriangleCount); 46 | CheckError(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.OpenTK/NvgSharp.Samples.OpenTK.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | PreserveNewest 19 | 20 | 21 | PreserveNewest 22 | 23 | 24 | PreserveNewest 25 | 26 | 27 | PreserveNewest 28 | 29 | 30 | PreserveNewest 31 | 32 | 33 | PreserveNewest 34 | 35 | 36 | PreserveNewest 37 | 38 | 39 | PreserveNewest 40 | 41 | 42 | PreserveNewest 43 | 44 | 45 | PreserveNewest 46 | 47 | 48 | PreserveNewest 49 | 50 | 51 | PreserveNewest 52 | 53 | 54 | 55 | 56 | 57 | PreserveNewest 58 | 59 | 60 | PreserveNewest 61 | 62 | 63 | PreserveNewest 64 | 65 | 66 | PreserveNewest 67 | 68 | 69 | PreserveNewest 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | PreserveNewest 82 | 83 | 84 | PreserveNewest 85 | 86 | 87 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.OpenTK/Platform/Renderer.cs: -------------------------------------------------------------------------------- 1 | using OpenTK.Graphics.OpenGL4; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Numerics; 5 | 6 | namespace NvgSharp.Samples 7 | { 8 | internal class Renderer : INvgRenderer 9 | { 10 | private const int MAX_VERTICES = 8192; 11 | 12 | private readonly Shader _shader; 13 | private BufferObject _vertexBuffer; 14 | private readonly VertexArrayObject _vao; 15 | private readonly bool _edgeAntiAlias, _stencilStrokes; 16 | private readonly int[] _viewPortValues = new int[4]; 17 | 18 | public bool EdgeAntiAlias => _edgeAntiAlias; 19 | 20 | public unsafe Renderer(bool edgeAntiAlias = true, bool stencilStrokes = true) 21 | { 22 | _edgeAntiAlias = edgeAntiAlias; 23 | _stencilStrokes = stencilStrokes; 24 | 25 | var defines = new Dictionary(); 26 | if (edgeAntiAlias) 27 | { 28 | defines["EDGE_AA"] = "1"; 29 | } 30 | 31 | _shader = new Shader("shader.vert", "shader.frag", defines); 32 | _vertexBuffer = new BufferObject(MAX_VERTICES, BufferTarget.ArrayBuffer, true); 33 | _vao = new VertexArrayObject(sizeof(Vertex)); 34 | } 35 | 36 | ~Renderer() => Dispose(false); 37 | 38 | public void Dispose() => Dispose(true); 39 | 40 | protected virtual void Dispose(bool disposing) 41 | { 42 | if (!disposing) 43 | { 44 | return; 45 | } 46 | 47 | _vao.Dispose(); 48 | _vertexBuffer.Dispose(); 49 | _shader.Dispose(); 50 | } 51 | 52 | public object CreateTexture(int width, int height) => new Texture(width, height); 53 | 54 | public Point GetTextureSize(object texture) 55 | { 56 | var t = (Texture)texture; 57 | return new Point(t.Width, t.Height); 58 | } 59 | 60 | public void SetTextureData(object texture, Rectangle bounds, byte[] data) 61 | { 62 | var t = (Texture)texture; 63 | t.SetData(bounds, data); 64 | } 65 | 66 | private void SetUniform(ref UniformInfo uniform) 67 | { 68 | _shader.SetUniform("scissorMat", uniform.scissorMat); 69 | _shader.SetUniform("paintMat", uniform.paintMat); 70 | _shader.SetUniform("innerCol", uniform.innerCol); 71 | _shader.SetUniform("outerCol", uniform.outerCol); 72 | _shader.SetUniform("scissorExt", uniform.scissorExt); 73 | _shader.SetUniform("scissorScale", uniform.scissorScale); 74 | _shader.SetUniform("extent", uniform.extent); 75 | _shader.SetUniform("radius", uniform.radius); 76 | _shader.SetUniform("feather", uniform.feather); 77 | _shader.SetUniform("type", (int)uniform.type); 78 | 79 | if (uniform.Image != null) 80 | { 81 | var texture = (Texture)uniform.Image; 82 | texture.Bind(); 83 | } 84 | else 85 | { 86 | GL.BindTexture(TextureTarget.Texture2D, 0); 87 | GLUtility.CheckError(); 88 | } 89 | 90 | if (_edgeAntiAlias) 91 | { 92 | _shader.SetUniform("strokeMult", uniform.strokeMult); 93 | _shader.SetUniform("strokeThr", uniform.strokeThr); 94 | } 95 | } 96 | 97 | private void ProcessFill(CallInfo call) 98 | { 99 | // Draw shapes 100 | GL.Enable(EnableCap.StencilTest); 101 | GLUtility.CheckError(); 102 | GL.StencilMask(0xff); 103 | GLUtility.CheckError(); 104 | GL.StencilFunc(StencilFunction.Always, 0, 0xff); 105 | GLUtility.CheckError(); 106 | GL.ColorMask(false, false, false, false); 107 | GLUtility.CheckError(); 108 | 109 | SetUniform(ref call.UniformInfo); 110 | 111 | // set bindpoint for solid loc 112 | GL.StencilOpSeparate(StencilFace.Front, StencilOp.Keep, StencilOp.Keep, StencilOp.IncrWrap); 113 | GLUtility.CheckError(); 114 | GL.StencilOpSeparate(StencilFace.Back, StencilOp.Keep, StencilOp.Keep, StencilOp.DecrWrap); 115 | GLUtility.CheckError(); 116 | 117 | GL.Disable(EnableCap.CullFace); 118 | GLUtility.CheckError(); 119 | 120 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 121 | { 122 | call.FillStrokeInfos[i].DrawFill(PrimitiveType.TriangleFan); 123 | } 124 | 125 | GL.Enable(EnableCap.CullFace); 126 | GLUtility.CheckError(); 127 | 128 | // Draw anti-aliased pixels 129 | GL.ColorMask(true, true, true, true); 130 | GLUtility.CheckError(); 131 | 132 | SetUniform(ref call.UniformInfo2); 133 | 134 | if (_edgeAntiAlias) 135 | { 136 | GL.StencilFunc(StencilFunction.Equal, 0, 0xff); 137 | GLUtility.CheckError(); 138 | GL.StencilOp(StencilOp.Keep, StencilOp.Keep, StencilOp.Keep); 139 | GLUtility.CheckError(); 140 | 141 | // Draw fringes 142 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 143 | { 144 | call.FillStrokeInfos[i].DrawStroke(PrimitiveType.TriangleStrip); 145 | } 146 | } 147 | 148 | // Draw fill 149 | GL.StencilFunc(StencilFunction.Notequal, 0, 0xff); 150 | GLUtility.CheckError(); 151 | GL.StencilOp(StencilOp.Zero, StencilOp.Zero, StencilOp.Zero); 152 | GLUtility.CheckError(); 153 | 154 | call.DrawTriangles(PrimitiveType.TriangleStrip); 155 | 156 | GL.Disable(EnableCap.StencilTest); 157 | GLUtility.CheckError(); 158 | } 159 | 160 | private void ProcessConvexFill(CallInfo call) 161 | { 162 | SetUniform(ref call.UniformInfo); 163 | 164 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 165 | { 166 | var fillStrokeInfo = call.FillStrokeInfos[i]; 167 | 168 | fillStrokeInfo.DrawFill(PrimitiveType.TriangleFan); 169 | fillStrokeInfo.DrawStroke(PrimitiveType.TriangleStrip); 170 | } 171 | } 172 | 173 | private void ProcessStroke(CallInfo call) 174 | { 175 | if (_stencilStrokes) 176 | { 177 | // Fill the stroke base without overlap 178 | GL.Enable(EnableCap.StencilTest); 179 | GLUtility.CheckError(); 180 | GL.StencilMask(0xff); 181 | GLUtility.CheckError(); 182 | GL.StencilFunc(StencilFunction.Equal, 0, 0xff); 183 | GLUtility.CheckError(); 184 | GL.StencilOp(StencilOp.Keep, StencilOp.Keep, StencilOp.Incr); 185 | GLUtility.CheckError(); 186 | 187 | SetUniform(ref call.UniformInfo2); 188 | 189 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 190 | { 191 | call.FillStrokeInfos[i].DrawStroke(PrimitiveType.TriangleStrip); 192 | } 193 | 194 | // Draw anti-aliased pixels. 195 | SetUniform(ref call.UniformInfo); 196 | 197 | GL.StencilFunc(StencilFunction.Equal, 0, 0xff); 198 | GLUtility.CheckError(); 199 | GL.StencilOp(StencilOp.Keep, StencilOp.Keep, StencilOp.Keep); 200 | GLUtility.CheckError(); 201 | 202 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 203 | { 204 | call.FillStrokeInfos[i].DrawStroke(PrimitiveType.TriangleStrip); 205 | } 206 | 207 | // Clear stencil buffer. 208 | GL.ColorMask(false, false, false, false); 209 | GLUtility.CheckError(); 210 | 211 | GL.StencilFunc(StencilFunction.Always, 0, 0xff); 212 | GLUtility.CheckError(); 213 | GL.StencilOp(StencilOp.Zero, StencilOp.Zero, StencilOp.Zero); 214 | GLUtility.CheckError(); 215 | 216 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 217 | { 218 | call.FillStrokeInfos[i].DrawStroke(PrimitiveType.TriangleStrip); 219 | } 220 | 221 | GL.ColorMask(true, true, true, true); 222 | GLUtility.CheckError(); 223 | 224 | GL.Disable(EnableCap.StencilTest); 225 | GLUtility.CheckError(); 226 | } 227 | else 228 | { 229 | SetUniform(ref call.UniformInfo); 230 | 231 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 232 | { 233 | call.FillStrokeInfos[i].DrawStroke(PrimitiveType.TriangleStrip); 234 | } 235 | } 236 | } 237 | 238 | private void ProcessTriangles(CallInfo call) 239 | { 240 | SetUniform(ref call.UniformInfo); 241 | 242 | call.DrawTriangles(PrimitiveType.Triangles); 243 | } 244 | 245 | public void Draw(float devicePixelRatio, IEnumerable calls, Vertex[] vertexes) 246 | { 247 | // Setup required GL state 248 | GL.Enable(EnableCap.CullFace); 249 | GLUtility.CheckError(); 250 | GL.CullFace(CullFaceMode.Back); 251 | GLUtility.CheckError(); 252 | GL.FrontFace(FrontFaceDirection.Ccw); 253 | GLUtility.CheckError(); 254 | GL.Enable(EnableCap.Blend); 255 | GLUtility.CheckError(); 256 | GL.Disable(EnableCap.DepthTest); 257 | GLUtility.CheckError(); 258 | GL.Disable(EnableCap.ScissorTest); 259 | GLUtility.CheckError(); 260 | GL.ColorMask(true, true, true, true); 261 | GLUtility.CheckError(); 262 | GL.StencilMask(0xffffffff); 263 | GLUtility.CheckError(); 264 | GL.StencilOp(StencilOp.Keep, StencilOp.Keep, StencilOp.Keep); 265 | GLUtility.CheckError(); 266 | GL.StencilFunc(StencilFunction.Always, 0, 0xffffffff); 267 | GLUtility.CheckError(); 268 | GL.ActiveTexture(TextureUnit.Texture0); 269 | GLUtility.CheckError(); 270 | GL.BindTexture(TextureTarget.Texture2D, 0); 271 | GLUtility.CheckError(); 272 | 273 | // Bind and update vertex buffer 274 | if (_vertexBuffer.Size < vertexes.Length) 275 | { 276 | _vertexBuffer = new BufferObject(vertexes.Length, BufferTarget.ArrayBuffer, true); 277 | } 278 | 279 | _vertexBuffer.Bind(); 280 | _vertexBuffer.SetData(vertexes, 0, vertexes.Length); 281 | 282 | // Setup vao 283 | _vao.Bind(); 284 | var location = _shader.GetAttribLocation("vertex"); 285 | _vao.VertexAttribPointer(location, 2, VertexAttribPointerType.Float, false, 0); 286 | 287 | location = _shader.GetAttribLocation("tcoord"); 288 | _vao.VertexAttribPointer(location, 2, VertexAttribPointerType.Float, false, 8); 289 | 290 | // Setup shader 291 | _shader.Use(); 292 | _shader.SetUniform("tex", 0); 293 | 294 | GL.GetInteger(GetPName.Viewport, _viewPortValues); 295 | GLUtility.CheckError(); 296 | 297 | var transform = Matrix4x4.CreateOrthographicOffCenter(0, _viewPortValues[2], _viewPortValues[3], 0, 0, -1); 298 | _shader.SetUniform("transformMat", transform); 299 | 300 | GL.BlendFunc(BlendingFactor.One, BlendingFactor.OneMinusSrcAlpha); 301 | GLUtility.CheckError(); 302 | 303 | // Process calls 304 | foreach (var call in calls) 305 | { 306 | switch (call.Type) 307 | { 308 | case CallType.Fill: 309 | ProcessFill(call); 310 | break; 311 | case CallType.ConvexFill: 312 | ProcessConvexFill(call); 313 | break; 314 | case CallType.Stroke: 315 | ProcessStroke(call); 316 | break; 317 | case CallType.Triangles: 318 | ProcessTriangles(call); 319 | break; 320 | } 321 | } 322 | } 323 | } 324 | } 325 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.OpenTK/Program.cs: -------------------------------------------------------------------------------- 1 | using OpenTK.Mathematics; 2 | using OpenTK.Windowing.Common; 3 | using OpenTK.Windowing.Desktop; 4 | 5 | namespace NvgSharp.Samples 6 | { 7 | class Program 8 | { 9 | private static void Main(string[] args) 10 | { 11 | var nativeWindowSettings = new NativeWindowSettings() 12 | { 13 | Size = new Vector2i(1200, 800), 14 | Title = "NvgSharp.Samples.OpenTK", 15 | // This is needed to run on macos 16 | Flags = ContextFlags.ForwardCompatible, 17 | }; 18 | 19 | using (var window = new Window(GameWindowSettings.Default, nativeWindowSettings)) 20 | { 21 | window.Run(); 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.OpenTK/Shader.cs: -------------------------------------------------------------------------------- 1 | using OpenTK.Graphics.OpenGL4; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Numerics; 6 | using System.Text; 7 | 8 | namespace NvgSharp.Samples 9 | { 10 | public class Shader : IDisposable 11 | { 12 | private int _handle; 13 | 14 | public Shader(string vertexPath, string fragmentPath, Dictionary defines) 15 | { 16 | int vertex = LoadShader(ShaderType.VertexShader, vertexPath, defines); 17 | int fragment = LoadShader(ShaderType.FragmentShader, fragmentPath, defines); 18 | _handle = GL.CreateProgram(); 19 | GLUtility.CheckError(); 20 | 21 | GL.AttachShader(_handle, vertex); 22 | GLUtility.CheckError(); 23 | 24 | GL.AttachShader(_handle, fragment); 25 | GLUtility.CheckError(); 26 | 27 | GL.LinkProgram(_handle); 28 | GL.GetProgram(_handle, GetProgramParameterName.LinkStatus, out var status); 29 | if (status == 0) 30 | { 31 | throw new Exception($"Program failed to link with error: {GL.GetProgramInfoLog(_handle)}"); 32 | } 33 | 34 | GL.DetachShader(_handle, vertex); 35 | GL.DetachShader(_handle, fragment); 36 | 37 | GL.DeleteShader(vertex); 38 | GL.DeleteShader(fragment); 39 | } 40 | 41 | public void Use() 42 | { 43 | GL.UseProgram(_handle); 44 | GLUtility.CheckError(); 45 | } 46 | 47 | public void SetUniform(string name, int value) 48 | { 49 | int location = GL.GetUniformLocation(_handle, name); 50 | if (location == -1) 51 | { 52 | throw new Exception($"{name} uniform not found on shader."); 53 | } 54 | GL.Uniform1(location, value); 55 | GLUtility.CheckError(); 56 | } 57 | 58 | public void SetUniform(string name, float value) 59 | { 60 | int location = GL.GetUniformLocation(_handle, name); 61 | if (location == -1) 62 | { 63 | throw new Exception($"{name} uniform not found on shader."); 64 | } 65 | GL.Uniform1(location, value); 66 | GLUtility.CheckError(); 67 | } 68 | 69 | public void SetUniform(string name, Vector2 value) 70 | { 71 | int location = GL.GetUniformLocation(_handle, name); 72 | if (location == -1) 73 | { 74 | throw new Exception($"{name} uniform not found on shader."); 75 | } 76 | GL.Uniform2(location, value.X, value.Y); 77 | GLUtility.CheckError(); 78 | } 79 | 80 | public void SetUniform(string name, Vector4 value) 81 | { 82 | int location = GL.GetUniformLocation(_handle, name); 83 | if (location == -1) 84 | { 85 | throw new Exception($"{name} uniform not found on shader."); 86 | } 87 | GL.Uniform4(location, value.X, value.Y, value.Z, value.W); 88 | GLUtility.CheckError(); 89 | } 90 | 91 | public unsafe void SetUniform(string name, Matrix4x4 value) 92 | { 93 | int location = GL.GetUniformLocation(_handle, name); 94 | if (location == -1) 95 | { 96 | throw new Exception($"{name} uniform not found on shader."); 97 | } 98 | 99 | GL.UniformMatrix4(location, 1, false, (float*)&value); 100 | GLUtility.CheckError(); 101 | } 102 | 103 | public void Dispose() 104 | { 105 | GL.DeleteProgram(_handle); 106 | } 107 | 108 | private int LoadShader(ShaderType type, string path, Dictionary defines) 109 | { 110 | var sb = new StringBuilder(); 111 | 112 | if (defines != null) 113 | { 114 | foreach(var pair in defines) 115 | { 116 | sb.Append("#define " + pair.Key + " " + pair.Value + "\n"); 117 | } 118 | } 119 | 120 | string src = File.ReadAllText(path); 121 | sb.Append(src); 122 | 123 | int handle = GL.CreateShader(type); 124 | GLUtility.CheckError(); 125 | 126 | GL.ShaderSource(handle, sb.ToString()); 127 | GLUtility.CheckError(); 128 | 129 | GL.CompileShader(handle); 130 | string infoLog = GL.GetShaderInfoLog(handle); 131 | if (!string.IsNullOrWhiteSpace(infoLog)) 132 | { 133 | throw new Exception($"Error compiling shader of type {type}, failed with error {infoLog}"); 134 | } 135 | 136 | return handle; 137 | } 138 | 139 | public int GetAttribLocation(string attribName) 140 | { 141 | var result = GL.GetAttribLocation(_handle, attribName); 142 | GLUtility.CheckError(); 143 | return result; 144 | } 145 | } 146 | } -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.OpenTK/Texture.cs: -------------------------------------------------------------------------------- 1 | using OpenTK.Graphics.OpenGL4; 2 | using System; 3 | using System.Drawing; 4 | 5 | namespace NvgSharp.Samples 6 | { 7 | public unsafe class Texture : IDisposable 8 | { 9 | private readonly int _handle; 10 | 11 | public readonly int Width; 12 | public readonly int Height; 13 | 14 | public Texture(int width, int height) 15 | { 16 | Width = width; 17 | Height = height; 18 | 19 | _handle = GL.GenTexture(); 20 | GLUtility.CheckError(); 21 | Bind(); 22 | 23 | //Reserve enough memory from the gpu for the whole image 24 | GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, width, height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero); 25 | GLUtility.CheckError(); 26 | 27 | SetParameters(); 28 | } 29 | 30 | private void SetParameters() 31 | { 32 | //Setting some texture perameters so the texture behaves as expected. 33 | GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge); 34 | GLUtility.CheckError(); 35 | 36 | GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge); 37 | GLUtility.CheckError(); 38 | 39 | GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); 40 | GLUtility.CheckError(); 41 | 42 | GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMinFilter.Linear); 43 | GLUtility.CheckError(); 44 | 45 | //Generating mipmaps. 46 | GL.GenerateMipmap(GenerateMipmapTarget.Texture2D); 47 | GLUtility.CheckError(); 48 | } 49 | 50 | public void Bind(TextureUnit textureSlot = TextureUnit.Texture0) 51 | { 52 | //When we bind a texture we can choose which textureslot we can bind it to. 53 | GL.ActiveTexture(textureSlot); 54 | GLUtility.CheckError(); 55 | 56 | GL.BindTexture(TextureTarget.Texture2D, _handle); 57 | GLUtility.CheckError(); 58 | } 59 | 60 | public void Dispose() 61 | { 62 | //In order to dispose we need to delete the opengl handle for the texure. 63 | GL.DeleteTexture(_handle); 64 | GLUtility.CheckError(); 65 | } 66 | 67 | public void SetData(Rectangle bounds, byte[] data) 68 | { 69 | Bind(); 70 | fixed (byte* ptr = data) 71 | { 72 | GL.TexSubImage2D( 73 | target: TextureTarget.Texture2D, 74 | level: 0, 75 | xoffset: bounds.Left, 76 | yoffset: bounds.Top, 77 | width: bounds.Width, 78 | height: bounds.Height, 79 | format: PixelFormat.Rgba, 80 | type: PixelType.UnsignedByte, 81 | pixels: new IntPtr(ptr) 82 | ); 83 | GLUtility.CheckError(); 84 | } 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.OpenTK/VertexArrayObject.cs: -------------------------------------------------------------------------------- 1 | using OpenTK.Graphics.OpenGL4; 2 | using System; 3 | 4 | namespace NvgSharp.Samples 5 | { 6 | public class VertexArrayObject: IDisposable 7 | { 8 | private readonly uint _handle; 9 | private readonly int _stride; 10 | 11 | public VertexArrayObject(int stride) 12 | { 13 | if (stride <= 0) 14 | { 15 | throw new ArgumentOutOfRangeException(nameof(stride)); 16 | } 17 | 18 | _stride = stride; 19 | 20 | GL.GenVertexArrays(1, out _handle); 21 | GLUtility.CheckError(); 22 | } 23 | 24 | public void Dispose() 25 | { 26 | GL.DeleteVertexArray(_handle); 27 | GLUtility.CheckError(); 28 | } 29 | 30 | public void Bind() 31 | { 32 | GL.BindVertexArray(_handle); 33 | GLUtility.CheckError(); 34 | } 35 | 36 | public unsafe void VertexAttribPointer(int location, int size, VertexAttribPointerType type, bool normalized, int offset) 37 | { 38 | GL.EnableVertexAttribArray(location); 39 | GLUtility.CheckError(); 40 | GL.VertexAttribPointer(location, size, type, normalized, _stride, new IntPtr(offset)); 41 | GLUtility.CheckError(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.OpenTK/Window.cs: -------------------------------------------------------------------------------- 1 | using OpenTK.Graphics.OpenGL4; 2 | using OpenTK.Windowing.Common; 3 | using OpenTK.Windowing.Desktop; 4 | using System; 5 | using System.Diagnostics; 6 | 7 | namespace NvgSharp.Samples 8 | { 9 | internal class Window : GameWindow 10 | { 11 | private Renderer _renderer; 12 | private NvgContext nvgContext; 13 | private PerfGraph _perfGraph; 14 | private Demo demo; 15 | private Stopwatch gameTimer; 16 | private long startTicks; 17 | private long previousTicks; 18 | 19 | public Window(GameWindowSettings gameWindowSettings, NativeWindowSettings nativeWindowSettings) 20 | : base(gameWindowSettings, nativeWindowSettings) 21 | { 22 | gameTimer = Stopwatch.StartNew(); 23 | startTicks = gameTimer.Elapsed.Ticks; 24 | } 25 | 26 | protected override void OnLoad() 27 | { 28 | base.OnLoad(); 29 | 30 | var renderer = new Renderer(true, true); 31 | nvgContext = new NvgContext(renderer, renderer.EdgeAntiAlias); 32 | 33 | demo = new Demo(nvgContext); 34 | _perfGraph = new PerfGraph(PerfGraph.Style.GRAPH_RENDER_FPS, "Frame Time", demo.fontSystemNormal); 35 | } 36 | 37 | protected override void OnRenderFrame(FrameEventArgs args) 38 | { 39 | base.OnRenderFrame(args); 40 | 41 | GL.ClearColor(0.3f, 0.3f, 0.32f, 1.0f); 42 | GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit); 43 | 44 | 45 | nvgContext.ResetState(); 46 | 47 | long currentTicks = gameTimer.Elapsed.Ticks; 48 | 49 | var elapsedTime = (float)TimeSpan.FromTicks(currentTicks - previousTicks).TotalSeconds; 50 | _perfGraph.Update(elapsedTime); 51 | 52 | previousTicks = currentTicks; 53 | 54 | var totalElapsedTime = (float)TimeSpan.FromTicks(currentTicks - startTicks).TotalSeconds; 55 | 56 | demo.renderDemo(nvgContext, MousePosition.X, MousePosition.Y, Size.X, Size.Y, totalElapsedTime, false); 57 | _perfGraph.Render(nvgContext, 5, 5); 58 | 59 | nvgContext.Flush(); 60 | 61 | SwapBuffers(); 62 | } 63 | 64 | protected override void OnResize(ResizeEventArgs e) 65 | { 66 | base.OnResize(e); 67 | 68 | GL.Viewport(0, 0, Size.X, Size.Y); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.OpenTK/shader.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | #define LOWP lowp 3 | precision mediump float; 4 | #else 5 | #define LOWP 6 | #endif 7 | 8 | // Uniforms 9 | uniform sampler2D tex; 10 | uniform mat4 scissorMat; 11 | uniform mat4 paintMat; 12 | uniform vec4 innerCol; 13 | uniform vec4 outerCol; 14 | uniform vec2 scissorExt; 15 | uniform vec2 scissorScale; 16 | uniform vec2 extent; 17 | uniform float radius; 18 | uniform float feather; 19 | uniform float strokeMult; 20 | uniform float strokeThr; 21 | uniform int type; 22 | 23 | // Varyings 24 | varying vec2 fpos; 25 | varying vec2 ftcoord; 26 | 27 | float sdroundrect(vec2 pt, vec2 ext, float rad) { 28 | vec2 ext2 = ext - vec2(rad,rad); 29 | vec2 d = abs(pt) - ext2; 30 | return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rad; 31 | } 32 | 33 | // Scissoring 34 | float scissorMask(vec2 p) { 35 | vec2 sc = (abs((scissorMat * vec4(p,0,1)).xy) - scissorExt); 36 | sc = vec2(0.5,0.5) - sc * scissorScale; 37 | return clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0); 38 | } 39 | #ifdef EDGE_AA 40 | // Stroke - from [0..1] to clipped pyramid, where the slope is 1px. 41 | float strokeMask() { 42 | return min(1.0, (1.0-abs(ftcoord.x*2.0-1.0))*strokeMult) * min(1.0, ftcoord.y); 43 | } 44 | #endif 45 | 46 | void main(void) { 47 | vec4 result; 48 | float scissor = scissorMask(fpos); 49 | #ifdef EDGE_AA 50 | float strokeAlpha = strokeMask(); 51 | if (strokeAlpha < strokeThr) discard; 52 | #else 53 | float strokeAlpha = 1.0; 54 | #endif 55 | if (type == 0) { 56 | // Gradient 57 | // Calculate gradient color using box gradient 58 | vec2 pt = (paintMat * vec4(fpos,0,1)).xy; 59 | float d = clamp((sdroundrect(pt, extent, radius) + feather*0.5) / feather, 0.0, 1.0); 60 | vec4 color = mix(innerCol,outerCol,d); 61 | 62 | // Combine alpha 63 | color *= strokeAlpha * scissor; 64 | result = color; 65 | } else if (type == 1) { 66 | // Image 67 | // Calculate color fron texture 68 | vec2 pt = (paintMat * vec4(fpos,0,1)).xy / extent; 69 | vec4 color = texture2D(tex, pt); 70 | color = vec4(color.xyz*color.w,color.w); 71 | 72 | // Apply color tint and alpha. 73 | color *= innerCol; 74 | // Combine alpha 75 | color *= strokeAlpha * scissor; 76 | result = color; 77 | } else if (type == 2) { 78 | // Stencil fill 79 | result = vec4(1,1,1,1); 80 | } else if (type == 3) { 81 | // Textured tris 82 | vec4 color = texture2D(tex, ftcoord); 83 | color *= scissor; 84 | result = color * innerCol; 85 | } 86 | 87 | gl_FragColor = result; 88 | } -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.OpenTK/shader.vert: -------------------------------------------------------------------------------- 1 | // Attributes 2 | attribute vec2 vertex; 3 | attribute vec2 tcoord; 4 | 5 | // Uniforms 6 | uniform mat4 transformMat; 7 | 8 | // Varyings 9 | varying vec2 fpos; 10 | varying vec2 ftcoord; 11 | 12 | void main() 13 | { 14 | ftcoord = tcoord; 15 | fpos = vertex; 16 | gl_Position = transformMat * vec4(vertex, 0, 1); 17 | } 18 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Silk.NET/BufferObject.cs: -------------------------------------------------------------------------------- 1 | using Silk.NET.OpenGL; 2 | using System; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace NvgSharp.Samples 6 | { 7 | public class BufferObject : IDisposable where T : unmanaged 8 | { 9 | private readonly uint _handle; 10 | private readonly BufferTargetARB _bufferType; 11 | private readonly int _size; 12 | 13 | public int Size => _size; 14 | 15 | public unsafe BufferObject(int size, BufferTargetARB bufferType, bool isDynamic) 16 | { 17 | _bufferType = bufferType; 18 | _size = size; 19 | 20 | _handle = Env.Gl.GenBuffer(); 21 | GLUtility.CheckError(); 22 | 23 | Bind(); 24 | 25 | var elementSizeInBytes = Marshal.SizeOf(); 26 | Env.Gl.BufferData(bufferType, (nuint)(size * elementSizeInBytes), null, isDynamic ? BufferUsageARB.StreamDraw : BufferUsageARB.StaticDraw); 27 | GLUtility.CheckError(); 28 | } 29 | 30 | public void Bind() 31 | { 32 | Env.Gl.BindBuffer(_bufferType, _handle); 33 | GLUtility.CheckError(); 34 | } 35 | 36 | public void Dispose() 37 | { 38 | Env.Gl.DeleteBuffer(_handle); 39 | GLUtility.CheckError(); 40 | } 41 | 42 | public unsafe void SetData(T[] data, int startIndex, int elementCount) 43 | { 44 | Bind(); 45 | 46 | fixed(T* dataPtr = &data[startIndex]) 47 | { 48 | var elementSizeInBytes = sizeof(T); 49 | 50 | Env.Gl.BufferSubData(_bufferType, 0, (nuint)(elementCount * elementSizeInBytes), dataPtr); 51 | GLUtility.CheckError(); 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Silk.NET/Env.cs: -------------------------------------------------------------------------------- 1 | using Silk.NET.OpenGL; 2 | 3 | namespace NvgSharp.Samples 4 | { 5 | internal static class Env 6 | { 7 | public static GL Gl; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Silk.NET/GLUtility.cs: -------------------------------------------------------------------------------- 1 | using Silk.NET.OpenGL; 2 | using System; 3 | using System.Drawing; 4 | using System.Numerics; 5 | 6 | 7 | namespace NvgSharp.Samples 8 | { 9 | internal static class GLUtility 10 | { 11 | public static void CheckError() 12 | { 13 | var error = (ErrorCode)Env.Gl.GetError(); 14 | if (error != ErrorCode.NoError) 15 | throw new Exception("GL.GetError() returned " + error.ToString()); 16 | } 17 | 18 | public static Matrix4x4 ToMatrix4x4(this Transform t) 19 | { 20 | var result = Matrix4x4.Identity; 21 | 22 | result.M11 = t.T1; 23 | result.M12 = t.T2; 24 | result.M13 = 0f; 25 | result.M14 = 0f; 26 | result.M21 = t.T3; 27 | result.M22 = t.T4; 28 | result.M23 = 0f; 29 | result.M24 = 0f; 30 | result.M31 = 0f; 31 | result.M32 = 0f; 32 | result.M33 = 1f; 33 | result.M34 = 0f; 34 | result.M41 = t.T5; 35 | result.M42 = t.T6; 36 | result.M43 = 0f; 37 | result.M44 = 1f; 38 | 39 | return result; 40 | } 41 | 42 | public static void MakeZero(this Matrix4x4 m) 43 | { 44 | m.M11 = m.M12 = m.M13 = m.M14 = 0; 45 | m.M21 = m.M22 = m.M23 = m.M24 = 0; 46 | m.M31 = m.M32 = m.M33 = m.M34 = 0; 47 | m.M41 = m.M42 = m.M43 = m.M44 = 0; 48 | } 49 | 50 | 51 | public static void DrawStroke(this FillStrokeInfo fillStrokeInfo, PrimitiveType primitiveType) 52 | { 53 | if (fillStrokeInfo.StrokeCount <= 0) 54 | { 55 | return; 56 | } 57 | 58 | Env.Gl.DrawArrays(primitiveType, fillStrokeInfo.StrokeOffset, (uint)fillStrokeInfo.StrokeCount); 59 | CheckError(); 60 | } 61 | 62 | public static void DrawFill(this FillStrokeInfo fillStrokeInfo, PrimitiveType primitiveType) 63 | { 64 | if (fillStrokeInfo.FillCount <= 0) 65 | { 66 | return; 67 | } 68 | 69 | Env.Gl.DrawArrays(primitiveType, fillStrokeInfo.FillOffset, (uint)fillStrokeInfo.FillCount); 70 | CheckError(); 71 | } 72 | 73 | public static void DrawTriangles(this CallInfo callInfo, PrimitiveType primitiveType) 74 | { 75 | if (callInfo.TriangleCount <= 0) 76 | { 77 | return; 78 | } 79 | 80 | Env.Gl.DrawArrays(primitiveType, callInfo.TriangleOffset, (uint)callInfo.TriangleCount); 81 | CheckError(); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Silk.NET/NvgSharp.Samples.Silk.NET.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | PreserveNewest 19 | 20 | 21 | PreserveNewest 22 | 23 | 24 | PreserveNewest 25 | 26 | 27 | PreserveNewest 28 | 29 | 30 | PreserveNewest 31 | 32 | 33 | PreserveNewest 34 | 35 | 36 | PreserveNewest 37 | 38 | 39 | PreserveNewest 40 | 41 | 42 | PreserveNewest 43 | 44 | 45 | PreserveNewest 46 | 47 | 48 | PreserveNewest 49 | 50 | 51 | PreserveNewest 52 | 53 | 54 | 55 | 56 | 57 | PreserveNewest 58 | 59 | 60 | PreserveNewest 61 | 62 | 63 | PreserveNewest 64 | 65 | 66 | PreserveNewest 67 | 68 | 69 | PreserveNewest 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | PreserveNewest 84 | 85 | 86 | PreserveNewest 87 | 88 | 89 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Silk.NET/Platform/Renderer.cs: -------------------------------------------------------------------------------- 1 | using Silk.NET.OpenGL; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Numerics; 5 | 6 | namespace NvgSharp.Samples 7 | { 8 | internal class Renderer : INvgRenderer 9 | { 10 | private const int MAX_VERTICES = 8192; 11 | 12 | private readonly Shader _shader; 13 | private BufferObject _vertexBuffer; 14 | private readonly VertexArrayObject _vao; 15 | private readonly bool _edgeAntiAlias, _stencilStrokes; 16 | private readonly int[] _viewPortValues = new int[4]; 17 | 18 | public bool EdgeAntiAlias => _edgeAntiAlias; 19 | 20 | public unsafe Renderer(bool edgeAntiAlias = true, bool stencilStrokes = true) 21 | { 22 | _edgeAntiAlias = edgeAntiAlias; 23 | _stencilStrokes = stencilStrokes; 24 | 25 | var defines = new Dictionary(); 26 | if (edgeAntiAlias) 27 | { 28 | defines["EDGE_AA"] = "1"; 29 | } 30 | 31 | _shader = new Shader("shader.vert", "shader.frag", defines); 32 | _vertexBuffer = new BufferObject(MAX_VERTICES, BufferTargetARB.ArrayBuffer, true); 33 | _vao = new VertexArrayObject(sizeof(Vertex)); 34 | } 35 | 36 | ~Renderer() => Dispose(false); 37 | 38 | public void Dispose() => Dispose(true); 39 | 40 | protected virtual void Dispose(bool disposing) 41 | { 42 | if (!disposing) 43 | { 44 | return; 45 | } 46 | 47 | _vao.Dispose(); 48 | _vertexBuffer.Dispose(); 49 | _shader.Dispose(); 50 | } 51 | 52 | public object CreateTexture(int width, int height) => new Texture(width, height); 53 | 54 | public Point GetTextureSize(object texture) 55 | { 56 | var t = (Texture)texture; 57 | return new Point(t.Width, t.Height); 58 | } 59 | 60 | public void SetTextureData(object texture, Rectangle bounds, byte[] data) 61 | { 62 | var t = (Texture)texture; 63 | t.SetData(bounds, data); 64 | } 65 | 66 | private void SetUniform(ref UniformInfo uniform) 67 | { 68 | _shader.SetUniform("scissorMat", uniform.scissorMat); 69 | _shader.SetUniform("paintMat", uniform.paintMat); 70 | _shader.SetUniform("innerCol", uniform.innerCol); 71 | _shader.SetUniform("outerCol", uniform.outerCol); 72 | _shader.SetUniform("scissorExt", uniform.scissorExt); 73 | _shader.SetUniform("scissorScale", uniform.scissorScale); 74 | _shader.SetUniform("extent", uniform.extent); 75 | _shader.SetUniform("radius", uniform.radius); 76 | _shader.SetUniform("feather", uniform.feather); 77 | _shader.SetUniform("type", (int)uniform.type); 78 | 79 | if (uniform.Image != null) 80 | { 81 | var texture = (Texture)uniform.Image; 82 | texture.Bind(); 83 | } 84 | else 85 | { 86 | Env.Gl.BindTexture(TextureTarget.Texture2D, 0); 87 | GLUtility.CheckError(); 88 | } 89 | 90 | if (_edgeAntiAlias) 91 | { 92 | _shader.SetUniform("strokeMult", uniform.strokeMult); 93 | _shader.SetUniform("strokeThr", uniform.strokeThr); 94 | } 95 | } 96 | 97 | private void ProcessFill(CallInfo call) 98 | { 99 | // Draw shapes 100 | Env.Gl.Enable(EnableCap.StencilTest); 101 | GLUtility.CheckError(); 102 | Env.Gl.StencilMask(0xff); 103 | GLUtility.CheckError(); 104 | Env.Gl.StencilFunc(StencilFunction.Always, 0, 0xff); 105 | GLUtility.CheckError(); 106 | Env.Gl.ColorMask(false, false, false, false); 107 | GLUtility.CheckError(); 108 | 109 | SetUniform(ref call.UniformInfo); 110 | 111 | // set bindpoint for solid loc 112 | Env.Gl.StencilOpSeparate(StencilFaceDirection.Front, StencilOp.Keep, StencilOp.Keep, StencilOp.IncrWrap); 113 | GLUtility.CheckError(); 114 | Env.Gl.StencilOpSeparate(StencilFaceDirection.Back, StencilOp.Keep, StencilOp.Keep, StencilOp.DecrWrap); 115 | GLUtility.CheckError(); 116 | 117 | Env.Gl.Disable(EnableCap.CullFace); 118 | GLUtility.CheckError(); 119 | 120 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 121 | { 122 | call.FillStrokeInfos[i].DrawFill(PrimitiveType.TriangleFan); 123 | } 124 | 125 | Env.Gl.Enable(EnableCap.CullFace); 126 | GLUtility.CheckError(); 127 | 128 | // Draw anti-aliased pixels 129 | Env.Gl.ColorMask(true, true, true, true); 130 | GLUtility.CheckError(); 131 | 132 | SetUniform(ref call.UniformInfo2); 133 | 134 | if (_edgeAntiAlias) 135 | { 136 | Env.Gl.StencilFunc(StencilFunction.Equal, 0, 0xff); 137 | GLUtility.CheckError(); 138 | Env.Gl.StencilOp(StencilOp.Keep, StencilOp.Keep, StencilOp.Keep); 139 | GLUtility.CheckError(); 140 | 141 | // Draw fringes 142 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 143 | { 144 | call.FillStrokeInfos[i].DrawStroke(PrimitiveType.TriangleStrip); 145 | } 146 | } 147 | 148 | // Draw fill 149 | Env.Gl.StencilFunc(StencilFunction.Notequal, 0, 0xff); 150 | GLUtility.CheckError(); 151 | Env.Gl.StencilOp(StencilOp.Zero, StencilOp.Zero, StencilOp.Zero); 152 | GLUtility.CheckError(); 153 | 154 | call.DrawTriangles(PrimitiveType.TriangleStrip); 155 | 156 | Env.Gl.Disable(EnableCap.StencilTest); 157 | GLUtility.CheckError(); 158 | } 159 | 160 | private void ProcessConvexFill(CallInfo call) 161 | { 162 | SetUniform(ref call.UniformInfo); 163 | 164 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 165 | { 166 | var fillStrokeInfo = call.FillStrokeInfos[i]; 167 | 168 | fillStrokeInfo.DrawFill(PrimitiveType.TriangleFan); 169 | fillStrokeInfo.DrawStroke(PrimitiveType.TriangleStrip); 170 | } 171 | } 172 | 173 | private void ProcessStroke(CallInfo call) 174 | { 175 | if (_stencilStrokes) 176 | { 177 | // Fill the stroke base without overlap 178 | Env.Gl.Enable(EnableCap.StencilTest); 179 | GLUtility.CheckError(); 180 | Env.Gl.StencilMask(0xff); 181 | GLUtility.CheckError(); 182 | Env.Gl.StencilFunc(StencilFunction.Equal, 0, 0xff); 183 | GLUtility.CheckError(); 184 | Env.Gl.StencilOp(StencilOp.Keep, StencilOp.Keep, StencilOp.Incr); 185 | GLUtility.CheckError(); 186 | 187 | SetUniform(ref call.UniformInfo2); 188 | 189 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 190 | { 191 | call.FillStrokeInfos[i].DrawStroke(PrimitiveType.TriangleStrip); 192 | } 193 | 194 | // Draw anti-aliased pixels. 195 | SetUniform(ref call.UniformInfo); 196 | 197 | Env.Gl.StencilFunc(StencilFunction.Equal, 0, 0xff); 198 | GLUtility.CheckError(); 199 | Env.Gl.StencilOp(StencilOp.Keep, StencilOp.Keep, StencilOp.Keep); 200 | GLUtility.CheckError(); 201 | 202 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 203 | { 204 | call.FillStrokeInfos[i].DrawStroke(PrimitiveType.TriangleStrip); 205 | } 206 | 207 | // Clear stencil buffer. 208 | Env.Gl.ColorMask(false, false, false, false); 209 | GLUtility.CheckError(); 210 | 211 | Env.Gl.StencilFunc(StencilFunction.Always, 0, 0xff); 212 | GLUtility.CheckError(); 213 | Env.Gl.StencilOp(StencilOp.Zero, StencilOp.Zero, StencilOp.Zero); 214 | GLUtility.CheckError(); 215 | 216 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 217 | { 218 | call.FillStrokeInfos[i].DrawStroke(PrimitiveType.TriangleStrip); 219 | } 220 | 221 | Env.Gl.ColorMask(true, true, true, true); 222 | GLUtility.CheckError(); 223 | 224 | Env.Gl.Disable(EnableCap.StencilTest); 225 | GLUtility.CheckError(); 226 | } 227 | else 228 | { 229 | SetUniform(ref call.UniformInfo); 230 | 231 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 232 | { 233 | call.FillStrokeInfos[i].DrawStroke(PrimitiveType.TriangleStrip); 234 | } 235 | } 236 | } 237 | 238 | private void ProcessTriangles(CallInfo call) 239 | { 240 | SetUniform(ref call.UniformInfo); 241 | 242 | call.DrawTriangles(PrimitiveType.Triangles); 243 | } 244 | 245 | public void Draw(float devicePixelRatio, IEnumerable calls, Vertex[] vertexes) 246 | { 247 | // Setup required GL state 248 | Env.Gl.Enable(EnableCap.CullFace); 249 | GLUtility.CheckError(); 250 | Env.Gl.CullFace(CullFaceMode.Back); 251 | GLUtility.CheckError(); 252 | Env.Gl.FrontFace(FrontFaceDirection.Ccw); 253 | GLUtility.CheckError(); 254 | Env.Gl.Enable(EnableCap.Blend); 255 | GLUtility.CheckError(); 256 | Env.Gl.Disable(EnableCap.DepthTest); 257 | GLUtility.CheckError(); 258 | Env.Gl.Disable(EnableCap.ScissorTest); 259 | GLUtility.CheckError(); 260 | Env.Gl.ColorMask(true, true, true, true); 261 | GLUtility.CheckError(); 262 | Env.Gl.StencilMask(0xffffffff); 263 | GLUtility.CheckError(); 264 | Env.Gl.StencilOp(StencilOp.Keep, StencilOp.Keep, StencilOp.Keep); 265 | GLUtility.CheckError(); 266 | Env.Gl.StencilFunc(StencilFunction.Always, 0, 0xffffffff); 267 | GLUtility.CheckError(); 268 | Env.Gl.ActiveTexture(TextureUnit.Texture0); 269 | GLUtility.CheckError(); 270 | Env.Gl.BindTexture(TextureTarget.Texture2D, 0); 271 | GLUtility.CheckError(); 272 | 273 | // Bind and update vertex buffer 274 | if (_vertexBuffer.Size < vertexes.Length) 275 | { 276 | _vertexBuffer = new BufferObject(vertexes.Length, BufferTargetARB.ArrayBuffer, true); 277 | } 278 | 279 | _vertexBuffer.Bind(); 280 | _vertexBuffer.SetData(vertexes, 0, vertexes.Length); 281 | 282 | // Setup vao 283 | _vao.Bind(); 284 | var location = _shader.GetAttribLocation("vertex"); 285 | _vao.VertexAttribPointer(location, 2, VertexAttribPointerType.Float, false, 0); 286 | 287 | location = _shader.GetAttribLocation("tcoord"); 288 | _vao.VertexAttribPointer(location, 2, VertexAttribPointerType.Float, false, 8); 289 | 290 | // Setup shader 291 | _shader.Use(); 292 | _shader.SetUniform("tex", 0); 293 | 294 | unsafe 295 | { 296 | fixed (int* ptr = _viewPortValues) 297 | { 298 | Env.Gl.GetInteger(GLEnum.Viewport, 0, ptr); 299 | } 300 | } 301 | GLUtility.CheckError(); 302 | 303 | var transform = Matrix4x4.CreateOrthographicOffCenter(0, _viewPortValues[2], _viewPortValues[3], 0, 0, -1); 304 | _shader.SetUniform("transformMat", transform); 305 | 306 | Env.Gl.BlendFunc(BlendingFactor.One, BlendingFactor.OneMinusSrcAlpha); 307 | GLUtility.CheckError(); 308 | 309 | // Process calls 310 | foreach (var call in calls) 311 | { 312 | switch (call.Type) 313 | { 314 | case CallType.Fill: 315 | ProcessFill(call); 316 | break; 317 | case CallType.ConvexFill: 318 | ProcessConvexFill(call); 319 | break; 320 | case CallType.Stroke: 321 | ProcessStroke(call); 322 | break; 323 | case CallType.Triangles: 324 | ProcessTriangles(call); 325 | break; 326 | } 327 | } 328 | } 329 | } 330 | } 331 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Silk.NET/Program.cs: -------------------------------------------------------------------------------- 1 | using Silk.NET.Input; 2 | using Silk.NET.OpenGL; 3 | using Silk.NET.Windowing; 4 | using Silk.NET.Maths; 5 | using System; 6 | using System.Diagnostics; 7 | 8 | namespace NvgSharp.Samples 9 | { 10 | class Program 11 | { 12 | private static IWindow window; 13 | private static IInputContext input; 14 | private static NvgContext nvgContext; 15 | private static PerfGraph _perfGraph; 16 | private static Demo demo; 17 | private static Stopwatch gameTimer; 18 | private static long startTicks; 19 | private static long previousTicks; 20 | 21 | private static void Main(string[] args) 22 | { 23 | gameTimer = Stopwatch.StartNew(); 24 | startTicks = gameTimer.Elapsed.Ticks; 25 | 26 | var options = WindowOptions.Default; 27 | options.Size = new Vector2D(1200, 800); 28 | options.PreferredDepthBufferBits = 24; 29 | options.PreferredStencilBufferBits = 8; 30 | options.Title = "FontStashSharp.Silk.NET"; 31 | window = Window.Create(options); 32 | 33 | window.Load += OnLoad; 34 | window.Render += OnRender; 35 | window.Closing += OnClose; 36 | 37 | window.Run(); 38 | } 39 | 40 | private static void OnLoad() 41 | { 42 | input = window.CreateInput(); 43 | for (int i = 0; i < input.Keyboards.Count; i++) 44 | { 45 | input.Keyboards[i].KeyDown += KeyDown; 46 | } 47 | 48 | Env.Gl = GL.GetApi(window); 49 | var renderer = new Renderer(true, true); 50 | nvgContext = new NvgContext(renderer, renderer.EdgeAntiAlias); 51 | 52 | demo = new Demo(nvgContext); 53 | _perfGraph = new PerfGraph(PerfGraph.Style.GRAPH_RENDER_FPS, "Frame Time", demo.fontSystemNormal); 54 | } 55 | 56 | private static unsafe void OnRender(double obj) 57 | { 58 | Env.Gl.ClearColor(0.3f, 0.3f, 0.32f, 1.0f); 59 | Env.Gl.Clear((uint)(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit)); 60 | 61 | nvgContext.ResetState(); 62 | 63 | long currentTicks = gameTimer.Elapsed.Ticks; 64 | 65 | var elapsedTime = (float)TimeSpan.FromTicks(currentTicks - previousTicks).TotalSeconds; 66 | _perfGraph.Update(elapsedTime); 67 | 68 | previousTicks = currentTicks; 69 | 70 | var totalElapsedTime = (float)TimeSpan.FromTicks(currentTicks - startTicks).TotalSeconds; 71 | 72 | var mousePos = input.Mice[0].Position; 73 | demo.renderDemo(nvgContext, mousePos.X, mousePos.Y, window.Size.X, window.Size.Y, totalElapsedTime, false); 74 | _perfGraph.Render(nvgContext, 5, 5); 75 | 76 | nvgContext.Flush(); 77 | } 78 | 79 | private static void OnClose() 80 | { 81 | } 82 | 83 | private static void KeyDown(IKeyboard arg1, Key arg2, int arg3) 84 | { 85 | if (arg2 == Key.Escape) 86 | { 87 | window.Close(); 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Silk.NET/Shader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Numerics; 5 | using System.Text; 6 | using Silk.NET.OpenGL; 7 | 8 | namespace NvgSharp.Samples 9 | { 10 | public class Shader : IDisposable 11 | { 12 | private uint _handle; 13 | 14 | public Shader(string vertexPath, string fragmentPath, Dictionary defines) 15 | { 16 | uint vertex = LoadShader(ShaderType.VertexShader, vertexPath, defines); 17 | uint fragment = LoadShader(ShaderType.FragmentShader, fragmentPath, defines); 18 | _handle = Env.Gl.CreateProgram(); 19 | GLUtility.CheckError(); 20 | 21 | Env.Gl.AttachShader(_handle, vertex); 22 | GLUtility.CheckError(); 23 | 24 | Env.Gl.AttachShader(_handle, fragment); 25 | GLUtility.CheckError(); 26 | 27 | Env.Gl.LinkProgram(_handle); 28 | Env.Gl.GetProgram(_handle, GLEnum.LinkStatus, out var status); 29 | if (status == 0) 30 | { 31 | throw new Exception($"Program failed to link with error: {Env.Gl.GetProgramInfoLog(_handle)}"); 32 | } 33 | 34 | Env.Gl.DetachShader(_handle, vertex); 35 | Env.Gl.DetachShader(_handle, fragment); 36 | 37 | Env.Gl.DeleteShader(vertex); 38 | Env.Gl.DeleteShader(fragment); 39 | } 40 | 41 | public void Use() 42 | { 43 | Env.Gl.UseProgram(_handle); 44 | GLUtility.CheckError(); 45 | } 46 | 47 | public void SetUniform(string name, int value) 48 | { 49 | int location = Env.Gl.GetUniformLocation(_handle, name); 50 | if (location == -1) 51 | { 52 | throw new Exception($"{name} uniform not found on shader."); 53 | } 54 | Env.Gl.Uniform1(location, value); 55 | GLUtility.CheckError(); 56 | } 57 | 58 | public void SetUniform(string name, float value) 59 | { 60 | int location = Env.Gl.GetUniformLocation(_handle, name); 61 | if (location == -1) 62 | { 63 | throw new Exception($"{name} uniform not found on shader."); 64 | } 65 | Env.Gl.Uniform1(location, value); 66 | GLUtility.CheckError(); 67 | } 68 | 69 | public void SetUniform(string name, Vector2 value) 70 | { 71 | int location = Env.Gl.GetUniformLocation(_handle, name); 72 | if (location == -1) 73 | { 74 | throw new Exception($"{name} uniform not found on shader."); 75 | } 76 | Env.Gl.Uniform2(location, ref value); 77 | GLUtility.CheckError(); 78 | } 79 | 80 | public void SetUniform(string name, Vector4 value) 81 | { 82 | int location = Env.Gl.GetUniformLocation(_handle, name); 83 | if (location == -1) 84 | { 85 | throw new Exception($"{name} uniform not found on shader."); 86 | } 87 | Env.Gl.Uniform4(location, ref value); 88 | GLUtility.CheckError(); 89 | } 90 | 91 | public unsafe void SetUniform(string name, Matrix4x4 value) 92 | { 93 | int location = Env.Gl.GetUniformLocation(_handle, name); 94 | if (location == -1) 95 | { 96 | throw new Exception($"{name} uniform not found on shader."); 97 | } 98 | 99 | Env.Gl.UniformMatrix4(location, 1, false, (float*)&value); 100 | GLUtility.CheckError(); 101 | } 102 | 103 | public void Dispose() 104 | { 105 | Env.Gl.DeleteProgram(_handle); 106 | } 107 | 108 | private uint LoadShader(ShaderType type, string path, Dictionary defines) 109 | { 110 | var sb = new StringBuilder(); 111 | 112 | if (defines != null) 113 | { 114 | foreach(var pair in defines) 115 | { 116 | sb.Append("#define " + pair.Key + " " + pair.Value + "\n"); 117 | } 118 | } 119 | 120 | string src = File.ReadAllText(path); 121 | sb.Append(src); 122 | 123 | uint handle = Env.Gl.CreateShader(type); 124 | GLUtility.CheckError(); 125 | 126 | Env.Gl.ShaderSource(handle, sb.ToString()); 127 | GLUtility.CheckError(); 128 | 129 | Env.Gl.CompileShader(handle); 130 | string infoLog = Env.Gl.GetShaderInfoLog(handle); 131 | if (!string.IsNullOrWhiteSpace(infoLog)) 132 | { 133 | throw new Exception($"Error compiling shader of type {type}, failed with error {infoLog}"); 134 | } 135 | 136 | return handle; 137 | } 138 | 139 | public int GetAttribLocation(string attribName) 140 | { 141 | var result = Env.Gl.GetAttribLocation(_handle, attribName); 142 | GLUtility.CheckError(); 143 | return result; 144 | } 145 | } 146 | } -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Silk.NET/Texture.cs: -------------------------------------------------------------------------------- 1 | using Silk.NET.OpenGL; 2 | using StbImageSharp; 3 | using System; 4 | using System.Drawing; 5 | 6 | namespace NvgSharp.Samples 7 | { 8 | public unsafe class Texture : IDisposable 9 | { 10 | private readonly uint _handle; 11 | 12 | public readonly int Width; 13 | public readonly int Height; 14 | 15 | public uint Handle => _handle; 16 | 17 | public Texture(int width, int height) 18 | { 19 | Width = width; 20 | Height = height; 21 | 22 | _handle = Env.Gl.GenTexture(); 23 | GLUtility.CheckError(); 24 | Bind(); 25 | 26 | //Reserve enough memory from the gpu for the whole image 27 | Env.Gl.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba8, (uint)width, (uint)height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, null); 28 | GLUtility.CheckError(); 29 | 30 | SetParameters(); 31 | } 32 | 33 | private void SetParameters() 34 | { 35 | //Setting some texture perameters so the texture behaves as expected. 36 | Env.Gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)GLEnum.ClampToEdge); 37 | GLUtility.CheckError(); 38 | 39 | Env.Gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)GLEnum.ClampToEdge); 40 | GLUtility.CheckError(); 41 | 42 | Env.Gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)GLEnum.Linear); 43 | GLUtility.CheckError(); 44 | 45 | Env.Gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)GLEnum.Linear); 46 | GLUtility.CheckError(); 47 | 48 | //Generating mipmaps. 49 | Env.Gl.GenerateMipmap(TextureTarget.Texture2D); 50 | GLUtility.CheckError(); 51 | } 52 | 53 | public void Bind(TextureUnit textureSlot = TextureUnit.Texture0) 54 | { 55 | //When we bind a texture we can choose which textureslot we can bind it to. 56 | Env.Gl.ActiveTexture(textureSlot); 57 | GLUtility.CheckError(); 58 | 59 | Env.Gl.BindTexture(TextureTarget.Texture2D, _handle); 60 | GLUtility.CheckError(); 61 | } 62 | 63 | public void Dispose() 64 | { 65 | //In order to dispose we need to delete the opengl handle for the texure. 66 | Env.Gl.DeleteTexture(_handle); 67 | GLUtility.CheckError(); 68 | } 69 | 70 | public void SetData(Rectangle bounds, byte[] data) 71 | { 72 | Bind(); 73 | fixed (byte* ptr = data) 74 | { 75 | Env.Gl.TexSubImage2D( 76 | target: TextureTarget.Texture2D, 77 | level: 0, 78 | xoffset: bounds.Left, 79 | yoffset: bounds.Top, 80 | width: (uint)bounds.Width, 81 | height: (uint)bounds.Height, 82 | format: PixelFormat.Rgba, 83 | type: PixelType.UnsignedByte, 84 | pixels: ptr 85 | ); 86 | GLUtility.CheckError(); 87 | } 88 | } 89 | 90 | public ImageResult GetData() 91 | { 92 | var result = new ImageResult 93 | { 94 | Width = Width, 95 | Height = Height, 96 | Data = new byte[Width * Height * 4] 97 | }; 98 | 99 | fixed (byte* ptr = result.Data) 100 | { 101 | Env.Gl.GetTexImage( 102 | target: TextureTarget.Texture2D, 103 | level: 0, 104 | format: PixelFormat.Rgba, 105 | type: PixelType.UnsignedByte, 106 | ptr); 107 | } 108 | 109 | return result; 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Silk.NET/VertexArrayObject.cs: -------------------------------------------------------------------------------- 1 | using Silk.NET.OpenGL; 2 | using System; 3 | 4 | namespace NvgSharp.Samples 5 | { 6 | public class VertexArrayObject: IDisposable 7 | { 8 | private readonly uint _handle; 9 | private readonly int _stride; 10 | 11 | public VertexArrayObject(int stride) 12 | { 13 | if (stride <= 0) 14 | { 15 | throw new ArgumentOutOfRangeException(nameof(stride)); 16 | } 17 | 18 | _stride = stride; 19 | 20 | Env.Gl.GenVertexArrays(1, out _handle); 21 | GLUtility.CheckError(); 22 | } 23 | 24 | public void Dispose() 25 | { 26 | Env.Gl.DeleteVertexArray(_handle); 27 | GLUtility.CheckError(); 28 | } 29 | 30 | public void Bind() 31 | { 32 | Env.Gl.BindVertexArray(_handle); 33 | GLUtility.CheckError(); 34 | } 35 | 36 | public unsafe void VertexAttribPointer(int location, int size, VertexAttribPointerType type, bool normalized, int offset) 37 | { 38 | Env.Gl.EnableVertexAttribArray((uint)location); 39 | GLUtility.CheckError(); 40 | Env.Gl.VertexAttribPointer((uint)location, size, type, normalized, (uint)_stride, (void*)offset); 41 | GLUtility.CheckError(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Silk.NET/shader.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | #define LOWP lowp 3 | precision mediump float; 4 | #else 5 | #define LOWP 6 | #endif 7 | 8 | // Uniforms 9 | uniform sampler2D tex; 10 | uniform mat4 scissorMat; 11 | uniform mat4 paintMat; 12 | uniform vec4 innerCol; 13 | uniform vec4 outerCol; 14 | uniform vec2 scissorExt; 15 | uniform vec2 scissorScale; 16 | uniform vec2 extent; 17 | uniform float radius; 18 | uniform float feather; 19 | uniform float strokeMult; 20 | uniform float strokeThr; 21 | uniform int type; 22 | 23 | // Varyings 24 | varying vec2 fpos; 25 | varying vec2 ftcoord; 26 | 27 | float sdroundrect(vec2 pt, vec2 ext, float rad) { 28 | vec2 ext2 = ext - vec2(rad,rad); 29 | vec2 d = abs(pt) - ext2; 30 | return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rad; 31 | } 32 | 33 | // Scissoring 34 | float scissorMask(vec2 p) { 35 | vec2 sc = (abs((scissorMat * vec4(p,0,1)).xy) - scissorExt); 36 | sc = vec2(0.5,0.5) - sc * scissorScale; 37 | return clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0); 38 | } 39 | #ifdef EDGE_AA 40 | // Stroke - from [0..1] to clipped pyramid, where the slope is 1px. 41 | float strokeMask() { 42 | return min(1.0, (1.0-abs(ftcoord.x*2.0-1.0))*strokeMult) * min(1.0, ftcoord.y); 43 | } 44 | #endif 45 | 46 | void main(void) { 47 | vec4 result; 48 | float scissor = scissorMask(fpos); 49 | #ifdef EDGE_AA 50 | float strokeAlpha = strokeMask(); 51 | if (strokeAlpha < strokeThr) discard; 52 | #else 53 | float strokeAlpha = 1.0; 54 | #endif 55 | if (type == 0) { 56 | // Gradient 57 | // Calculate gradient color using box gradient 58 | vec2 pt = (paintMat * vec4(fpos,0,1)).xy; 59 | float d = clamp((sdroundrect(pt, extent, radius) + feather*0.5) / feather, 0.0, 1.0); 60 | vec4 color = mix(innerCol,outerCol,d); 61 | 62 | // Combine alpha 63 | color *= strokeAlpha * scissor; 64 | result = color; 65 | } else if (type == 1) { 66 | // Image 67 | // Calculate color fron texture 68 | vec2 pt = (paintMat * vec4(fpos,0,1)).xy / extent; 69 | vec4 color = texture2D(tex, pt); 70 | color = vec4(color.xyz*color.w,color.w); 71 | 72 | // Apply color tint and alpha. 73 | color *= innerCol; 74 | // Combine alpha 75 | color *= strokeAlpha * scissor; 76 | result = color; 77 | } else if (type == 2) { 78 | // Stencil fill 79 | result = vec4(1,1,1,1); 80 | } else if (type == 3) { 81 | // Textured tris 82 | vec4 color = texture2D(tex, ftcoord); 83 | color *= scissor; 84 | result = color * innerCol; 85 | } 86 | 87 | gl_FragColor = result; 88 | } -------------------------------------------------------------------------------- /samples/NvgSharp.Samples.Silk.NET/shader.vert: -------------------------------------------------------------------------------- 1 | // Attributes 2 | attribute vec2 vertex; 3 | attribute vec2 tcoord; 4 | 5 | // Uniforms 6 | uniform mat4 transformMat; 7 | 8 | // Varyings 9 | varying vec2 fpos; 10 | varying vec2 ftcoord; 11 | 12 | void main() 13 | { 14 | ftcoord = tcoord; 15 | fpos = vertex; 16 | gl_Position = transformMat * vec4(vertex, 0, 1); 17 | } 18 | -------------------------------------------------------------------------------- /src/NvgSharp.Text/NvgSharp.Text.FNA.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | NvgSharp.Text.FNA 5 | NvgSharp.Text.FNA 6 | NvgSharp.Text for FNA.Core 7 | $(DefineConstants);FNA 8 | bin\FNA.Core\$(Configuration) 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/NvgSharp.Text/NvgSharp.Text.FNA.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net461 4 | NvgSharp.Text.FNA 5 | NvgSharp.Text.FNA 6 | NvgSharp.Text for FNA 7 | $(DefineConstants);FNA 8 | bin\FNA\$(Configuration) 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/NvgSharp.Text/NvgSharp.Text.MonoGame.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0 4 | NvgSharp.Text for MonoGame 5 | $(DefineConstants);MONOGAME 6 | bin\MonoGame\$(Configuration) 7 | 8 | 9 | 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/NvgSharp.Text/NvgSharp.Text.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | Platform-Agnostic Version of NvgSharp.Text 5 | $(DefineConstants);PLATFORM_AGNOSTIC 6 | 7 | 8 | 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/NvgSharp.Text/NvgText.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using FontStashSharp; 3 | using FontStashSharp.Interfaces; 4 | 5 | #if MONOGAME || FNA 6 | using Microsoft.Xna.Framework; 7 | using Microsoft.Xna.Framework.Graphics; 8 | #elif STRIDE 9 | using Stride.Core.Mathematics; 10 | #else 11 | using System.Numerics; 12 | using System.Drawing; 13 | using Texture2D = System.Object; 14 | using Color = FontStashSharp.FSColor; 15 | #endif 16 | 17 | namespace NvgSharp 18 | { 19 | public static class NvgText 20 | { 21 | private class TextRenderer : IFontStashRenderer2 22 | #if PLATFORM_AGNOSTIC 23 | , ITexture2DManager 24 | #endif 25 | { 26 | private readonly NvgContext _context; 27 | internal int _lastVertexOffset; 28 | internal Texture2D _lastTextTexture = null; 29 | 30 | #if MONOGAME || FNA || STRIDE 31 | public GraphicsDevice GraphicsDevice => _context.GraphicsDevice; 32 | #else 33 | 34 | public ITexture2DManager TextureManager => this; 35 | 36 | public object CreateTexture(int width, int height) => _context._renderer.CreateTexture(width, height); 37 | 38 | public Point GetTextureSize(object texture) => _context._renderer.GetTextureSize(texture); 39 | 40 | public void SetTextureData(object texture, Rectangle bounds, byte[] data) => _context._renderer.SetTextureData(texture, bounds, data); 41 | 42 | #endif 43 | 44 | public TextRenderer(NvgContext context) 45 | { 46 | _context = context; 47 | } 48 | 49 | public void DrawQuad(Texture2D texture, ref VertexPositionColorTexture topLeft, ref VertexPositionColorTexture topRight, 50 | ref VertexPositionColorTexture bottomLeft, ref VertexPositionColorTexture bottomRight) 51 | { 52 | if (_lastTextTexture != null && _lastTextTexture != texture) 53 | { 54 | FlushText(); 55 | } 56 | 57 | var state = _context._currentState; 58 | 59 | float px, py; 60 | state.Transform.TransformPoint(out px, out py, topLeft.Position.X, topLeft.Position.Y); 61 | px = (int)px; 62 | py = (int)py; 63 | var newTopLeft = new Vertex(px, py, topLeft.TextureCoordinate.X, topLeft.TextureCoordinate.Y); 64 | 65 | state.Transform.TransformPoint(out px, out py, topRight.Position.X, topRight.Position.Y); 66 | px = (int)px; 67 | py = (int)py; 68 | var newTopRight = new Vertex(px, py, topRight.TextureCoordinate.X, topRight.TextureCoordinate.Y); 69 | 70 | state.Transform.TransformPoint(out px, out py, bottomRight.Position.X, bottomRight.Position.Y); 71 | px = (int)px; 72 | py = (int)py; 73 | var newBottomRight = new Vertex(px, py, bottomRight.TextureCoordinate.X, bottomRight.TextureCoordinate.Y); 74 | 75 | state.Transform.TransformPoint(out px, out py, bottomLeft.Position.X, bottomLeft.Position.Y); 76 | px = (int)px; 77 | py = (int)py; 78 | var newBottomLeft = new Vertex(px, py, bottomLeft.TextureCoordinate.X, bottomLeft.TextureCoordinate.Y); 79 | 80 | var renderCache = _context._renderCache; 81 | renderCache.AddVertex(newTopLeft); 82 | renderCache.AddVertex(newBottomRight); 83 | renderCache.AddVertex(newTopRight); 84 | renderCache.AddVertex(newTopLeft); 85 | renderCache.AddVertex(newBottomLeft); 86 | renderCache.AddVertex(newBottomRight); 87 | 88 | _lastTextTexture = texture; 89 | } 90 | 91 | private void FlushText() 92 | { 93 | var renderCache = _context._renderCache; 94 | if (_lastTextTexture == null || _lastVertexOffset == renderCache.VertexCount) 95 | { 96 | return; 97 | } 98 | 99 | var state = _context._currentState; 100 | var paint = state.Fill; 101 | paint.Image = _lastTextTexture; 102 | 103 | NvgContext.MultiplyAlpha(ref paint.InnerColor, state.Alpha); 104 | NvgContext.MultiplyAlpha(ref paint.OuterColor, state.Alpha); 105 | 106 | renderCache.RenderTriangles(ref paint, ref state.Scissor, _context._fringeWidth, _lastVertexOffset, renderCache.VertexCount - _lastVertexOffset); 107 | 108 | _lastVertexOffset = renderCache.VertexCount; 109 | _lastTextTexture = null; 110 | } 111 | 112 | public void Text(SpriteFontBase font, TextSource text, float x, float y, float layerDepth, float characterSpacing, float lineSpacing) 113 | { 114 | if (text.IsNull) 115 | { 116 | return; 117 | } 118 | 119 | _lastVertexOffset = _context._renderCache.VertexCount; 120 | 121 | if (text.StringText != null) 122 | { 123 | font.DrawText(this, text.StringText, new Vector2(x, y), Color.White, 124 | layerDepth: layerDepth, characterSpacing: characterSpacing, lineSpacing: lineSpacing); 125 | } 126 | else 127 | { 128 | font.DrawText(this, text.StringBuilderText, new Vector2(x, y), Color.White, 129 | layerDepth: layerDepth, characterSpacing: characterSpacing, lineSpacing: lineSpacing); 130 | } 131 | 132 | FlushText(); 133 | } 134 | } 135 | private static void Text(this NvgContext context, SpriteFontBase font, TextSource text, float x, float y, 136 | float layerDepth, float characterSpacing, float lineSpacing) 137 | { 138 | TextRenderer textRenderer; 139 | if (context._textRenderer == null) 140 | { 141 | textRenderer = new TextRenderer(context); 142 | context._textRenderer = textRenderer; 143 | } else { 144 | textRenderer = (TextRenderer)context._textRenderer; 145 | } 146 | 147 | textRenderer.Text(font, text, x, y, layerDepth, characterSpacing, lineSpacing); 148 | } 149 | 150 | public static void Text(this NvgContext context, SpriteFontBase font, string text, float x, float y, 151 | float layerDepth = 0.0f, float characterSpacing = 0.0f, float lineSpacing = 0.0f) => 152 | Text(context, font, new TextSource(text), x, y, layerDepth, characterSpacing, lineSpacing); 153 | 154 | public static void Text(this NvgContext context, SpriteFontBase font, StringBuilder text, float x, float y, 155 | float layerDepth = 0.0f, float characterSpacing = 0.0f, float lineSpacing = 0.0f) => 156 | Text(context, font, new TextSource(text), x, y, layerDepth, characterSpacing, lineSpacing); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/NvgSharp.Text/TextSource.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace NvgSharp 4 | { 5 | internal struct TextSource 6 | { 7 | public string StringText; 8 | public StringBuilder StringBuilderText; 9 | private int Position; 10 | 11 | public TextSource(string text) 12 | { 13 | StringText = text; 14 | StringBuilderText = null; 15 | Position = 0; 16 | } 17 | 18 | public TextSource(StringBuilder text) 19 | { 20 | StringText = null; 21 | StringBuilderText = text; 22 | Position = 0; 23 | } 24 | 25 | public bool IsNull => StringText == null && StringBuilderText == null; 26 | 27 | public int Length 28 | { 29 | get 30 | { 31 | if (StringText != null) 32 | { 33 | return StringText.Length; 34 | } 35 | 36 | if (StringBuilderText != null) 37 | { 38 | return StringBuilderText.Length; 39 | } 40 | 41 | return 0; 42 | } 43 | } 44 | 45 | public bool GetNextCodepoint(out int result) 46 | { 47 | result = 0; 48 | 49 | if (StringText != null) 50 | { 51 | if (Position >= StringText.Length) 52 | { 53 | return false; 54 | } 55 | 56 | result = char.ConvertToUtf32(StringText, Position); 57 | Position += char.IsSurrogatePair(StringText, Position) ? 2 : 1; 58 | return true; 59 | } 60 | 61 | if (StringBuilderText != null) 62 | { 63 | if (Position >= StringBuilderText.Length) 64 | { 65 | return false; 66 | } 67 | 68 | result = StringBuilderConvertToUtf32(StringBuilderText, Position); 69 | Position += StringBuilderIsSurrogatePair(StringBuilderText, Position) ? 2 : 1; 70 | return true; 71 | } 72 | 73 | return false; 74 | } 75 | 76 | public void Reset() 77 | { 78 | Position = 0; 79 | } 80 | 81 | private static bool StringBuilderIsSurrogatePair(StringBuilder sb, int index) 82 | { 83 | if (index + 1 < sb.Length) 84 | return char.IsSurrogatePair(sb[index], sb[index + 1]); 85 | return false; 86 | } 87 | 88 | private static int StringBuilderConvertToUtf32(StringBuilder sb, int index) 89 | { 90 | if (!char.IsHighSurrogate(sb[index])) 91 | return sb[index]; 92 | 93 | return char.ConvertToUtf32(sb[index], sb[index + 1]); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/NvgSharp/ArrayBuffer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NvgSharp 4 | { 5 | internal class ArrayBuffer 6 | { 7 | private T[] _array; 8 | private int _count = 0; 9 | 10 | public T[] Array => _array; 11 | 12 | public int Count => _count; 13 | 14 | public int Capacity => _array.Length; 15 | 16 | public T this[int index] 17 | { 18 | get => _array[index]; 19 | set => _array[index] = value; 20 | } 21 | 22 | public T this[ulong index] 23 | { 24 | get => _array[index]; 25 | set => _array[index] = value; 26 | } 27 | 28 | public ArrayBuffer(int capacity) 29 | { 30 | _array = new T[capacity]; 31 | } 32 | 33 | public void Clear() 34 | { 35 | _count = 0; 36 | } 37 | 38 | public void EnsureSize(int required) 39 | { 40 | if (_array.Length >= required) return; 41 | 42 | // Realloc 43 | var oldData = _array; 44 | 45 | var newSize = _array.Length; 46 | while (newSize < required) 47 | { 48 | newSize *= 2; 49 | } 50 | 51 | _array = new T[newSize]; 52 | 53 | System.Array.Copy(oldData, _array, oldData.Length); 54 | } 55 | 56 | public void Add(T item) 57 | { 58 | EnsureSize(_count + 1); 59 | 60 | _array[_count] = item; 61 | ++_count; 62 | } 63 | 64 | public void Add(ArraySegment data) 65 | { 66 | if (data.Count == 0) 67 | { 68 | return; 69 | } 70 | 71 | EnsureSize(_count + data.Count); 72 | System.Array.Copy(data.Array, data.Offset, _array, _count, data.Count); 73 | _count += data.Count; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/NvgSharp/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | #if MONOGAME 4 | [assembly: InternalsVisibleTo("NvgSharp.Text.MonoGame", AllInternalsVisible = true)] 5 | #elif FNA 6 | [assembly: InternalsVisibleTo("NvgSharp.Text.FNA", AllInternalsVisible = true)] 7 | #else 8 | [assembly: InternalsVisibleTo("NvgSharp.Text", AllInternalsVisible = true)] 9 | #endif 10 | -------------------------------------------------------------------------------- /src/NvgSharp/Bounds.cs: -------------------------------------------------------------------------------- 1 | #if MONOGAME || FNA 2 | using Microsoft.Xna.Framework; 3 | #elif STRIDE 4 | using Stride.Core.Mathematics; 5 | #else 6 | using System.Numerics; 7 | #endif 8 | 9 | namespace NvgSharp 10 | { 11 | internal struct Bounds 12 | { 13 | public static readonly Bounds Empty = new Bounds 14 | { 15 | X = 0, 16 | Y = 0, 17 | X2 = 0, 18 | Y2 = 0, 19 | }; 20 | 21 | public float X, Y, X2, Y2; 22 | 23 | public Bounds(float x, float y, float x2, float y2) 24 | { 25 | X = x; 26 | Y = y; 27 | X2 = x2; 28 | Y2 = y2; 29 | } 30 | 31 | public void ApplyScale(Vector2 scale) 32 | { 33 | X *= scale.X; 34 | Y *= scale.Y; 35 | X2 *= scale.X; 36 | Y2 *= scale.Y; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/NvgSharp/Command.cs: -------------------------------------------------------------------------------- 1 | namespace NvgSharp 2 | { 3 | internal struct Command 4 | { 5 | public CommandType Type; 6 | public float P1, P2, P3, P4, P5, P6; 7 | 8 | public Command(CommandType type) 9 | { 10 | Type = type; 11 | P1 = P2 = P3 = P4 = P5 = P6 = 0; 12 | } 13 | 14 | public Command(Solidity solidity) 15 | { 16 | Type = CommandType.Winding; 17 | P1 = (int)solidity; 18 | P2 = P3 = P4 = P5 = P6 = 0; 19 | } 20 | 21 | public Command(CommandType type, float p1, float p2) 22 | { 23 | Type = type; 24 | P1 = p1; 25 | P2 = p2; 26 | P3 = P4 = P5 = P6 = 0; 27 | } 28 | 29 | public Command(float p1, float p2, float p3, float p4, float p5, float p6) 30 | { 31 | Type = CommandType.BezierTo; 32 | P1 = p1; 33 | P2 = p2; 34 | P3 = p3; 35 | P4 = p4; 36 | P5 = p5; 37 | P6 = p6; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/NvgSharp/Enums.cs: -------------------------------------------------------------------------------- 1 | namespace NvgSharp 2 | { 3 | public enum Winding 4 | { 5 | /// 6 | /// Winding for solid shapes 7 | /// 8 | CounterClockWise = 1, 9 | 10 | /// 11 | /// Winding for holes 12 | /// 13 | ClockWise = 2, 14 | }; 15 | 16 | public enum Solidity 17 | { 18 | /// 19 | /// CCW 20 | /// 21 | Solid = 1, 22 | 23 | /// 24 | /// CW 25 | /// 26 | Hole = 2, 27 | }; 28 | 29 | public enum LineCap 30 | { 31 | Butt, 32 | Round, 33 | Square, 34 | Bevel, 35 | Miter, 36 | }; 37 | 38 | public enum ImageFlags 39 | { 40 | /// 41 | /// Generate mipmaps during creation of the image 42 | /// 43 | GenerateMipMaps = 1 << 0, 44 | 45 | /// 46 | /// Repeat image in X direction 47 | /// 48 | RepeatX = 1 << 1, 49 | 50 | /// 51 | /// Repeat image in Y direction 52 | /// 53 | RepeatY = 1 << 2, 54 | 55 | /// 56 | /// Flips (inverses) image in Y direction when rendered 57 | /// 58 | FlipY = 1 << 3, 59 | 60 | /// 61 | /// Image data has premultiplied alpha 62 | /// 63 | Premultiplied = 1 << 4, 64 | 65 | /// 66 | /// Image interpolation is Nearest instead Linear 67 | /// 68 | Nearest = 1 << 5, 69 | }; 70 | 71 | internal enum CommandType 72 | { 73 | MoveTo = 0, 74 | LineTo = 1, 75 | BezierTo = 2, 76 | Close = 3, 77 | Winding = 4, 78 | }; 79 | 80 | internal enum PointFlags 81 | { 82 | Corner = 0x01, 83 | Left = 0x02, 84 | Bevel = 0x04, 85 | InnerBevel = 0x08, 86 | }; 87 | 88 | internal enum CodepointType 89 | { 90 | Space, 91 | Newline, 92 | Char, 93 | CjkChar, 94 | }; 95 | } -------------------------------------------------------------------------------- /src/NvgSharp/INvgRenderer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | #if MONOGAME || FNA 4 | using Microsoft.Xna.Framework; 5 | using Microsoft.Xna.Framework.Graphics; 6 | #elif STRIDE 7 | using Stride.Graphics; 8 | #else 9 | using System.Drawing; 10 | using System.Numerics; 11 | using Matrix = System.Numerics.Matrix4x4; 12 | using Texture2D = System.Object; 13 | #endif 14 | 15 | namespace NvgSharp 16 | { 17 | public enum CallType 18 | { 19 | Fill, 20 | ConvexFill, 21 | Stroke, 22 | Triangles 23 | } 24 | 25 | public enum RenderType 26 | { 27 | FillGradient, 28 | FillImage, 29 | Simple, 30 | Image 31 | }; 32 | 33 | public struct UniformInfo 34 | { 35 | public Matrix scissorMat; 36 | public Matrix paintMat; 37 | public Vector4 innerCol; 38 | public Vector4 outerCol; 39 | public Vector2 scissorExt; 40 | public Vector2 scissorScale; 41 | public Vector2 extent; 42 | public float radius; 43 | public float feather; 44 | public float strokeMult; 45 | public float strokeThr; 46 | public Texture2D Image; 47 | public RenderType type; 48 | } 49 | 50 | public struct FillStrokeInfo 51 | { 52 | public int FillOffset; 53 | public int FillCount; 54 | public int StrokeOffset; 55 | public int StrokeCount; 56 | } 57 | 58 | public class CallInfo 59 | { 60 | public CallType Type; 61 | public UniformInfo UniformInfo, UniformInfo2; 62 | public readonly List FillStrokeInfos = new List(); 63 | public int TriangleOffset; 64 | public int TriangleCount; 65 | } 66 | 67 | public interface INvgRenderer 68 | { 69 | #if MONOGAME || FNA || STRIDE 70 | GraphicsDevice GraphicsDevice { get; } 71 | #else 72 | /// 73 | /// Creates a texture of the specified size 74 | /// 75 | /// 76 | /// 77 | /// 78 | object CreateTexture(int width, int height); 79 | 80 | /// 81 | /// Returns size of the specified texture 82 | /// 83 | /// 84 | /// 85 | Point GetTextureSize(object texture); 86 | 87 | /// 88 | /// Sets RGBA data at the specified bounds 89 | /// 90 | /// 91 | /// 92 | void SetTextureData(object texture, Rectangle bounds, byte[] data); 93 | #endif 94 | 95 | void Draw(float devicePixelRatio, IEnumerable calls, Vertex[] vertexes); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/NvgSharp/NvgContextState.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace NvgSharp 4 | { 5 | [StructLayout(LayoutKind.Sequential)] 6 | internal class NvgContextState 7 | { 8 | public int ShapeAntiAlias; 9 | public Paint Fill; 10 | public Paint Stroke; 11 | public float StrokeWidth; 12 | public float MiterLimit; 13 | public LineCap LineJoin; 14 | public LineCap LineCap; 15 | public float Alpha; 16 | public Transform Transform = new Transform(); 17 | public Scissor Scissor; 18 | 19 | public NvgContextState Clone() 20 | { 21 | return new NvgContextState 22 | { 23 | ShapeAntiAlias = ShapeAntiAlias, 24 | Fill = Fill, 25 | Stroke = Stroke, 26 | StrokeWidth = StrokeWidth, 27 | MiterLimit = MiterLimit, 28 | LineJoin = LineJoin, 29 | LineCap = LineCap, 30 | Alpha = Alpha, 31 | Transform = Transform, 32 | Scissor = Scissor, 33 | }; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/NvgSharp/NvgPoint.cs: -------------------------------------------------------------------------------- 1 | namespace NvgSharp 2 | { 3 | internal class NvgPoint 4 | { 5 | public float X; 6 | public float Y; 7 | public float DeltaX; 8 | public float DeltaY; 9 | public float Length; 10 | public float dmx; 11 | public float dmy; 12 | public byte flags; 13 | 14 | public void Reset() 15 | { 16 | X = Y = DeltaX = DeltaY = Length = dmx = dmy = 0; 17 | flags = 0; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/NvgSharp/NvgSharp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | Platform-Agnostic Version of NvgSharp 5 | $(DefineConstants);PLATFORM_AGNOSTIC 6 | 7 | 8 | 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/NvgSharp/NvgUtility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | #if MONOGAME || FNA 4 | using Microsoft.Xna.Framework; 5 | #elif STRIDE 6 | using Stride.Core.Mathematics; 7 | #else 8 | using System.Drawing; 9 | using System.Numerics; 10 | using Matrix = System.Numerics.Matrix4x4; 11 | #endif 12 | 13 | namespace NvgSharp 14 | { 15 | internal static class NvgUtility 16 | { 17 | /// 18 | /// Length proportional to radius of a cubic bezier handle for 90deg arcs 19 | /// 20 | public const float NVG_KAPPA90 = 0.5522847493f; 21 | 22 | /// 23 | /// PI 24 | /// 25 | public const float PI = (float)Math.PI; 26 | 27 | public static float SqrtF(float a) => (float)Math.Sqrt(a); 28 | 29 | public static float SinF(float a) => (float)Math.Sin(a); 30 | 31 | public static float TanF(float a) => (float)Math.Tan(a); 32 | 33 | public static float Atan2F(float a, float b) => (float)Math.Atan2(a, b); 34 | 35 | public static float CosF(float a) => (float)Math.Cos(a); 36 | 37 | public static float AcosF(float a) => (float)Math.Acos(a); 38 | 39 | public static float CeilingF(float a) => (float)Math.Ceiling(a); 40 | 41 | public static int ClampI(int a, int mn, int mx) 42 | { 43 | if (a < mn) return a; 44 | if (a > mx) return mx; 45 | 46 | return a; 47 | } 48 | 49 | public static float ClampF(float a, float mn, float mx) 50 | { 51 | if (a < mn) return a; 52 | if (a > mx) return mx; 53 | 54 | return a; 55 | } 56 | 57 | public static float Cross(float dx0, float dy0, float dx1, float dy1) => dx1 * dy0 - dx0 * dy1; 58 | 59 | public static float Normalize(ref float x, ref float y) 60 | { 61 | var d = SqrtF((x * x) + (y * y)); 62 | if (d > 1e-6f) 63 | { 64 | float id = (float)(1.0f / d); 65 | x *= id; 66 | y *= id; 67 | } 68 | 69 | return d; 70 | } 71 | 72 | public static void MakeZero(this Matrix m) 73 | { 74 | m.M11 = m.M12 = m.M13 = m.M14 = 0; 75 | m.M21 = m.M22 = m.M23 = m.M24 = 0; 76 | m.M31 = m.M32 = m.M33 = m.M34 = 0; 77 | m.M41 = m.M42 = m.M43 = m.M44 = 0; 78 | } 79 | 80 | public static Color FromRGBA(byte r, byte g, byte b, byte a) 81 | { 82 | #if MONOGAME || FNA || STRIDE 83 | return new Color(r, g, b, a); 84 | #else 85 | return Color.FromArgb(a, r, g, b); 86 | #endif 87 | } 88 | 89 | public static Vector4 ToVector4(this Color c, bool premultiply) 90 | { 91 | var result = new Vector4(c.R / 255.0f, c.G / 255.0f, c.B / 255.0f, c.A / 255.0f); 92 | 93 | if (premultiply) 94 | { 95 | result.X *= result.W; 96 | result.Y *= result.W; 97 | result.Z *= result.W; 98 | } 99 | 100 | return result; 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /src/NvgSharp/Paint.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | #if MONOGAME || FNA 4 | using Microsoft.Xna.Framework; 5 | using Microsoft.Xna.Framework.Graphics; 6 | #elif STRIDE 7 | using Stride.Core.Mathematics; 8 | #else 9 | using System.Numerics; 10 | using System.Drawing; 11 | using Texture2D = System.Object; 12 | #endif 13 | 14 | namespace NvgSharp 15 | { 16 | [StructLayout(LayoutKind.Sequential)] 17 | public struct Paint 18 | { 19 | public Transform Transform; 20 | public Vector2 Extent; 21 | public float Radius; 22 | public float Feather; 23 | public Color InnerColor; 24 | public Color OuterColor; 25 | public Texture2D Image; 26 | 27 | public Paint(Color color) 28 | { 29 | Transform = new Transform(); 30 | Extent = new Vector2(); 31 | Transform.SetIdentity(); 32 | Radius = 0.0f; 33 | Feather = 1.0f; 34 | InnerColor = color; 35 | OuterColor = color; 36 | Image = null; 37 | } 38 | 39 | public void Zero() 40 | { 41 | Transform.Zero(); 42 | Extent = Vector2.Zero; 43 | Radius = 0; 44 | Feather = 0; 45 | InnerColor = Color.Transparent; 46 | OuterColor = Color.Transparent; 47 | Image = null; 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/NvgSharp/Path.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace NvgSharp 4 | { 5 | internal class Path 6 | { 7 | public bool Closed; 8 | public int BevelCount; 9 | public int FillOffset, FillCount; 10 | public int StrokeOffset, StrokeCount; 11 | public Winding Winding; 12 | public bool Convex; 13 | public readonly List Points = new List(); 14 | 15 | public NvgPoint this[int index] 16 | { 17 | get => Points[index]; 18 | set => Points[index] = value; 19 | } 20 | 21 | public int Count => Points.Count; 22 | 23 | public NvgPoint FirstPoint => Points[0]; 24 | public NvgPoint LastPoint => Points[Points.Count - 1]; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/NvgSharp/RenderCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | #if MONOGAME || FNA 5 | using Microsoft.Xna.Framework; 6 | #elif STRIDE 7 | using Stride.Core.Mathematics; 8 | #else 9 | using System.Numerics; 10 | #endif 11 | 12 | namespace NvgSharp 13 | { 14 | internal class RenderCache 15 | { 16 | private const int MAX_VERTICES = 8192; 17 | 18 | private readonly bool _stencilStrokes; 19 | 20 | public readonly ArrayBuffer VertexArray = new ArrayBuffer(MAX_VERTICES); 21 | public readonly List Calls = new List(); 22 | public float DevicePixelRatio; 23 | 24 | public int VertexCount => VertexArray.Count; 25 | 26 | public bool StencilStrokes => _stencilStrokes; 27 | 28 | public RenderCache(bool stencilStrokes) 29 | { 30 | _stencilStrokes = stencilStrokes; 31 | } 32 | 33 | public void Reset() 34 | { 35 | VertexArray.Clear(); 36 | Calls.Clear(); 37 | } 38 | 39 | public void AddVertex(float x, float y, float u, float v) 40 | { 41 | VertexArray.Add(new Vertex(x, y, u, v)); 42 | } 43 | 44 | public void AddVertex(Vertex v) 45 | { 46 | VertexArray.Add(v); 47 | } 48 | 49 | private static void BuildUniform(ref Paint paint, ref Scissor scissor, float width, float fringe, 50 | float strokeThr, ref UniformInfo uniform) 51 | { 52 | uniform.innerCol = paint.InnerColor.ToVector4(true); 53 | uniform.outerCol = paint.OuterColor.ToVector4(true); 54 | 55 | if (scissor.Extent.X < -0.5f || scissor.Extent.Y < -0.5f) 56 | { 57 | uniform.scissorMat.MakeZero(); 58 | uniform.scissorExt.X = 1.0f; 59 | uniform.scissorExt.Y = 1.0f; 60 | uniform.scissorScale.X = 1.0f; 61 | uniform.scissorScale.Y = 1.0f; 62 | } 63 | else 64 | { 65 | uniform.scissorMat = scissor.Transform.BuildInverse().ToMatrix(); 66 | uniform.scissorExt.X = scissor.Extent.X; 67 | uniform.scissorExt.Y = scissor.Extent.Y; 68 | uniform.scissorScale.X = (float)Math.Sqrt(scissor.Transform.T1 * scissor.Transform.T1 + scissor.Transform.T3 * scissor.Transform.T3) / fringe; 69 | uniform.scissorScale.Y = (float)Math.Sqrt(scissor.Transform.T2 * scissor.Transform.T2 + scissor.Transform.T4 * scissor.Transform.T4) / fringe; 70 | } 71 | 72 | uniform.extent = paint.Extent; 73 | uniform.strokeMult = (width * 0.5f + fringe * 0.5f) / fringe; 74 | uniform.strokeThr = strokeThr; 75 | 76 | uniform.Image = paint.Image; 77 | 78 | if (paint.Image != null) 79 | { 80 | uniform.type = RenderType.FillImage; 81 | } 82 | else 83 | { 84 | uniform.type = (int)RenderType.FillGradient; 85 | uniform.radius = paint.Radius; 86 | uniform.feather = paint.Feather; 87 | } 88 | 89 | uniform.paintMat = paint.Transform.BuildInverse().ToMatrix(); 90 | } 91 | 92 | public void RenderFill(ref Paint paint, ref Scissor scissor, float fringe, Bounds bounds, IReadOnlyList paths) 93 | { 94 | var call = new CallInfo 95 | { 96 | Type = CallType.Fill 97 | }; 98 | 99 | if (paths.Count == 1 && paths[0].Convex) 100 | { 101 | call.Type = CallType.ConvexFill; 102 | } 103 | 104 | for (var i = 0; i < paths.Count; i++) 105 | { 106 | var path = paths[i]; 107 | 108 | var drawCallInfo = new FillStrokeInfo 109 | { 110 | FillOffset = path.FillOffset, 111 | FillCount = path.FillCount, 112 | StrokeOffset = path.StrokeOffset, 113 | StrokeCount = path.StrokeCount, 114 | }; 115 | 116 | call.FillStrokeInfos.Add(drawCallInfo); 117 | } 118 | 119 | // Setup uniforms for draw calls 120 | if (call.Type == CallType.Fill) 121 | { 122 | // Quad 123 | call.TriangleOffset = VertexArray.Count; 124 | call.TriangleCount = 4; 125 | VertexArray.Add(new Vertex(bounds.X2, bounds.Y2, 0.5f, 1.0f)); 126 | VertexArray.Add(new Vertex(bounds.X2, bounds.Y, 0.5f, 1.0f)); 127 | VertexArray.Add(new Vertex(bounds.X, bounds.Y2, 0.5f, 1.0f)); 128 | VertexArray.Add(new Vertex(bounds.X, bounds.Y, 0.5f, 1.0f)); 129 | 130 | // Simple shader for stencil 131 | call.UniformInfo.strokeThr = -1.0f; 132 | call.UniformInfo.type = RenderType.Simple; 133 | 134 | // Fill shader 135 | BuildUniform(ref paint, ref scissor, fringe, fringe, -1.0f, ref call.UniformInfo2); 136 | } 137 | else 138 | { 139 | // Fill shader 140 | BuildUniform(ref paint, ref scissor, fringe, fringe, -1.0f, ref call.UniformInfo); 141 | } 142 | 143 | Calls.Add(call); 144 | } 145 | 146 | public void RenderStroke(ref Paint paint, ref Scissor scissor, float fringe, float strokeWidth, IReadOnlyList paths) 147 | { 148 | var call = new CallInfo 149 | { 150 | Type = CallType.Stroke, 151 | }; 152 | 153 | for (var i = 0; i < paths.Count; i++) 154 | { 155 | var path = paths[i]; 156 | 157 | var drawCallInfo = new FillStrokeInfo 158 | { 159 | StrokeOffset = path.StrokeOffset, 160 | StrokeCount = path.StrokeCount, 161 | }; 162 | 163 | call.FillStrokeInfos.Add(drawCallInfo); 164 | } 165 | 166 | // Setup uniforms for draw calls 167 | if (_stencilStrokes) 168 | { 169 | // Fill shader 170 | BuildUniform(ref paint, ref scissor, strokeWidth, fringe, -1.0f, ref call.UniformInfo); 171 | BuildUniform(ref paint, ref scissor, strokeWidth, fringe, 1.0f - 0.5f / 255.0f, ref call.UniformInfo2); 172 | } 173 | else 174 | { 175 | // Fill shader 176 | BuildUniform(ref paint, ref scissor, strokeWidth, fringe, -1.0f, ref call.UniformInfo); 177 | } 178 | 179 | Calls.Add(call); 180 | } 181 | 182 | public void RenderTriangles(ref Paint paint, ref Scissor scissor, float fringe, int triangleOffset, int triangleCount) 183 | { 184 | var call = new CallInfo 185 | { 186 | Type = CallType.Triangles, 187 | TriangleOffset = triangleOffset, 188 | TriangleCount = triangleCount 189 | }; 190 | 191 | // Fill shader 192 | BuildUniform(ref paint, ref scissor, 1.0f, fringe, -1.0f, ref call.UniformInfo); 193 | call.UniformInfo.type = RenderType.Image; 194 | 195 | Calls.Add(call); 196 | } 197 | } 198 | } -------------------------------------------------------------------------------- /src/NvgSharp/Scissor.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | #if MONOGAME || FNA 4 | using Microsoft.Xna.Framework; 5 | #elif STRIDE 6 | using Stride.Core.Mathematics; 7 | #else 8 | using System.Numerics; 9 | #endif 10 | 11 | namespace NvgSharp 12 | { 13 | [StructLayout(LayoutKind.Sequential)] 14 | internal struct Scissor 15 | { 16 | public Transform Transform; 17 | public Vector2 Extent; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/NvgSharp/Transform.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | #if MONOGAME || FNA 4 | using Microsoft.Xna.Framework; 5 | #elif STRIDE 6 | using Stride.Core.Mathematics; 7 | #else 8 | using System.Numerics; 9 | #endif 10 | 11 | namespace NvgSharp 12 | { 13 | [StructLayout(LayoutKind.Sequential)] 14 | public struct Transform 15 | { 16 | public float T1, T2, T3, T4, T5, T6; 17 | 18 | public void Zero() 19 | { 20 | T1 = T2 = T3 = T4 = T5 = T6 = 0; 21 | } 22 | 23 | public void Set(Transform src) 24 | { 25 | T1 = src.T1; 26 | T2 = src.T2; 27 | T3 = src.T3; 28 | T4 = src.T4; 29 | T5 = src.T5; 30 | T6 = src.T6; 31 | } 32 | 33 | public void SetIdentity() 34 | { 35 | T1 = 1.0f; 36 | T2 = 0.0f; 37 | T3 = 0.0f; 38 | T4 = 1.0f; 39 | T5 = 0.0f; 40 | T6 = 0.0f; 41 | } 42 | 43 | public void SetTranslate(float tx, float ty) 44 | { 45 | T1 = 1.0f; 46 | T2 = 0.0f; 47 | T3 = 0.0f; 48 | T4 = 1.0f; 49 | T5 = tx; 50 | T6 = ty; 51 | } 52 | 53 | public void SetScale(float sx, float sy) 54 | { 55 | T1 = sx; 56 | T2 = 0.0f; 57 | T3 = 0.0f; 58 | T4 = sy; 59 | T5 = 0.0f; 60 | T6 = 0.0f; 61 | } 62 | 63 | public void SetRotate(float a) 64 | { 65 | var cs = NvgUtility.CosF(a); 66 | var sn = NvgUtility.SinF(a); 67 | T1 = cs; 68 | T2 = sn; 69 | T3 = -sn; 70 | T4 = cs; 71 | T5 = 0.0f; 72 | T6 = 0.0f; 73 | } 74 | 75 | public void SetSkewX(float a) 76 | { 77 | T1 = 1.0f; 78 | T2 = 0.0f; 79 | T3 = NvgUtility.TanF(a); 80 | T4 = 1.0f; 81 | T5 = 0.0f; 82 | T6 = 0.0f; 83 | } 84 | 85 | public void SetSkewY(float a) 86 | { 87 | T1 = 1.0f; 88 | T2 = NvgUtility.TanF(a); 89 | T3 = 0.0f; 90 | T4 = 1.0f; 91 | T5 = 0.0f; 92 | T6 = 0.0f; 93 | } 94 | 95 | public void Multiply(ref Transform s) 96 | { 97 | var t0 = T1 * s.T1 + T2 * s.T3; 98 | var t2 = T3 * s.T1 + T4 * s.T3; 99 | var t4 = T5 * s.T1 + T6 * s.T3 + s.T5; 100 | T2 = T1 * s.T2 + T2 * s.T4; 101 | T4 = T3 * s.T2 + T4 * s.T4; 102 | T6 = T5 * s.T2 + T6 * s.T4 + s.T6; 103 | T1 = t0; 104 | T3 = t2; 105 | T5 = t4; 106 | } 107 | 108 | public void Premultiply(ref Transform s) 109 | { 110 | var s2 = s; 111 | s2.Multiply(ref this); 112 | Set(s2); 113 | } 114 | 115 | public Transform BuildInverse() 116 | { 117 | var det = T1 * T4 - T3 * T2; 118 | var inv = new Transform(); 119 | if (det > -1e-6 && det < 1e-6) 120 | { 121 | inv.SetIdentity(); 122 | return inv; 123 | } 124 | 125 | var inverseDeterminant = 1.0f / det; 126 | inv.T1 = T4 * inverseDeterminant; 127 | inv.T3 = -T3 * inverseDeterminant; 128 | inv.T5 = (T3 * T6 - T4 * T5) * inverseDeterminant; 129 | inv.T2 = -T2 * inverseDeterminant; 130 | inv.T4 = T1 * inverseDeterminant; 131 | inv.T6 = (T2 * T5 - T1 * T6) * inverseDeterminant; 132 | 133 | return inv; 134 | } 135 | 136 | public void TransformPoint(out float dx, out float dy, float sx, float sy) 137 | { 138 | dx = sx * T1 + sy * T3 + T5; 139 | dy = sx * T2 + sy * T4 + T6; 140 | } 141 | 142 | public void TransformVector(out Vector2 v, Vector2 s) 143 | { 144 | TransformPoint(out v.X, out v.Y, s.X, s.Y); 145 | } 146 | 147 | #if MONOGAME || FNA || STRIDE 148 | public Matrix ToMatrix() 149 | { 150 | var m3 = Matrix.Identity; 151 | 152 | m3.M11 = T1; 153 | m3.M21 = T2; 154 | m3.M31 = 0.0f; 155 | m3.M41 = 0.0f; 156 | m3.M12 = T3; 157 | m3.M22 = T4; 158 | m3.M32 = 0.0f; 159 | m3.M42 = 0.0f; 160 | m3.M13 = T5; 161 | m3.M23 = T6; 162 | m3.M33 = 1.0f; 163 | m3.M43 = 0.0f; 164 | 165 | return m3; 166 | } 167 | #else 168 | public Matrix4x4 ToMatrix() 169 | { 170 | var result = Matrix4x4.Identity; 171 | 172 | result.M11 = T1; 173 | result.M12 = T2; 174 | result.M13 = 0f; 175 | result.M14 = 0f; 176 | result.M21 = T3; 177 | result.M22 = T4; 178 | result.M23 = 0f; 179 | result.M24 = 0f; 180 | result.M31 = 0f; 181 | result.M32 = 0f; 182 | result.M33 = 1f; 183 | result.M34 = 0f; 184 | result.M41 = T5; 185 | result.M42 = T6; 186 | result.M43 = 0f; 187 | result.M44 = 1f; 188 | 189 | return result; 190 | } 191 | #endif 192 | } 193 | } -------------------------------------------------------------------------------- /src/NvgSharp/Vertex.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | #if MONOGAME || FNA 4 | using Microsoft.Xna.Framework; 5 | using Microsoft.Xna.Framework.Graphics; 6 | #elif STRIDE 7 | using Stride.Core.Mathematics; 8 | #else 9 | using System.Numerics; 10 | #endif 11 | 12 | namespace NvgSharp 13 | { 14 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 15 | public struct Vertex 16 | #if MONOGAME || FNA || STRIDE 17 | : IVertexType 18 | #endif 19 | { 20 | public Vector2 Position; 21 | public Vector2 TextureCoordinate; 22 | 23 | public Vertex(float x, float y, float u, float v) 24 | { 25 | Position.X = x; 26 | Position.Y = y; 27 | TextureCoordinate.X = u; 28 | TextureCoordinate.Y = v; 29 | } 30 | 31 | #if MONOGAME || FNA || STRIDE 32 | 33 | public static readonly VertexDeclaration VertexDeclaration; 34 | 35 | VertexDeclaration IVertexType.VertexDeclaration 36 | { 37 | get 38 | { 39 | return VertexDeclaration; 40 | } 41 | } 42 | 43 | static Vertex() 44 | { 45 | VertexElement[] elements = new VertexElement[] { 46 | new VertexElement(0, VertexElementFormat.Vector2, VertexElementUsage.Position, 0), 47 | new VertexElement(8, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0) 48 | }; 49 | VertexDeclaration declaration = new VertexDeclaration(elements); 50 | VertexDeclaration = declaration; 51 | } 52 | #endif 53 | } 54 | } -------------------------------------------------------------------------------- /src/XNA/NvgSharp.FNA.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | NvgSharp.FNA 5 | NvgSharp.FNA 6 | NvgSharp for FNA.Core 7 | $(DefineConstants);FNA 8 | bin\FNA.Core\$(Configuration) 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/XNA/NvgSharp.FNA.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net461 4 | NvgSharp.FNA 5 | NvgSharp.FNA 6 | NvgSharp for FNA 7 | $(DefineConstants);FNA 8 | bin\FNA\$(Configuration) 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/XNA/NvgSharp.MonoGame.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0 4 | NvgSharp for MonoGame 5 | $(DefineConstants);MONOGAME 6 | bin\MonoGame\$(Configuration) 7 | 8 | 9 | 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/XNA/Resources.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using System.Reflection; 4 | using Microsoft.Xna.Framework.Graphics; 5 | 6 | namespace NvgSharp 7 | { 8 | internal static class Resources 9 | { 10 | private static byte[] _effectSource = null, _effectWithAASource = null; 11 | 12 | #if MONOGAME 13 | private static bool? _isOpenGL; 14 | #endif 15 | 16 | public static byte[] GetNvgEffectSource(bool edgeAntiAlias) 17 | { 18 | if (_effectSource != null && !edgeAntiAlias) 19 | { 20 | return _effectSource; 21 | } 22 | 23 | if (_effectWithAASource != null && edgeAntiAlias) 24 | { 25 | return _effectWithAASource; 26 | } 27 | 28 | var assembly = typeof(Resources).Assembly; 29 | 30 | var name = "Effect"; 31 | if (edgeAntiAlias) 32 | { 33 | name += "_AA"; 34 | } 35 | 36 | #if MONOGAME 37 | var path = IsOpenGL?"NvgSharp.Resources." + name + ".ogl.mgfxo":"NvgSharp.Resources." + name + ".dx11.mgfxo"; 38 | #elif FNA 39 | var path = "NvgSharp.Resources." + name + ".fxb"; 40 | #endif 41 | 42 | byte[] result; 43 | 44 | var ms = new MemoryStream(); 45 | using (var stream = assembly.GetManifestResourceStream(path)) 46 | { 47 | stream.CopyTo(ms); 48 | result = ms.ToArray(); 49 | } 50 | 51 | if (edgeAntiAlias) 52 | { 53 | _effectWithAASource = result; 54 | } 55 | else 56 | { 57 | _effectSource = result; 58 | } 59 | 60 | return result; 61 | } 62 | 63 | #if MONOGAME 64 | public static bool IsOpenGL 65 | { 66 | get 67 | { 68 | if (_isOpenGL == null) 69 | { 70 | _isOpenGL = (from f in typeof(GraphicsDevice).GetFields(BindingFlags.NonPublic | 71 | BindingFlags.Instance) 72 | where f.Name == "glFramebuffer" 73 | select f).FirstOrDefault() != null; 74 | } 75 | 76 | return _isOpenGL.Value; 77 | } 78 | } 79 | #endif 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/XNA/Resources/Effect.dx11.mgfxo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/src/XNA/Resources/Effect.dx11.mgfxo -------------------------------------------------------------------------------- /src/XNA/Resources/Effect.fx: -------------------------------------------------------------------------------- 1 | #include "Macros.fxh" 2 | 3 | DECLARE_TEXTURE(g_texture, 0); 4 | 5 | BEGIN_CONSTANTS 6 | 7 | float4 innerCol; 8 | float4 outerCol; 9 | float2 scissorExt; 10 | float2 scissorScale; 11 | float2 extent; 12 | float radius; 13 | float feather; 14 | float strokeMult; 15 | float strokeThr; 16 | 17 | MATRIX_CONSTANTS 18 | 19 | float4x4 dummy; 20 | float4x4 scissorMat; 21 | float4x4 paintMat; 22 | float4x4 transformMat; 23 | 24 | END_CONSTANTS 25 | 26 | 27 | struct VS_OUTPUT 28 | { 29 | float4 position : SV_Position; // vertex position 30 | float2 ftcoord : TEXCOORD0; // float 2 tex coord 31 | float2 fpos : TEXCOORD1; // float 2 position 32 | }; 33 | 34 | struct PS_INPUT 35 | { 36 | float4 position : SV_Position; // vertex position 37 | float2 ftcoord : TEXCOORD0; // float 2 tex coord 38 | float2 fpos : TEXCOORD1; // float 2 position 39 | }; 40 | 41 | VS_OUTPUT VSMain(float2 pt : POSITION, float2 tex : TEXCOORD0) 42 | { 43 | VS_OUTPUT Output; 44 | Output.ftcoord = tex; 45 | Output.fpos = pt; 46 | Output.position = mul(float4(pt.x, pt.y, 0, 1), transformMat); 47 | 48 | return Output; 49 | } 50 | 51 | float sdroundrect(float2 pt, float2 ext, float rad) 52 | { 53 | float2 ext2 = ext - float2(rad,rad); 54 | float2 d = abs(pt) - ext2; 55 | return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rad; 56 | } 57 | 58 | // Scissoring 59 | float scissorMask(float2 p) 60 | { 61 | float2 sc = (abs((mul((float3x3)scissorMat, float3(p.x, p.y, 1.0))).xy) - scissorExt.xy); 62 | sc = float2(0.5,0.5) - sc * scissorScale.xy; 63 | return clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0); 64 | } 65 | 66 | #ifdef EDGE_AA 67 | // Stroke - from [0..1] to clipped pyramid, where the slope is 1px. 68 | float strokeMask(float2 ftcoord) 69 | { 70 | return min(1.0, (1.0 - abs(ftcoord.x*2.0 - 1.0))*strokeMult.x) * min(1.0f, ftcoord.y); 71 | } 72 | #endif 73 | 74 | float4 PSMainFillGradient(PS_INPUT input) : SV_TARGET 75 | { 76 | float4 result; 77 | float scissor = scissorMask(input.fpos); 78 | #ifdef EDGE_AA 79 | float strokeAlpha = strokeMask(input.ftcoord); 80 | if (strokeAlpha < strokeThr) discard; 81 | #else 82 | float strokeAlpha = 1.0; 83 | #endif 84 | // Calculate gradient color using box gradient 85 | float2 pt = (mul((float3x3)paintMat, float3(input.fpos,1.0))).xy; 86 | float d = clamp((sdroundrect(pt, extent.xy, radius.x) + feather.x*0.5) / feather.x, 0.0, 1.0); 87 | float4 color = lerp(innerCol, outerCol, d); 88 | 89 | // Combine alpha 90 | color *= strokeAlpha * scissor; 91 | result = color; 92 | 93 | return result; 94 | } 95 | 96 | float4 PSMainFillImage(PS_INPUT input) : SV_TARGET 97 | { 98 | float4 result; 99 | float scissor = scissorMask(input.fpos); 100 | #ifdef EDGE_AA 101 | float strokeAlpha = strokeMask(input.ftcoord); 102 | if (strokeAlpha < strokeThr) discard; 103 | #else 104 | float strokeAlpha = 1.0; 105 | #endif 106 | // Calculate color fron texture 107 | float2 pt = (mul((float3x3)paintMat, float3(input.fpos,1.0))).xy / extent.xy; 108 | float4 color = SAMPLE_TEXTURE(g_texture, pt); 109 | color = float4(color.xyz*color.w,color.w); 110 | 111 | // Apply color tint and alpha. 112 | color *= innerCol; 113 | // Combine alpha 114 | color *= strokeAlpha * scissor; 115 | result = color; 116 | 117 | return result; 118 | } 119 | 120 | float4 PSMainSimple(PS_INPUT input) : SV_TARGET 121 | { 122 | float4 result; 123 | float scissor = scissorMask(input.fpos); 124 | #ifdef EDGE_AA 125 | float strokeAlpha = strokeMask(input.ftcoord); 126 | if (strokeAlpha < strokeThr) discard; 127 | #else 128 | float strokeAlpha = 1.0; 129 | #endif 130 | // Stencil fill 131 | result = float4(1,1,1,1); 132 | 133 | return result; 134 | } 135 | 136 | float4 PSMainTriangles(PS_INPUT input) : SV_TARGET 137 | { 138 | float4 result; 139 | float scissor = scissorMask(input.fpos); 140 | #ifdef EDGE_AA 141 | float strokeAlpha = strokeMask(input.ftcoord); 142 | if (strokeAlpha < strokeThr) discard; 143 | #else 144 | float strokeAlpha = 1.0; 145 | #endif 146 | // Textured tris 147 | float4 color = SAMPLE_TEXTURE(g_texture, input.ftcoord); 148 | color *= scissor; 149 | result = (color * innerCol); 150 | 151 | return result; 152 | } 153 | 154 | TECHNIQUE(FillGradient, VSMain, PSMainFillGradient); 155 | TECHNIQUE(FillImage, VSMain, PSMainFillImage); 156 | TECHNIQUE(Simple, VSMain, PSMainSimple); 157 | TECHNIQUE(Triangles, VSMain, PSMainTriangles); -------------------------------------------------------------------------------- /src/XNA/Resources/Effect.fxb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/src/XNA/Resources/Effect.fxb -------------------------------------------------------------------------------- /src/XNA/Resources/Effect.ogl.mgfxo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/src/XNA/Resources/Effect.ogl.mgfxo -------------------------------------------------------------------------------- /src/XNA/Resources/Effect_AA.dx11.mgfxo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/src/XNA/Resources/Effect_AA.dx11.mgfxo -------------------------------------------------------------------------------- /src/XNA/Resources/Effect_AA.fxb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/src/XNA/Resources/Effect_AA.fxb -------------------------------------------------------------------------------- /src/XNA/Resources/Effect_AA.ogl.mgfxo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rds1983/NvgSharp/b6e8b7ed50b8fe6b550406f45a077d7138033fb6/src/XNA/Resources/Effect_AA.ogl.mgfxo -------------------------------------------------------------------------------- /src/XNA/Resources/Macros.fxh: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Macros.fxh 3 | // 4 | // Microsoft XNA Community Game Platform 5 | // Copyright (C) Microsoft Corporation. All rights reserved. 6 | //----------------------------------------------------------------------------- 7 | 8 | #ifdef SM4 9 | 10 | // Macros for targetting shader model 4.0 (DX11) 11 | 12 | #define TECHNIQUE(name, vsname, psname ) \ 13 | technique name { pass { VertexShader = compile vs_4_0_level_9_1 vsname (); PixelShader = compile ps_4_0_level_9_1 psname(); } } 14 | 15 | #define BEGIN_CONSTANTS cbuffer Parameters : register(b0) { 16 | #define MATRIX_CONSTANTS 17 | #define END_CONSTANTS }; 18 | 19 | #define _vs(r) 20 | #define _ps(r) 21 | #define _cb(r) 22 | 23 | #define DECLARE_TEXTURE(Name, index) \ 24 | Texture2D Name : register(t##index); \ 25 | sampler Name##Sampler : register(s##index) 26 | 27 | #define DECLARE_CUBEMAP(Name, index) \ 28 | TextureCube Name : register(t##index); \ 29 | sampler Name##Sampler : register(s##index) 30 | 31 | #define SAMPLE_TEXTURE(Name, texCoord) Name.Sample(Name##Sampler, texCoord) 32 | #define SAMPLE_CUBEMAP(Name, texCoord) Name.Sample(Name##Sampler, texCoord) 33 | 34 | 35 | #else 36 | 37 | 38 | // Macros for targetting shader model 2.0 (DX9) 39 | 40 | #define TECHNIQUE(name, vsname, psname ) \ 41 | technique name { pass { VertexShader = compile vs_2_0 vsname (); PixelShader = compile ps_2_0 psname(); } } 42 | 43 | #define BEGIN_CONSTANTS 44 | #define MATRIX_CONSTANTS 45 | #define END_CONSTANTS 46 | 47 | #define _vs(r) : register(vs, r) 48 | #define _ps(r) : register(ps, r) 49 | #define _cb(r) 50 | 51 | #define DECLARE_TEXTURE(Name, index) \ 52 | texture2D Name; \ 53 | sampler Name##Sampler : register(s##index) = sampler_state { Texture = (Name); }; 54 | 55 | #define DECLARE_CUBEMAP(Name, index) \ 56 | textureCUBE Name; \ 57 | sampler Name##Sampler : register(s##index) = sampler_state { Texture = (Name); }; 58 | 59 | #define SAMPLE_TEXTURE(Name, texCoord) tex2D(Name##Sampler, texCoord) 60 | #define SAMPLE_CUBEMAP(Name, texCoord) texCUBE(Name##Sampler, texCoord) 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/XNA/Resources/build.bat: -------------------------------------------------------------------------------- 1 | mgfxc Effect.fx Effect.dx11.mgfxo /Profile:DirectX_11 2 | mgfxc Effect.fx Effect_AA.ogl.mgfxo /Profile:OpenGL /defines:EDGE_AA=1 3 | mgfxc Effect.fx Effect.dx11.mgfxo /Profile:DirectX_11 4 | mgfxc Effect.fx Effect_AA.dx11.mgfxo /Profile:DirectX_11 /defines:EDGE_AA=1 5 | 6 | "D:\Windows Kits\10\bin\10.0.19041.0\x64\fxc.exe" /T fx_2_0 /Fo Effect.fxb Effect.fx 7 | "D:\Windows Kits\10\bin\10.0.19041.0\x64\fxc.exe" /T fx_2_0 /Fo Effect_AA.fxb Effect.fx /D EDGE_AA=1 -------------------------------------------------------------------------------- /src/XNA/XNARenderer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Microsoft.Xna.Framework; 5 | using Microsoft.Xna.Framework.Graphics; 6 | 7 | namespace NvgSharp 8 | { 9 | internal class XNARenderer : INvgRenderer 10 | { 11 | private readonly BlendState _blendStateNoDraw = new BlendState 12 | { 13 | ColorWriteChannels = ColorWriteChannels.None 14 | }; 15 | 16 | private readonly GraphicsDevice _device; 17 | private readonly Effect _effect; 18 | 19 | private readonly DepthStencilState _stencilStateFill1 = new DepthStencilState 20 | { 21 | StencilEnable = true, 22 | TwoSidedStencilMode = true, 23 | StencilWriteMask = 0xff, 24 | ReferenceStencil = 0, 25 | StencilMask = 0xff, 26 | StencilFunction = CompareFunction.Always, 27 | StencilFail = StencilOperation.Keep, 28 | StencilDepthBufferFail = StencilOperation.Keep, 29 | StencilPass = StencilOperation.Increment, 30 | CounterClockwiseStencilFunction = CompareFunction.Always, 31 | CounterClockwiseStencilFail = StencilOperation.Keep, 32 | CounterClockwiseStencilDepthBufferFail = StencilOperation.Keep, 33 | CounterClockwiseStencilPass = StencilOperation.Decrement 34 | }; 35 | 36 | private readonly DepthStencilState _stencilStateFill2 = new DepthStencilState 37 | { 38 | StencilEnable = true, 39 | TwoSidedStencilMode = false, 40 | StencilWriteMask = 0xff, 41 | ReferenceStencil = 0, 42 | StencilMask = 0xff, 43 | StencilFunction = CompareFunction.Equal, 44 | StencilFail = StencilOperation.Keep, 45 | StencilDepthBufferFail = StencilOperation.Keep, 46 | StencilPass = StencilOperation.Keep, 47 | }; 48 | 49 | private readonly DepthStencilState _stencilStateFill3 = new DepthStencilState 50 | { 51 | StencilEnable = true, 52 | TwoSidedStencilMode = false, 53 | StencilWriteMask = 0xff, 54 | ReferenceStencil = 0, 55 | StencilMask = 0xff, 56 | StencilFunction = CompareFunction.NotEqual, 57 | StencilFail = StencilOperation.Zero, 58 | StencilDepthBufferFail = StencilOperation.Zero, 59 | StencilPass = StencilOperation.Zero 60 | }; 61 | 62 | private readonly EffectTechnique[] _techniques = new EffectTechnique[4]; 63 | private readonly EffectParameter _extentParam; 64 | private readonly EffectParameter _radiusParam; 65 | private readonly EffectParameter _featherParam; 66 | private readonly EffectParameter _innerColParam; 67 | private readonly EffectParameter _outerColParam; 68 | private readonly EffectParameter _textureParam; 69 | private short[] _indexes = BuildTriangleFanIndexBuffer(2048 * 6); 70 | private BlendState _oldBlendState; 71 | private DepthStencilState _oldDepthStencilState; 72 | private RasterizerState _oldRasterizerState; 73 | private SamplerState _oldSamplerState; 74 | private readonly bool _edgeAntiAlias; 75 | private Vertex[] _vertexArray; 76 | 77 | private readonly EffectParameter _transformMatParam; 78 | private readonly EffectParameter _scissorMatParam; 79 | private readonly EffectParameter _scissorExtParam; 80 | private readonly EffectParameter _scissorScaleParam; 81 | private readonly EffectParameter _paintMatParam; 82 | private readonly EffectParameter _strokeMultParam, _strokeThrParam; 83 | 84 | public GraphicsDevice GraphicsDevice => _device; 85 | 86 | public XNARenderer(GraphicsDevice device, bool edgeAntiAlias) 87 | { 88 | if (device == null) 89 | throw new ArgumentNullException("device"); 90 | 91 | _device = device; 92 | _edgeAntiAlias = edgeAntiAlias; 93 | _effect = new Effect(device, Resources.GetNvgEffectSource(edgeAntiAlias)); 94 | 95 | _transformMatParam = _effect.Parameters["transformMat"]; 96 | _scissorMatParam = _effect.Parameters["scissorMat"]; 97 | _scissorExtParam = _effect.Parameters["scissorExt"]; 98 | _scissorScaleParam = _effect.Parameters["scissorScale"]; 99 | _paintMatParam = _effect.Parameters["paintMat"]; 100 | _extentParam = _effect.Parameters["extent"]; 101 | _radiusParam = _effect.Parameters["radius"]; 102 | _featherParam = _effect.Parameters["feather"]; 103 | _innerColParam = _effect.Parameters["innerCol"]; 104 | _outerColParam = _effect.Parameters["outerCol"]; 105 | _textureParam = _effect.Parameters["g_texture"]; 106 | 107 | if (_edgeAntiAlias) 108 | { 109 | _strokeThrParam = _effect.Parameters["strokeThr"]; 110 | _strokeMultParam = _effect.Parameters["strokeMult"]; 111 | } 112 | 113 | foreach (RenderingType param in Enum.GetValues(typeof(RenderingType))) 114 | _techniques[(int)param] = _effect.Techniques[param.ToString()]; 115 | } 116 | 117 | public void Draw(float devicePixelRatio, IEnumerable calls, Vertex[] vertexes) 118 | { 119 | try 120 | { 121 | _oldSamplerState = _device.SamplerStates[0]; 122 | _oldBlendState = _device.BlendState; 123 | _oldDepthStencilState = _device.DepthStencilState; 124 | _oldRasterizerState = _device.RasterizerState; 125 | 126 | _device.BlendState = BlendState.AlphaBlend; 127 | _device.DepthStencilState = DepthStencilState.None; 128 | _device.RasterizerState = RasterizerState.CullNone; 129 | _device.SamplerStates[0] = SamplerState.PointClamp; 130 | 131 | _vertexArray = vertexes; 132 | 133 | var transform = Matrix.CreateOrthographicOffCenter(0, _device.Viewport.Width, _device.Viewport.Height, 0, 0, -1); 134 | _transformMatParam.SetValue(transform); 135 | 136 | foreach (var call in calls) 137 | { 138 | switch (call.Type) 139 | { 140 | case CallType.Fill: 141 | RenderFill(call); 142 | break; 143 | case CallType.ConvexFill: 144 | RenderConvexFill(call); 145 | break; 146 | case CallType.Stroke: 147 | RenderStroke(call); 148 | break; 149 | case CallType.Triangles: 150 | RenderTriangles(call); 151 | break; 152 | } 153 | } 154 | } 155 | finally 156 | { 157 | _device.SamplerStates[0] = _oldSamplerState; 158 | _device.BlendState = _oldBlendState; 159 | _device.DepthStencilState = _oldDepthStencilState; 160 | _device.RasterizerState = _oldRasterizerState; 161 | _vertexArray = null; 162 | } 163 | } 164 | 165 | private void SetUniform(ref UniformInfo uniform) 166 | { 167 | _scissorMatParam.SetValue(uniform.scissorMat); 168 | _paintMatParam.SetValue(uniform.paintMat); 169 | _innerColParam.SetValue(uniform.innerCol); 170 | _outerColParam.SetValue(uniform.outerCol); 171 | _scissorExtParam.SetValue(uniform.scissorExt); 172 | _scissorScaleParam.SetValue(uniform.scissorScale); 173 | _extentParam.SetValue(uniform.extent); 174 | _radiusParam.SetValue(uniform.radius); 175 | _featherParam.SetValue(uniform.feather); 176 | _textureParam.SetValue(uniform.Image); 177 | 178 | if (_edgeAntiAlias) 179 | { 180 | _strokeMultParam.SetValue(uniform.strokeMult); 181 | _strokeThrParam.SetValue(uniform.strokeThr); 182 | } 183 | } 184 | 185 | private void DrawVertexes(RenderingType renderingType, PrimitiveType primitiveType, int vertexOffset, int vertexCount, bool indexed) 186 | { 187 | if (vertexCount == 0) 188 | { 189 | return; 190 | } 191 | 192 | var technique = _techniques[(int)renderingType]; 193 | _effect.CurrentTechnique = technique; 194 | foreach (var pass in _effect.CurrentTechnique.Passes) 195 | { 196 | pass.Apply(); 197 | 198 | if (indexed) 199 | { 200 | var primitiveCount = vertexCount - 2; 201 | _device.DrawUserIndexedPrimitives(primitiveType, _vertexArray, vertexOffset, vertexCount, _indexes, 0, primitiveCount); 202 | } 203 | else 204 | { 205 | var primitiveCount = 206 | primitiveType == PrimitiveType.TriangleList ? vertexCount / 3 : vertexCount - 2; 207 | _device.DrawUserPrimitives(primitiveType, _vertexArray, vertexOffset, primitiveCount); 208 | } 209 | } 210 | } 211 | 212 | private void RenderConvexFill(CallInfo call) 213 | { 214 | // Convex Fill 215 | SetUniform(ref call.UniformInfo); 216 | 217 | var renderingType = call.UniformInfo.Image != null ? RenderingType.FillImage : RenderingType.FillGradient; 218 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 219 | { 220 | var fillStrokeInfo = call.FillStrokeInfos[i]; 221 | 222 | DrawVertexes(renderingType, PrimitiveType.TriangleList, fillStrokeInfo.FillOffset, fillStrokeInfo.FillCount, true); 223 | DrawVertexes(renderingType, PrimitiveType.TriangleStrip, fillStrokeInfo.StrokeOffset, fillStrokeInfo.StrokeCount, false); 224 | } 225 | } 226 | 227 | private void RenderFill(CallInfo call) 228 | { 229 | _device.BlendState = _blendStateNoDraw; 230 | _device.DepthStencilState = _stencilStateFill1; 231 | var renderingType = RenderingType.Simple; 232 | 233 | SetUniform(ref call.UniformInfo); 234 | 235 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 236 | { 237 | var fillStrokeInfo = call.FillStrokeInfos[i]; 238 | 239 | DrawVertexes(renderingType, PrimitiveType.TriangleList, fillStrokeInfo.FillOffset, fillStrokeInfo.FillCount, true); 240 | } 241 | 242 | // Draw anti-aliased pixels 243 | _device.BlendState = BlendState.AlphaBlend; 244 | 245 | SetUniform(ref call.UniformInfo2); 246 | 247 | if (_edgeAntiAlias) 248 | { 249 | _device.DepthStencilState = _stencilStateFill2; 250 | renderingType = call.UniformInfo2.Image != null ? RenderingType.FillImage : RenderingType.FillGradient; 251 | 252 | // Draw fringes 253 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 254 | { 255 | var fillStrokeInfo = call.FillStrokeInfos[i]; 256 | 257 | DrawVertexes(renderingType, PrimitiveType.TriangleStrip, fillStrokeInfo.StrokeOffset, fillStrokeInfo.StrokeCount, false); 258 | } 259 | } 260 | 261 | _device.DepthStencilState = _stencilStateFill3; 262 | 263 | renderingType = RenderingType.FillGradient; 264 | DrawVertexes(renderingType, PrimitiveType.TriangleStrip, call.TriangleOffset, call.TriangleCount, false); 265 | 266 | _device.DepthStencilState = DepthStencilState.None; 267 | } 268 | 269 | private void RenderStroke(CallInfo call) 270 | { 271 | SetUniform(ref call.UniformInfo); 272 | var renderingType = call.UniformInfo.Image != null ? RenderingType.FillImage : RenderingType.FillGradient; 273 | 274 | for (var i = 0; i < call.FillStrokeInfos.Count; i++) 275 | { 276 | var fillStrokeInfo = call.FillStrokeInfos[i]; 277 | 278 | DrawVertexes(renderingType, PrimitiveType.TriangleStrip, fillStrokeInfo.StrokeOffset, fillStrokeInfo.StrokeCount, false); 279 | } 280 | } 281 | 282 | private void RenderTriangles(CallInfo call) 283 | { 284 | SetUniform(ref call.UniformInfo); 285 | 286 | DrawVertexes(RenderingType.Triangles, PrimitiveType.TriangleList, call.TriangleOffset, call.TriangleCount, false); 287 | } 288 | 289 | private static short[] BuildTriangleFanIndexBuffer(int indexesCount) 290 | { 291 | var result = new List(); 292 | for (var j = 2; j < indexesCount; ++j) 293 | { 294 | result.Add(0); 295 | result.Add((short)(j - 1)); 296 | result.Add((short)j); 297 | } 298 | 299 | return result.ToArray(); 300 | } 301 | 302 | private enum RenderingType 303 | { 304 | FillGradient, 305 | FillImage, 306 | Simple, 307 | Triangles 308 | } 309 | } 310 | } --------------------------------------------------------------------------------