├── .config
└── dotnet-tools.json
├── .editorconfig
├── .gitignore
├── .paket
├── paket.bootstrapper.exe
└── paket.targets
├── GLWpfControl.sln
├── GLWpfControl.sln.DotSettings
├── LICENSE.md
├── README.md
├── RELEASE_NOTES.md
├── build.cmd
├── build.fsx
├── build.fsx.lock
├── build.sh
├── paket.dependencies
├── paket.lock
└── src
├── Example
├── App.xaml
├── App.xaml.cs
├── AssemblyInfo.cs
├── Example.csproj
├── ExampleScene.cs
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── TabbedMainWindowTest.xaml
└── TabbedMainWindowTest.xaml.cs
└── GLWpfControl
├── DXGLContext.cs
├── GLWpfControl.cs
├── GLWpfControl.csproj
├── GLWpfControlRenderer.cs
├── GLWpfControlSettings.cs
├── Interop
├── DXInterop.cs
├── Enums.cs
└── PresentationParameters.cs
├── NonReloadingTabControl.cs
└── paket
/.config/dotnet-tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "isRoot": true,
4 | "tools": {
5 | "fake-cli": {
6 | "version": "5.20.4",
7 | "commands": [
8 | "fake"
9 | ]
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.cs]
2 |
3 | # IDE0090: Use 'new(...)'
4 | csharp_style_implicit_object_creation_when_type_is_apparent = false
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/vim,osx,linux,macos,emacs,fsharp,csharp,windows,android,monodevelop,intellij+all,visualstudio,xamarinstudio,visualstudiocode
3 |
4 | ### Android ###
5 | # Built application files
6 | *.apk
7 | *.ap_
8 |
9 | # Files for the ART/Dalvik VM
10 | *.dex
11 |
12 | # Java class files
13 | *.class
14 |
15 | # Generated files
16 | bin/
17 | gen/
18 | out/
19 |
20 | # Gradle files
21 | .gradle/
22 |
23 | # Local configuration file (sdk path, etc)
24 | local.properties
25 |
26 | # Proguard folder generated by Eclipse
27 | proguard/
28 |
29 | # Log Files
30 | *.log
31 |
32 | # Android Studio Navigation editor temp files
33 | .navigation/
34 |
35 | # Android Studio captures folder
36 | captures/
37 |
38 | # Intellij
39 | *.iml
40 | .idea/workspace.xml
41 | .idea/tasks.xml
42 | .idea/gradle.xml
43 | .idea/dictionaries
44 | .idea/libraries
45 |
46 | # External native build folder generated in Android Studio 2.2 and later
47 | .externalNativeBuild
48 |
49 | # Freeline
50 | freeline.py
51 | freeline/
52 | freeline_project_description.json
53 |
54 | ### Android Patch ###
55 | gen-external-apklibs
56 |
57 | ### Csharp ###
58 | ## Ignore Visual Studio temporary files, build results, and
59 | ## files generated by popular Visual Studio add-ons.
60 | ##
61 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
62 |
63 | # User-specific files
64 | *.suo
65 | *.user
66 | *.userosscache
67 | *.sln.docstates
68 |
69 | # User-specific files (MonoDevelop/Xamarin Studio)
70 | *.userprefs
71 |
72 | # Build results
73 | [Dd]ebug/
74 | [Dd]ebugPublic/
75 | [Rr]elease/
76 | [Rr]eleases/
77 | x64/
78 | x86/
79 | bld/
80 | [Bb]in/
81 | [Oo]bj/
82 | [Ll]og/
83 |
84 | # Visual Studio 2015 cache/options directory
85 | .vs/
86 | # Uncomment if you have tasks that create the project's static files in wwwroot
87 | #wwwroot/
88 |
89 | # MSTest test Results
90 | [Tt]est[Rr]esult*/
91 | [Bb]uild[Ll]og.*
92 |
93 | # NUNIT
94 | *.VisualState.xml
95 | TestResult.xml
96 |
97 | # Build Results of an ATL Project
98 | [Dd]ebugPS/
99 | [Rr]eleasePS/
100 | dlldata.c
101 |
102 | # .NET Core
103 | project.lock.json
104 | project.fragment.lock.json
105 | artifacts/
106 | **/Properties/launchSettings.json
107 |
108 | *_i.c
109 | *_p.c
110 | *_i.h
111 | *.ilk
112 | *.meta
113 | *.obj
114 | *.pch
115 | *.pdb
116 | *.pgc
117 | *.pgd
118 | *.rsp
119 | *.sbr
120 | *.tlb
121 | *.tli
122 | *.tlh
123 | *.tmp
124 | *.tmp_proj
125 | *.vspscc
126 | *.vssscc
127 | .builds
128 | *.pidb
129 | *.svclog
130 | *.scc
131 |
132 | # Chutzpah Test files
133 | _Chutzpah*
134 |
135 | # Visual C++ cache files
136 | ipch/
137 | *.aps
138 | *.ncb
139 | *.opendb
140 | *.opensdf
141 | *.sdf
142 | *.cachefile
143 | *.VC.db
144 | *.VC.VC.opendb
145 |
146 | # Visual Studio profiler
147 | *.psess
148 | *.vsp
149 | *.vspx
150 | *.sap
151 |
152 | # TFS 2012 Local Workspace
153 | $tf/
154 |
155 | # Guidance Automation Toolkit
156 | *.gpState
157 |
158 | # ReSharper is a .NET coding add-in
159 | _ReSharper*/
160 | *.[Rr]e[Ss]harper
161 | *.DotSettings.user
162 |
163 | # JustCode is a .NET coding add-in
164 | .JustCode
165 |
166 | # TeamCity is a build add-in
167 | _TeamCity*
168 |
169 | # DotCover is a Code Coverage Tool
170 | *.dotCover
171 |
172 | # Visual Studio code coverage results
173 | *.coverage
174 | *.coveragexml
175 |
176 | # NCrunch
177 | _NCrunch_*
178 | .*crunch*.local.xml
179 | nCrunchTemp_*
180 |
181 | # MightyMoose
182 | *.mm.*
183 | AutoTest.Net/
184 |
185 | # Web workbench (sass)
186 | .sass-cache/
187 |
188 | # Installshield output folder
189 | [Ee]xpress/
190 |
191 | # DocProject is a documentation generator add-in
192 | DocProject/buildhelp/
193 | DocProject/Help/*.HxT
194 | DocProject/Help/*.HxC
195 | DocProject/Help/*.hhc
196 | DocProject/Help/*.hhk
197 | DocProject/Help/*.hhp
198 | DocProject/Help/Html2
199 | DocProject/Help/html
200 |
201 | # Click-Once directory
202 | publish/
203 |
204 | # Publish Web Output
205 | *.[Pp]ublish.xml
206 | *.azurePubxml
207 | # TODO: Uncomment the next line to ignore your web deploy settings.
208 | # By default, sensitive information, such as encrypted password
209 | # should be stored in the .pubxml.user file.
210 | #*.pubxml
211 | *.pubxml.user
212 | *.publishproj
213 |
214 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
215 | # checkin your Azure Web App publish settings, but sensitive information contained
216 | # in these scripts will be unencrypted
217 | PublishScripts/
218 |
219 | # NuGet Packages
220 | *.nupkg
221 | # The packages folder can be ignored because of Package Restore
222 | **/packages/*
223 | # except build/, which is used as an MSBuild target.
224 | !**/packages/build/
225 | # Uncomment if necessary however generally it will be regenerated when needed
226 | #!**/packages/repositories.config
227 | # NuGet v3's project.json files produces more ignorable files
228 | *.nuget.props
229 | *.nuget.targets
230 |
231 | # Microsoft Azure Build Output
232 | csx/
233 | *.build.csdef
234 |
235 | # Microsoft Azure Emulator
236 | ecf/
237 | rcf/
238 |
239 | # Windows Store app package directories and files
240 | AppPackages/
241 | BundleArtifacts/
242 | Package.StoreAssociation.xml
243 | _pkginfo.txt
244 |
245 | # Visual Studio cache files
246 | # files ending in .cache can be ignored
247 | *.[Cc]ache
248 | # but keep track of directories ending in .cache
249 | !*.[Cc]ache/
250 |
251 | # Others
252 | ClientBin/
253 | ~$*
254 | *~
255 | *.dbmdl
256 | *.dbproj.schemaview
257 | *.jfm
258 | *.pfx
259 | *.publishsettings
260 | orleans.codegen.cs
261 |
262 | # Since there are multiple workflows, uncomment next line to ignore bower_components
263 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
264 | #bower_components/
265 |
266 | # RIA/Silverlight projects
267 | Generated_Code/
268 |
269 | # Backup & report files from converting an old project file
270 | # to a newer Visual Studio version. Backup files are not needed,
271 | # because we have git ;-)
272 | _UpgradeReport_Files/
273 | Backup*/
274 | UpgradeLog*.XML
275 | UpgradeLog*.htm
276 |
277 | # SQL Server files
278 | *.mdf
279 | *.ldf
280 | *.ndf
281 |
282 | # Business Intelligence projects
283 | *.rdl.data
284 | *.bim.layout
285 | *.bim_*.settings
286 |
287 | # Microsoft Fakes
288 | FakesAssemblies/
289 |
290 | # GhostDoc plugin setting file
291 | *.GhostDoc.xml
292 |
293 | # Node.js Tools for Visual Studio
294 | .ntvs_analysis.dat
295 | node_modules/
296 |
297 | # Typescript v1 declaration files
298 | typings/
299 |
300 | # Visual Studio 6 build log
301 | *.plg
302 |
303 | # Visual Studio 6 workspace options file
304 | *.opt
305 |
306 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
307 | *.vbw
308 |
309 | # Visual Studio LightSwitch build output
310 | **/*.HTMLClient/GeneratedArtifacts
311 | **/*.DesktopClient/GeneratedArtifacts
312 | **/*.DesktopClient/ModelManifest.xml
313 | **/*.Server/GeneratedArtifacts
314 | **/*.Server/ModelManifest.xml
315 | _Pvt_Extensions
316 |
317 | # Paket dependency manager
318 | .paket/paket.exe
319 | paket-files/
320 | *.Restore.targets
321 |
322 | # Build tool temp file
323 | *.template
324 |
325 | ### OpenTK AssemblyInfo files ###
326 | **/AssemblyInfo.cs
327 | **/AssemblyInfo.fs
328 |
329 | # FAKE - F# Make
330 | .fake/
331 |
332 | # JetBrains Rider
333 | .idea/
334 | *.sln.iml
335 |
336 | # CodeRush
337 | .cr/
338 |
339 | # Python Tools for Visual Studio (PTVS)
340 | __pycache__/
341 | *.pyc
342 |
343 | # Cake - Uncomment if you are using it
344 | # tools/**
345 | # !tools/packages.config
346 |
347 | # Telerik's JustMock configuration file
348 | *.jmconfig
349 |
350 | # BizTalk build output
351 | *.btp.cs
352 | *.btm.cs
353 | *.odx.cs
354 | *.xsd.cs
355 |
356 | ### Emacs ###
357 | # -*- mode: gitignore; -*-
358 | \#*\#
359 | /.emacs.desktop
360 | /.emacs.desktop.lock
361 | *.elc
362 | auto-save-list
363 | tramp
364 | .\#*
365 |
366 | # Org-mode
367 | .org-id-locations
368 | *_archive
369 |
370 | # flymake-mode
371 | *_flymake.*
372 |
373 | # eshell files
374 | /eshell/history
375 | /eshell/lastdir
376 |
377 | # elpa packages
378 | /elpa/
379 |
380 | # reftex files
381 | *.rel
382 |
383 | # AUCTeX auto folder
384 | /auto/
385 |
386 | # cask packages
387 | .cask/
388 | dist/
389 |
390 | # Flycheck
391 | flycheck_*.el
392 |
393 | # server auth directory
394 | /server/
395 |
396 | # projectiles files
397 | .projectile
398 | projectile-bookmarks.eld
399 |
400 | # directory configuration
401 | .dir-locals.el
402 |
403 | # saveplace
404 | places
405 |
406 | # url cache
407 | url/cache/
408 |
409 | # cedet
410 | ede-projects.el
411 |
412 | # smex
413 | smex-items
414 |
415 | # company-statistics
416 | company-statistics-cache.el
417 |
418 | # anaconda-mode
419 | anaconda-mode/
420 |
421 | ### fsharp ###
422 | lib/debug
423 | lib/release
424 | *.exe
425 | !.paket/paket.bootstrapper.exe
426 |
427 | ### Intellij+all ###
428 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
429 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
430 |
431 | # User-specific stuff:
432 | .idea/**/workspace.xml
433 | .idea/**/tasks.xml
434 |
435 | # Sensitive or high-churn files:
436 | .idea/**/dataSources/
437 | .idea/**/dataSources.ids
438 | .idea/**/dataSources.xml
439 | .idea/**/dataSources.local.xml
440 | .idea/**/sqlDataSources.xml
441 | .idea/**/dynamic.xml
442 | .idea/**/uiDesigner.xml
443 |
444 | # Gradle:
445 | .idea/**/gradle.xml
446 | .idea/**/libraries
447 |
448 | # CMake
449 | cmake-build-debug/
450 |
451 | # Mongo Explorer plugin:
452 | .idea/**/mongoSettings.xml
453 |
454 | ## File-based project format:
455 | *.iws
456 |
457 | ## Plugin-specific files:
458 |
459 | # IntelliJ
460 | /out/
461 |
462 | # mpeltonen/sbt-idea plugin
463 | .idea_modules/
464 |
465 | # JIRA plugin
466 | atlassian-ide-plugin.xml
467 |
468 | # Cursive Clojure plugin
469 | .idea/replstate.xml
470 |
471 | # Ruby plugin and RubyMine
472 | /.rakeTasks
473 |
474 | # Crashlytics plugin (for Android Studio and IntelliJ)
475 | com_crashlytics_export_strings.xml
476 | crashlytics.properties
477 | crashlytics-build.properties
478 | fabric.properties
479 |
480 | ### Linux ###
481 |
482 | # temporary files which can be created if a process still has a handle open of a deleted file
483 | .fuse_hidden*
484 |
485 | # KDE directory preferences
486 | .directory
487 |
488 | # Linux trash folder which might appear on any partition or disk
489 | .Trash-*
490 |
491 | # .nfs files are created when an open file is removed but is still being accessed
492 | .nfs*
493 |
494 | ### macOS ###
495 | *.DS_Store
496 | .AppleDouble
497 | .LSOverride
498 |
499 | # Icon must end with two \r
500 | Icon
501 |
502 | # Thumbnails
503 | ._*
504 |
505 | # Files that might appear in the root of a volume
506 | .DocumentRevisions-V100
507 | .fseventsd
508 | .Spotlight-V100
509 | .TemporaryItems
510 | .Trashes
511 | .VolumeIcon.icns
512 | .com.apple.timemachine.donotpresent
513 |
514 | # Directories potentially created on remote AFP share
515 | .AppleDB
516 | .AppleDesktop
517 | Network Trash Folder
518 | Temporary Items
519 | .apdisk
520 |
521 | ### MonoDevelop ###
522 | #User Specific
523 | *.usertasks
524 |
525 | #Mono Project Files
526 | *.resources
527 | test-results/
528 |
529 | ### OSX ###
530 |
531 | # Icon must end with two \r
532 |
533 | # Thumbnails
534 |
535 | # Files that might appear in the root of a volume
536 |
537 | # Directories potentially created on remote AFP share
538 |
539 | ### Vim ###
540 | # swap
541 | [._]*.s[a-v][a-z]
542 | [._]*.sw[a-p]
543 | [._]s[a-v][a-z]
544 | [._]sw[a-p]
545 | # session
546 | Session.vim
547 | # temporary
548 | .netrwhist
549 | # auto-generated tag files
550 | tags
551 |
552 | ### VisualStudioCode ###
553 | .vscode/*
554 | !.vscode/settings.json
555 | !.vscode/tasks.json
556 | !.vscode/launch.json
557 | !.vscode/extensions.json
558 | .history
559 |
560 | ### Windows ###
561 | # Windows thumbnail cache files
562 | Thumbs.db
563 | ehthumbs.db
564 | ehthumbs_vista.db
565 |
566 | # Folder config file
567 | Desktop.ini
568 |
569 | # Recycle Bin used on file shares
570 | $RECYCLE.BIN/
571 |
572 | # Windows Installer files
573 | *.cab
574 | *.msi
575 | *.msm
576 | *.msp
577 |
578 | # Windows shortcuts
579 | *.lnk
580 |
581 | ### XamarinStudio ###
582 | .packages
583 |
584 | ### Mono Code Coverage ###
585 | TestResults.xml
586 |
587 | ### OpenTK Binding files ###
588 | .bindingsGenerated
589 | src/OpenTK/Graphics/ES10/Enums
590 | src/OpenTK/Graphics/ES10/Wrappers
591 | src/OpenTK/Graphics/ES11/Enums
592 | src/OpenTK/Graphics/ES11/Wrappers
593 | src/OpenTK/Graphics/ES20/Enums
594 | src/OpenTK/Graphics/ES20/Wrappers
595 | src/OpenTK/Graphics/ES30/Enums
596 | src/OpenTK/Graphics/ES30/Wrappers
597 | src/OpenTK/Graphics/ES31/Enums
598 | src/OpenTK/Graphics/ES31/Wrappers
599 | src/OpenTK/Graphics/OpenGL/Enums
600 | src/OpenTK/Graphics/OpenGL/Wrappers
601 | src/OpenTK/Graphics/OpenGL4/Enums
602 | src/OpenTK/Graphics/OpenGL4/Wrappers
603 |
604 | ### Tooling files ""
605 | tools/
606 |
607 | ### LaTeX ###
608 | ## Core latex/pdflatex auxiliary files:
609 | *.aux
610 | *.lof
611 | *.lot
612 | *.fls
613 | *.out
614 | *.toc
615 | *.fmt
616 | *.fot
617 | *.cb
618 | *.cb2
619 | .*.lb
620 |
621 | ## Intermediate documents:
622 | *.dvi
623 | *.xdv
624 | *-converted-to.*
625 | # these rules might exclude image files for figures etc.
626 | # *.ps
627 | # *.eps
628 | # *.pdf
629 |
630 | ## Generated if empty string is given at "Please type another file name for output:"
631 | .pdf
632 |
633 | ## Bibliography auxiliary files (bibtex/biblatex/biber):
634 | *.bbl
635 | *.bcf
636 | *.blg
637 | *-blx.aux
638 | *-blx.bib
639 | *.run.xml
640 |
641 | ## Build tool auxiliary files:
642 | *.fdb_latexmk
643 | *.synctex
644 | *.synctex(busy)
645 | *.synctex.gz
646 | *.synctex.gz(busy)
647 | *.pdfsync
648 |
649 | ## Build tool directories for auxiliary files
650 | # latexrun
651 | latex.out/
652 |
653 | ## Auxiliary and intermediate files from other packages:
654 | # algorithms
655 | *.alg
656 | *.loa
657 |
658 | # achemso
659 | acs-*.bib
660 |
661 | # amsthm
662 | *.thm
663 |
664 | # beamer
665 | *.nav
666 | *.pre
667 | *.snm
668 | *.vrb
669 |
670 | # changes
671 | *.soc
672 |
673 | # cprotect
674 | *.cpt
675 |
676 | # elsarticle (documentclass of Elsevier journals)
677 | *.spl
678 |
679 | # endnotes
680 | *.ent
681 |
682 | # fixme
683 | *.lox
684 |
685 | # feynmf/feynmp
686 | *.mf
687 | *.mp
688 | *.t[1-9]
689 | *.t[1-9][0-9]
690 | *.tfm
691 |
692 | # glossaries
693 | *.acn
694 | *.acr
695 | *.glg
696 | *.glo
697 | *.gls
698 | *.glsdefs
699 |
700 | # gnuplottex
701 | *-gnuplottex-*
702 |
703 | # gregoriotex
704 | *.gaux
705 | *.gtex
706 |
707 | # htlatex
708 | *.4ct
709 | *.4tc
710 | *.idv
711 | *.lg
712 | *.trc
713 | *.xref
714 |
715 | # hyperref
716 | *.brf
717 |
718 | # knitr
719 | *-concordance.tex
720 | # TODO Comment the next line if you want to keep your tikz graphics files
721 | *.tikz
722 | *-tikzDictionary
723 |
724 | # listings
725 | *.lol
726 |
727 | # makeidx
728 | *.idx
729 | *.ilg
730 | *.ind
731 | *.ist
732 |
733 | # minitoc
734 | *.maf
735 | *.mlf
736 | *.mlt
737 | *.mtc[0-9]*
738 | *.slf[0-9]*
739 | *.slt[0-9]*
740 | *.stc[0-9]*
741 |
742 | # minted
743 | _minted*
744 | *.pyg
745 |
746 | # morewrites
747 | *.mw
748 |
749 | # nomencl
750 | *.nlg
751 | *.nlo
752 | *.nls
753 |
754 | # pax
755 | *.pax
756 |
757 | # pdfpcnotes
758 | *.pdfpc
759 |
760 | # sagetex
761 | *.sagetex.sage
762 | *.sagetex.py
763 | *.sagetex.scmd
764 |
765 | # scrwfile
766 | *.wrt
767 |
768 | # sympy
769 | *.sout
770 | *.sympy
771 | sympy-plots-for-*.tex/
772 |
773 | # pdfcomment
774 | *.upa
775 | *.upb
776 |
777 | # pythontex
778 | *.pytxcode
779 | pythontex-files-*/
780 |
781 | # thmtools
782 | *.loe
783 |
784 | # TikZ & PGF
785 | *.dpth
786 | *.md5
787 | *.auxlock
788 |
789 | # todonotes
790 | *.tdo
791 |
792 | # easy-todo
793 | *.lod
794 |
795 | # xmpincl
796 | *.xmpi
797 |
798 | # xindy
799 | *.xdy
800 |
801 | # xypic precompiled matrices
802 | *.xyc
803 |
804 | # endfloat
805 | *.ttt
806 | *.fff
807 |
808 | # Latexian
809 | TSWLatexianTemp*
810 |
811 | ## Editors:
812 | # WinEdt
813 | *.bak
814 | *.sav
815 |
816 | # Texpad
817 | .texpadtmp
818 |
819 | # LyX
820 | *.lyx~
821 |
822 | # Kile
823 | *.backup
824 |
825 | # KBibTeX
826 | *~[0-9]*
827 |
828 | # auto folder when using emacs and auctex
829 | auto/*
830 | *.el
831 |
832 | # expex forward references with \gathertags
833 | *-tags.tex
834 |
835 | # standalone packages
836 | *.sta
837 |
838 | ### LaTeX Patch ###
839 | # glossaries
840 | *.glstex
841 |
--------------------------------------------------------------------------------
/.paket/paket.bootstrapper.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentk/GLWpfControl/f354d51715565a30ecd41bf9df370c42f32ed957/.paket/paket.bootstrapper.exe
--------------------------------------------------------------------------------
/.paket/paket.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | true
6 |
7 | true
8 | $(MSBuildThisFileDirectory)
9 | $(MSBuildThisFileDirectory)..\
10 | /Library/Frameworks/Mono.framework/Commands/mono
11 | mono
12 |
13 |
14 |
15 | $(PaketToolsPath)paket.exe
16 | $(PaketToolsPath)paket.bootstrapper.exe
17 | "$(PaketExePath)"
18 | $(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)"
19 | "$(PaketBootStrapperExePath)" $(PaketBootStrapperCommandArgs)
20 | $(MonoPath) --runtime=v4.0.30319 $(PaketBootStrapperExePath) $(PaketBootStrapperCommandArgs)
21 |
22 | $(MSBuildProjectDirectory)\paket.references
23 | $(MSBuildStartupDirectory)\paket.references
24 | $(MSBuildProjectFullPath).paket.references
25 | $(PaketCommand) restore --references-files "$(PaketReferences)"
26 | $(PaketBootStrapperCommand)
27 |
28 | RestorePackages; $(BuildDependsOn);
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/GLWpfControl.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.2.32516.85
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{F02DE1CD-94DB-4F38-8B0A-833B2A357E2E}"
7 | ProjectSection(SolutionItems) = preProject
8 | build.cmd = build.cmd
9 | build.fsx = build.fsx
10 | build.sh = build.sh
11 | paket.dependencies = paket.dependencies
12 | paket.lock = paket.lock
13 | EndProjectSection
14 | EndProject
15 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "project", "project", "{8A911F4A-8A01-4B86-959B-27CA1CDA2C1B}"
16 | ProjectSection(SolutionItems) = preProject
17 | src\GLWpfControl\paket.template = src\GLWpfControl\paket.template
18 | README.md = README.md
19 | RELEASE_NOTES.md = RELEASE_NOTES.md
20 | EndProjectSection
21 | EndProject
22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GLWpfControl", "src\GLWpfControl\GLWpfControl.csproj", "{E201C66F-F247-4E23-AB4D-0EB50005091D}"
23 | EndProject
24 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example", "src\Example\Example.csproj", "{7E12D07B-0DD6-4288-A4F8-92EB75848ECF}"
25 | EndProject
26 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{441E95E4-0A78-4121-A68C-C778C8050489}"
27 | ProjectSection(SolutionItems) = preProject
28 | .editorconfig = .editorconfig
29 | EndProjectSection
30 | EndProject
31 | Global
32 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
33 | Debug|Any CPU = Debug|Any CPU
34 | Debug|x64 = Debug|x64
35 | Release|Any CPU = Release|Any CPU
36 | Release|x64 = Release|x64
37 | EndGlobalSection
38 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
39 | {E201C66F-F247-4E23-AB4D-0EB50005091D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
40 | {E201C66F-F247-4E23-AB4D-0EB50005091D}.Debug|Any CPU.Build.0 = Debug|Any CPU
41 | {E201C66F-F247-4E23-AB4D-0EB50005091D}.Debug|x64.ActiveCfg = Debug|x64
42 | {E201C66F-F247-4E23-AB4D-0EB50005091D}.Debug|x64.Build.0 = Debug|x64
43 | {E201C66F-F247-4E23-AB4D-0EB50005091D}.Release|Any CPU.ActiveCfg = Release|Any CPU
44 | {E201C66F-F247-4E23-AB4D-0EB50005091D}.Release|Any CPU.Build.0 = Release|Any CPU
45 | {E201C66F-F247-4E23-AB4D-0EB50005091D}.Release|x64.ActiveCfg = Release|x64
46 | {E201C66F-F247-4E23-AB4D-0EB50005091D}.Release|x64.Build.0 = Release|x64
47 | {7E12D07B-0DD6-4288-A4F8-92EB75848ECF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
48 | {7E12D07B-0DD6-4288-A4F8-92EB75848ECF}.Debug|Any CPU.Build.0 = Debug|Any CPU
49 | {7E12D07B-0DD6-4288-A4F8-92EB75848ECF}.Debug|x64.ActiveCfg = Debug|x64
50 | {7E12D07B-0DD6-4288-A4F8-92EB75848ECF}.Debug|x64.Build.0 = Debug|x64
51 | {7E12D07B-0DD6-4288-A4F8-92EB75848ECF}.Release|Any CPU.ActiveCfg = Release|Any CPU
52 | {7E12D07B-0DD6-4288-A4F8-92EB75848ECF}.Release|Any CPU.Build.0 = Release|Any CPU
53 | {7E12D07B-0DD6-4288-A4F8-92EB75848ECF}.Release|x64.ActiveCfg = Release|x64
54 | {7E12D07B-0DD6-4288-A4F8-92EB75848ECF}.Release|x64.Build.0 = Release|x64
55 | EndGlobalSection
56 | GlobalSection(SolutionProperties) = preSolution
57 | HideSolutionNode = FALSE
58 | EndGlobalSection
59 | GlobalSection(ExtensibilityGlobals) = postSolution
60 | SolutionGuid = {97CD4768-306D-4862-9FE0-1ED5261AA0D4}
61 | EndGlobalSection
62 | EndGlobal
63 |
--------------------------------------------------------------------------------
/GLWpfControl.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | GL
3 | True
4 | True
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 varon
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## GLWpfControl - A fast OpenGL Control for WPF
2 | 
3 |
4 | A native control for WPF in OpenTK 3.x and 4.x.
5 |
6 | Supported configurations:
7 | - .Net Framework for OpenTK 3.x (the 3.x series NuGet packages)
8 | - .Net Core for OpenTK 4.x (the 4.x series NuGet packages)
9 |
10 | Since version 3.0.0, we're using full OpenGL/DirectX interop via OpenGL extensions - [NV_DX_interop](https://www.khronos.org/registry/OpenGL/extensions/NV/WGL_NV_DX_interop.txt).
11 | This should run almost everywhere with **AMAZING PERFORMANCE** and is fully supported on Intel, AMD and Nvidia graphics.
12 |
13 | This offers a way more clean solution than embedding GLControl and totally solves [the airspace problem](https://stackoverflow.com/questions/8006092/controls-dont-show-over-winforms-host).
14 | As controls can be layered, nested and structured over your 3D view.
15 |
16 | ## Getting started:
17 |
18 | 1. [Install via NuGet](https://www.nuget.org/packages/OpenTK.GLWpfControl)
19 | 2. In your window, include GLWpfControl.
20 | ```XML
21 |
25 | ```
26 | 3. Add the control into a container (Grid, StackPanel, etc.) and add a handler method to the render event.
27 |
28 | ```XML
29 |
30 | ...
31 |
34 | ...
35 |
36 | ```
37 | 4. In the code behind add to the constructor, after the InitializeComponents call, a call to the start method of the GLWpfControl.
38 | ```CS
39 | public MainWindow() {
40 | InitializeComponent();
41 | // [...]
42 | var settings = new GLWpfControlSettings
43 | {
44 | MajorVersion = 3,
45 | MinorVersion = 6
46 | };
47 | OpenTkControl.Start(settings);
48 | }
49 | ```
50 | 5. You can now render in the OnRender handler.
51 | ```CS
52 | private void OpenTkControl_OnRender(TimeSpan delta) {
53 | GL.ClearColor(Color4.Blue);
54 | GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
55 | }
56 | ```
57 | For additional examples, see [MainWindow.xaml](https://github.com/opentk/GLWpfControl/blob/master/src/Example/MainWindow.xaml) and [MainWindow.xaml.cs](https://github.com/opentk/GLWpfControl/blob/master/src/Example/MainWindow.xaml.cs) in the example project.
58 |
59 | ### I can't receive keyboard input when my control doesn't have keyboard focus!
60 |
61 | WPF by design only sends keyboard events to the control that has keybaord focus. To be able to get keyboard focus a control needs to have `Focusable==true` (this is the default for GLWpfControl) and `IsVisible==true`.
62 |
63 | If you however need to get keyboard events idependent of keyboard focus you will have to use the `Keyboard.AddPreview*` functions.
64 | These functions allow you to register a preview event that is called before the control with keyboard focus gets the keyboard event.
65 |
66 | This replaces the old `CanInvokeOnHandledEvents` and `RegisterToEventsDirectly` settings.
67 |
68 | See [Example](./src/Example/TabbedMainWindowTest.xaml.cs) for an example how to set this up.
69 |
70 | ## Build instructions
71 |
72 | 1. Clone repository
73 | ```shell
74 | $ git clone https://github.com/varon/GLWpfControl.git
75 | $ cd GLWpfControl
76 | ```
77 | or for SSH
78 | ```shell
79 | $ git clone git@github.com:varon/GLWpfControl.git
80 | $ cd GLWpfControl
81 | ```
82 | 2. Run `build.cmd` or `build.sh`.
83 | 3. Develop as normal in whatever IDE you like.
84 |
85 |
86 | ## Planned features
87 |
88 | #### DX-Hijacking rendering
89 |
90 | It's possible to bypass the RTT that takes place in WPF D3dImage by stealing the actual D3d handle from WPF and drawing manually.
91 | This is incredibly challenging, but would offer APEX performance as zero indirection is required.
92 | Currently more of an idea than a work in progress.
93 | Contributions welcome - Drop by the [Discord](https://discord.gg/6HqD48s) server if you want to give this a shot!
94 |
--------------------------------------------------------------------------------
/RELEASE_NOTES.md:
--------------------------------------------------------------------------------
1 | ## 4.3.3
2 |
3 | * Fix crashes related to `Dispose` and unloading of the control in general. (@Krugpelke, @NogginBops, @timsol, @4nonym0us)
4 | * Fixed issue where `GLWpfControl.Framebuffer` property stopped working. (@insel-maz, @NogginBops)
5 | * Hopefully fixed a few crashes related to MSAA not being supported. (@NogginBops)
6 | * Added `GLWpfControl.SupportsMSAA` property to check if MSAA will be supported. (@NogginBops)
7 |
8 | ## 4.3.2
9 |
10 | * Fixed AccessViolationException when disposing GLWpfControl. (@NogginBops)
11 | * Fixed issue where GLWpfControl would not work on integrated graphics cards.
12 | The current fix doesn't support using MSAA on these graphics cards and will throw a COMException. This is something we want to fix or be able to detect in the future. (@NogginBops)
13 | * Fixed issue where resizing control would leak GL objects due to wrong deletion order. (@NogginBops)
14 |
15 | ## 4.3.1
16 |
17 | Hotfix release to fix context handling in `4.3.0`.
18 |
19 | * Added documentation comments about OpenGL context handling. (@NogginBops)
20 | * Fixed issue where when multiple GLWpfControls only the last initialized controls OpenGL context would be current. (@NogginBops)
21 |
22 | ## 4.3.0
23 |
24 | * Made each `GLWpfControl` have it's own OpenGL context allowing different controls to have different context settings. (@NogginBops)
25 | * Enabled multisample anti-aliasing though `GLWpfControlSettings.Samples`. (@NogginBops)
26 | * Implemented `IDisposable` for `GLWpfControl` that allows native DirectX and OpenGL resources to be freed. (@NogginBops)
27 | * Made `GLWpfControl` have `Focusable` be `true` by default, solving a lot of the keyboard input event issues. (@NogginBops)
28 | * Deprecated `GLWpfControlSettings.GraphicsContextFlags` in favor of `GLWpfControlSettings.ContextFlags`. (@NogginBops)
29 | * Deprecated `GLWpfControlSettings.GraphicsProfile` in favor of `GLWpfControlSettings.Profile`. (@NogginBops)
30 | * Added `GLWpfControlSettings.SharedContext` to allow context sharing. (@NogginBops)
31 | * Deprecated `GLWpfControl.CanInvokeOnHandledEvents` and `GLWpfControl.RegisterToEventsDirectly`, updated readme to reflect this. (@NogginBops)
32 | * Fixed rounding issues related to DPI scaling. (@NogginBops, @5E-324)
33 | * Updated to depend on OpenTK 4.8.2. (@NogginBops, @softwareantics)
34 | * Fixed memory leak where DirectX resouces would never be freed. (@NogginBops)
35 |
36 | ## 4.2.3
37 |
38 | * Fix event issue, use `RegisterToEventsDirectly` and `CanInvokeOnHandledEvents` to customize event registering/handling. (@softwareantics)
39 | * Internal cleanup that fixed issue where setting `RenderContinuously = false` caused an extra call to render. (@francotiveron)
40 |
41 | ## 4.2.2
42 |
43 | * Fix issue where `4.2.1` was only compatible with `netcoreapp3.1-windows` and nothing else.
44 |
45 | ## 4.2.1
46 |
47 | * Fix broken nuget package in `4.2.0`.
48 |
49 | ## 4.2.0
50 | * Add ability to make the control transparent by setting `GLWpfControlSettings.TransparentBackground` to true. (@luiscuenca)
51 | * Change the dependency on OpenTK to be >= 4.3.0 < 5.0.0. (@NogginBops)
52 | * Add ability to pass a custom `IBindingsContext` in `GLWpfControlSettings`. (@Kaktusbot)
53 | * Add stencil buffer to the framebuffer. (@Svabik)
54 | * Fixed issue where remote desktop would fail due to having to use a software implementation of OpenGL. (@marcotod1410)
55 | * Fixed so that `KeyDownEvent` and `KeyUpEvent` properly work in the control. (@BBoldenow)
56 |
57 | ## 4.1.0
58 | * Add NonReloadingTabControl.
59 | * Add example with new NonReloadingTabControl.
60 |
61 | ## 4.0.0
62 | * Fix resizing
63 | * Unseal GLWpfControl
64 | * Fix crash on framebuffer access before inits
65 |
66 | ## 4.0.0-pre.12
67 | * Improved rendering performance by avoiding duplicate render calls (@marcotod1410)
68 | * Fix FrameBufferWidth property returning height incorrectly.
69 | * Fix resizing
70 |
71 | ## 4.0.0-pre.11
72 | * Fix for resource deallocation issue.
73 |
74 | ## 4.0.0-pre.10
75 | * Fix crash due to context mangling in tabbed views
76 |
77 | ## 4.0.0-pre.9
78 | * Fix crash for tabbed window
79 | * Total rewrite of the backend
80 | * All memory leaks removed
81 | * Faster loading
82 | * Faster resizing
83 | * Less memory usage
84 | * Reduced duplicate rendering
85 | * New design time preview
86 | * Simpler examples
87 | * Update to OpenTK 4.3.0
88 |
89 | ## 4.0.0-pre.8
90 | * Total rewrite of the backend
91 | * All memory leaks removed
92 | * Faster loading
93 | * Faster resizing
94 | * Less memory usage
95 | * Reduced duplicate rendering
96 | * New design time preview
97 | * Simpler examples
98 | * Update to OpenTK 4.3.0
99 |
100 | ## 4.0.0-pre.7
101 | * Fix design mode crash in Visual Studio.
102 |
103 | ## 4.0.0-pre.6
104 | * Update to OpenTK 4.3.0
105 |
106 | ## 4.0.0-pre.5
107 | * Fix for one-frame delay on startup (no more flashing screen) (@bezo97)
108 |
109 | ## 4.0.0-pre.4
110 | * Add support for DPI Scaling + optional config values to ignore this. (@marcotod1410)
111 | * Added Framebuffer Size to API. (@ marcotod1410)
112 | * Fix render initialization if not visible at the start (@marcotod1410)
113 | * Remove dependency on SharpDX and replace with custom bindings (@bezo97)
114 |
115 | ## 4.0.0-pre.3
116 | * Fix crash if control was to collapsed on startup.
117 |
118 | ## 4.0.0-pre.2
119 | * Fix Gamma/Linear color space issue (Thanks @Justin113D)
120 |
121 | ## 4.0.0-pre.1
122 | * Dotnet Core Support
123 | * Retarget to OpenTK 4.2.0
124 |
125 | ## 3.1.1
126 | * Backport of fix gamma/colour space issues (Thanks @Justin113D)
127 |
128 | ## 3.1.0
129 | * Add support for non-continuous event-based rendering via InvalidateVisual().
130 | * Fix Incorrect minor version in OpenGL Settings.
131 |
132 | ## 3.0.1
133 | * Fix SharpDX.Direct3D9 dependency.
134 |
135 | ## 3.0.0
136 | * >10x performance increase via DirectX interop. Huge thanks to @Zcore.
137 | * Simplified API
138 | * Removed software render path
139 | * Added automatic context sharing by default
140 |
141 | ## 2.1.0
142 | * Allow support for external contexts across multiple controls.
143 |
144 | ## 2.0.3
145 | * Improve fix for event-ordering crash on some systems.
146 |
147 | ## 2.0.2
148 | * Possible fix for event-ordering crash on some systems.
149 |
150 | ## 2.0.1
151 | * Fix resize events not being raised.
152 |
153 | ## 2.0.0
154 | * Moved namespace to OpenTK.Wpf.
155 | * GLWpfControl now extends FrameworkElement instead of Control.
156 | * Moved to pure-code solution for greater simplicity.
157 | * Added some extra-paranoid null checking.
158 |
159 | ## 1.1.2
160 | * Possible fix for NPE on renderer access.
161 |
162 | ## 1.1.1
163 | * Automatically set the viewport for the user.
164 |
165 | ## 1.1.0
166 | * Use own HWND for improved performance (Thanks to @Eschryn)
167 | * Add time delta to the render event.
168 | * Better handling of resizing via delayed updates.
169 | * Remove slow-path detection (2x performance on low-end devices!)
170 | * Fix duplicate OpenGL resource unloading.
171 |
172 | ## 1.0.1
173 | * Add API to access the control's framebuffer.
174 |
175 | ## 1.0.0
176 | * Initial release
177 |
178 |
--------------------------------------------------------------------------------
/build.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | SET PATH=%LOCALAPPDATA%\Microsoft\dotnet;%PATH%
4 | .paket\paket.bootstrapper.exe
5 |
6 | SET BuildTarget=
7 | if "%BuildRunner%" == "MyGet" (
8 | SET BuildTarget=NuGet
9 |
10 | :: Replace the existing release notes file with one for this build only
11 | echo ### %PackageVersion% > RELEASE_NOTES.md
12 | echo * git build >> RELEASE_NOTES.md
13 | )
14 |
15 | dotnet tool restore
16 | dotnet fake run build.fsx %*
17 |
--------------------------------------------------------------------------------
/build.fsx:
--------------------------------------------------------------------------------
1 | // --------------------------------------------------------------------------------------
2 | // FAKE build script
3 | // --------------------------------------------------------------------------------------
4 | open System
5 | open System.IO
6 | open System.Threading
7 | open System.Diagnostics
8 | open Fake.Core
9 | open Fake.DotNet
10 | open Fake.DotNet.NuGet
11 | open Fake.IO
12 |
13 | #r "paket:
14 | storage: packages
15 | nuget Fake.IO.FileSystem
16 | nuget Fake.DotNet.MSBuild
17 | nuget Fake.DotNet.Testing.XUnit2
18 | nuget Fake.DotNet.AssemblyInfoFile
19 | nuget Fake.DotNet.NuGet prerelease
20 | nuget Fake.DotNet.Paket
21 | nuget Fake.DotNet.Cli
22 | nuget Fake.Core.Target
23 | nuget Fake.Net.Http
24 | nuget Fake.Api.Github
25 | nuget xunit.runner.console
26 | nuget NuGet.CommandLine
27 | nuget Fake.Core.ReleaseNotes //"
28 |
29 | #load "./.fake/build.fsx/intellisense.fsx"
30 |
31 | open Fake.IO;
32 | open Fake.IO.FileSystemOperators
33 | open Fake.IO.Globbing.Operators
34 |
35 | // --------------------------------------------------------------------------------------
36 | // project-specific details below
37 | // --------------------------------------------------------------------------------------
38 |
39 | // Information about the project are used
40 | // - for version and project name in generated AssemblyInfo file
41 | // - by the generated NuGet package
42 | // - to run tests and to publish documentation on GitHub gh-pages
43 | // - for documentation, you also need to edit info in "docs/tools/generate.fsx"
44 |
45 | // The name of the project
46 | // (used by attributes in AssemblyInfo, name of a NuGet package and directory in 'src')
47 | let project = "OpenTK.GLWpfControl"
48 |
49 | // Short summary of the project
50 | // (used as description in AssemblyInfo and as a short summary for NuGet package)
51 | let summary = "A native WPF control for OpenTK 4.X."
52 |
53 | // Longer description of the project
54 | // (used as a description for NuGet package; line breaks are automatically cleaned up)
55 | let description = ""
56 |
57 | // List of author names (for NuGet package)
58 | let authors = [ "varon"; "NogginBops" ]
59 |
60 | // Tags for your project (for NuGet package)
61 | let tags = "WPF OpenTK OpenGL OpenGLES GLES OpenAL C# F# VB .NET Mono Vector Math Game Graphics Sound"
62 |
63 | let copyright = "Copyright (c) 2020 Team OpenTK."
64 |
65 | // File system information
66 | let solutionFile = "GLWpfControl.sln"
67 |
68 | let binDir = "./bin/"
69 | let buildDir = binDir > "build"
70 | let nugetDir = binDir > "nuget"
71 | let testDir = binDir > "test"
72 |
73 | // Pattern specifying assemblies to be tested using NUnit
74 | let testAssemblies = "tests/**/bin/Release/*Tests*.dll"
75 |
76 | // Git configuration (used for publishing documentation in gh-pages branch)
77 | // The profile where the project is posted
78 | let gitOwner = "opentk"
79 | let gitHome = "https://github.com/" + gitOwner
80 |
81 | // The name of the project on GitHub
82 | let gitName = "GLWpfControl"
83 |
84 | // The url for the raw files hosted
85 | let gitRaw = Environment.environVarOrDefault "gitRaw" "https://raw.github.com/opentk"
86 |
87 | // --------------------------------------------------------------------------------------
88 | // The rest of the file includes standard build steps
89 | // --------------------------------------------------------------------------------------
90 |
91 | // Read additional information from the release notes document
92 | let release = ReleaseNotes.load "RELEASE_NOTES.md"
93 |
94 | // Helper active pattern for project types
95 | let (|Fsproj|Csproj|Vbproj|) (projFileName:string) =
96 | match projFileName with
97 | | f when f.EndsWith "fsproj" -> Fsproj
98 | | f when f.EndsWith "csproj" -> Csproj
99 | | f when f.EndsWith "vbproj" -> Vbproj
100 | | _ -> failwith (sprintf "Project file %s not supported. Unknown project type." projFileName)
101 |
102 | let activeProjects =
103 | !! "src/**/*.??proj"
104 |
105 | let releaseProjects =
106 | !! "src/**/*.??proj"
107 | -- "src/Example/**"
108 |
109 | let install =
110 | lazy
111 | (if (DotNet.getVersion id).StartsWith "6" then id
112 | else DotNet.install (fun options -> { options with Version = DotNet.Version "6.0.200" }))
113 |
114 | // Set general properties without arguments
115 | let inline dotnetSimple arg = DotNet.Options.lift install.Value arg
116 |
117 | // Generate assembly info files with the right version & up-to-date information
118 | Target.create "AssemblyInfo" (fun _ ->
119 | let getAssemblyInfoAttributes (projectName:string) =
120 | [
121 | AssemblyInfo.Title (projectName)
122 | AssemblyInfo.Product project
123 | AssemblyInfo.Description summary
124 | AssemblyInfo.Version release.AssemblyVersion
125 | AssemblyInfo.FileVersion release.AssemblyVersion
126 | AssemblyInfo.CLSCompliant true
127 | AssemblyInfo.Copyright copyright
128 | ]
129 |
130 | let getProjectDetails projectPath =
131 | let projectName = Path.GetFileNameWithoutExtension((string)projectPath)
132 | ( projectPath,
133 | Path.GetDirectoryName((string)projectPath),
134 | (getAssemblyInfoAttributes projectName)
135 | )
136 |
137 | activeProjects
138 | |> Seq.map getProjectDetails
139 | |> Seq.iter (fun (projFileName, folderName, attributes) ->
140 | match projFileName with
141 | | Fsproj -> AssemblyInfoFile.createFSharp (folderName @@ "AssemblyInfo.fs") attributes
142 | | Csproj -> AssemblyInfoFile.createCSharp ((folderName @@ "Properties") @@ "AssemblyInfo.cs") attributes
143 | | Vbproj -> AssemblyInfoFile.createVisualBasic ((folderName @@ "My Project") @@ "AssemblyInfo.vb") attributes
144 | )
145 | )
146 |
147 | // Copies binaries from default VS location to expected bin folder
148 | // But keeps a subdirectory structure for each project in the
149 | // src folder to support multiple project outputs
150 | Target.create "CopyBinaries" (fun _ ->
151 | activeProjects
152 | |> Seq.map (fun f -> ((System.IO.Path.GetDirectoryName f) @@ "bin/Release", "bin" @@ (System.IO.Path.GetFileNameWithoutExtension f)))
153 | |> Seq.iter (fun (fromDir, toDir) -> Shell.copyDir toDir fromDir (fun _ -> true))
154 | )
155 |
156 | // --------------------------------------------------------------------------------------
157 | // Clean build results
158 |
159 | Target.create "Clean" (fun _ ->
160 | Shell.cleanDirs ["bin"; "temp"]
161 | )
162 |
163 | Target.create "Restore" (fun _ -> DotNet.restore dotnetSimple "GLWpfControl.sln" |> ignore)
164 |
165 | // --------------------------------------------------------------------------------------
166 | // Build library & test project
167 |
168 | Target.create "Build" (fun _ ->
169 | let setOptions a =
170 | let customParams = sprintf "/p:PackageVersion=%s /p:ProductVersion=%s" release.AssemblyVersion release.NugetVersion
171 | DotNet.Options.withCustomParams (Some customParams) (dotnetSimple a)
172 |
173 | for proj in activeProjects do
174 | DotNet.build setOptions proj
175 |
176 | )
177 |
178 | // --------------------------------------------------------------------------------------
179 | // Build a NuGet package
180 |
181 | Target.create "CreateNuGetPackage" (fun _ ->
182 | Directory.CreateDirectory nugetDir |> ignore
183 | let notes = release.Notes |> List.reduce (fun s1 s2 -> s1 + "\n" + s2)
184 |
185 | for proj in releaseProjects do
186 | Trace.logf "Creating nuget package for Project: %s\n" proj
187 |
188 | let dir = Path.GetDirectoryName proj
189 | let templatePath = Path.Combine(dir, "paket")
190 | let oldTemplateContent = File.ReadAllText templatePath
191 | let newTemplateContent = oldTemplateContent.Insert(
192 | oldTemplateContent.Length,
193 | sprintf "\nversion \n\t%s\nauthors \n\t%s\nowners \n\t%s\n"
194 | release.NugetVersion
195 | (authors |> List.reduce (fun s a -> s + " " + a))
196 | (authors |> List.reduce (fun s a -> s + " " + a))).Replace(
197 | "#VERSION#", release.NugetVersion)
198 | File.WriteAllText(templatePath+".template", newTemplateContent);
199 |
200 | Trace.logf "Packing into folder: %s\n" (Path.GetFullPath(nugetDir))
201 |
202 | let setParams (p:Paket.PaketPackParams) =
203 | { p with
204 | ReleaseNotes = notes
205 | OutputPath = Path.GetFullPath(nugetDir)
206 | WorkingDir = dir
207 | Version = release.NugetVersion
208 | }
209 | Paket.pack setParams
210 | )
211 |
212 |
213 | Target.create "BuildPackage" ignore
214 |
215 | // ---------
216 | // Release Targets
217 | // ---------
218 |
219 | open Fake.Api
220 |
221 | Target.create "ReleaseOnGitHub" (fun _ ->
222 | let token =
223 | match Environment.environVarOrDefault "opentk_github_token" "" with
224 | | s when not (System.String.IsNullOrWhiteSpace s) -> s
225 | | _ ->
226 | failwith
227 | "please set the github_token environment variable to a github personal access token with repro access."
228 |
229 | let files = !!"bin/*" |> Seq.toList
230 |
231 | GitHub.createClientWithToken token
232 | |> GitHub.draftNewRelease gitOwner gitName release.NugetVersion (release.SemVer.PreRelease <> None) release.Notes
233 | //|> GitHub.uploadFiles files
234 | |> GitHub.publishDraft
235 | |> Async.RunSynchronously)
236 |
237 | Target.create "ReleaseOnNuGet" (fun _ ->
238 | let apiKey =
239 | match Environment.environVarOrDefault "opentk_nuget_api_key" "" with
240 | | s when not (System.String.IsNullOrWhiteSpace s) -> s
241 | | _ -> failwith "please set the nuget_api_key environment variable to a nuget access token."
242 |
243 | !! (nugetDir > "*.nupkg")
244 | |> Seq.iter
245 | (DotNet.nugetPush (fun opts ->
246 | { opts with
247 | PushParams =
248 | { opts.PushParams with
249 | ApiKey = Some apiKey
250 | Source = Some "nuget.org" } })))
251 |
252 | Target.create "ReleaseOnAll" ignore
253 |
254 | // --------------------------------------------------------------------------------------
255 | // Run all targets by default. Invoke 'build ' to override
256 |
257 | open Fake.Core.TargetOperators
258 |
259 | Target.create "All" ignore
260 |
261 | "Clean"
262 | ==> "Restore"
263 | ==> "AssemblyInfo"
264 | ==> "Build"
265 | ==> "CopyBinaries"
266 | ==> "All"
267 |
268 | "All"
269 | ==> "CreateNuGetPackage"
270 | ==> "ReleaseOnNuGet"
271 | ==> "ReleaseOnGithub"
272 | ==> "ReleaseOnAll"
273 |
274 | Target.runOrDefault "All"
275 |
--------------------------------------------------------------------------------
/build.fsx.lock:
--------------------------------------------------------------------------------
1 | STORAGE: PACKAGES
2 | RESTRICTION: == netstandard2.0
3 | NUGET
4 | remote: https://api.nuget.org/v3/index.json
5 | BlackFox.VsWhere (1.1)
6 | FSharp.Core (>= 4.2.3)
7 | Microsoft.Win32.Registry (>= 4.7)
8 | Fake.Api.GitHub (5.20.4)
9 | FSharp.Core (>= 4.7.2)
10 | Octokit (>= 0.48)
11 | Fake.Core.CommandLineParsing (5.20.4)
12 | FParsec (>= 1.1.1)
13 | FSharp.Core (>= 4.7.2)
14 | Fake.Core.Context (5.20.4)
15 | FSharp.Core (>= 4.7.2)
16 | Fake.Core.Environment (5.20.4)
17 | FSharp.Core (>= 4.7.2)
18 | Fake.Core.FakeVar (5.20.4)
19 | Fake.Core.Context (>= 5.20.4)
20 | FSharp.Core (>= 4.7.2)
21 | Fake.Core.Process (5.20.4)
22 | Fake.Core.Environment (>= 5.20.4)
23 | Fake.Core.FakeVar (>= 5.20.4)
24 | Fake.Core.String (>= 5.20.4)
25 | Fake.Core.Trace (>= 5.20.4)
26 | Fake.IO.FileSystem (>= 5.20.4)
27 | FSharp.Core (>= 4.7.2)
28 | System.Collections.Immutable (>= 1.7.1)
29 | Fake.Core.ReleaseNotes (5.20.4)
30 | Fake.Core.SemVer (>= 5.20.4)
31 | Fake.Core.String (>= 5.20.4)
32 | FSharp.Core (>= 4.7.2)
33 | Fake.Core.SemVer (5.20.4)
34 | FSharp.Core (>= 4.7.2)
35 | Fake.Core.String (5.20.4)
36 | FSharp.Core (>= 4.7.2)
37 | Fake.Core.Target (5.20.4)
38 | Fake.Core.CommandLineParsing (>= 5.20.4)
39 | Fake.Core.Context (>= 5.20.4)
40 | Fake.Core.Environment (>= 5.20.4)
41 | Fake.Core.FakeVar (>= 5.20.4)
42 | Fake.Core.Process (>= 5.20.4)
43 | Fake.Core.String (>= 5.20.4)
44 | Fake.Core.Trace (>= 5.20.4)
45 | FSharp.Control.Reactive (>= 4.4.2)
46 | FSharp.Core (>= 4.7.2)
47 | Fake.Core.Tasks (5.20.4)
48 | Fake.Core.Trace (>= 5.20.4)
49 | FSharp.Core (>= 4.7.2)
50 | Fake.Core.Trace (5.20.4)
51 | Fake.Core.Environment (>= 5.20.4)
52 | Fake.Core.FakeVar (>= 5.20.4)
53 | FSharp.Core (>= 4.7.2)
54 | Fake.Core.Xml (5.20.4)
55 | Fake.Core.String (>= 5.20.4)
56 | FSharp.Core (>= 4.7.2)
57 | Fake.DotNet.AssemblyInfoFile (5.20.4)
58 | Fake.Core.Environment (>= 5.20.4)
59 | Fake.Core.String (>= 5.20.4)
60 | Fake.Core.Trace (>= 5.20.4)
61 | Fake.IO.FileSystem (>= 5.20.4)
62 | FSharp.Core (>= 4.7.2)
63 | Fake.DotNet.Cli (5.20.4)
64 | Fake.Core.Environment (>= 5.20.4)
65 | Fake.Core.Process (>= 5.20.4)
66 | Fake.Core.String (>= 5.20.4)
67 | Fake.Core.Trace (>= 5.20.4)
68 | Fake.DotNet.MSBuild (>= 5.20.4)
69 | Fake.DotNet.NuGet (>= 5.20.4)
70 | Fake.IO.FileSystem (>= 5.20.4)
71 | FSharp.Core (>= 4.7.2)
72 | Mono.Posix.NETStandard (>= 1.0)
73 | Newtonsoft.Json (>= 12.0.3)
74 | Fake.DotNet.MSBuild (5.20.4)
75 | BlackFox.VsWhere (>= 1.1)
76 | Fake.Core.Environment (>= 5.20.4)
77 | Fake.Core.Process (>= 5.20.4)
78 | Fake.Core.String (>= 5.20.4)
79 | Fake.Core.Trace (>= 5.20.4)
80 | Fake.IO.FileSystem (>= 5.20.4)
81 | FSharp.Core (>= 4.7.2)
82 | MSBuild.StructuredLogger (>= 2.1.176)
83 | Fake.DotNet.NuGet (5.20.4)
84 | Fake.Core.Environment (>= 5.20.4)
85 | Fake.Core.Process (>= 5.20.4)
86 | Fake.Core.SemVer (>= 5.20.4)
87 | Fake.Core.String (>= 5.20.4)
88 | Fake.Core.Tasks (>= 5.20.4)
89 | Fake.Core.Trace (>= 5.20.4)
90 | Fake.Core.Xml (>= 5.20.4)
91 | Fake.IO.FileSystem (>= 5.20.4)
92 | Fake.Net.Http (>= 5.20.4)
93 | FSharp.Core (>= 4.7.2)
94 | Newtonsoft.Json (>= 12.0.3)
95 | NuGet.Protocol (>= 5.6)
96 | Fake.DotNet.Paket (5.20.4)
97 | Fake.Core.Process (>= 5.20.4)
98 | Fake.Core.String (>= 5.20.4)
99 | Fake.Core.Trace (>= 5.20.4)
100 | Fake.DotNet.Cli (>= 5.20.4)
101 | Fake.IO.FileSystem (>= 5.20.4)
102 | FSharp.Core (>= 4.7.2)
103 | Fake.DotNet.Testing.XUnit2 (5.20.4)
104 | Fake.Core.Process (>= 5.20.4)
105 | Fake.Core.String (>= 5.20.4)
106 | Fake.Core.Trace (>= 5.20.4)
107 | Fake.IO.FileSystem (>= 5.20.4)
108 | Fake.Testing.Common (>= 5.20.4)
109 | FSharp.Core (>= 4.7.2)
110 | Fake.IO.FileSystem (5.20.4)
111 | Fake.Core.String (>= 5.20.4)
112 | FSharp.Core (>= 4.7.2)
113 | Fake.Net.Http (5.20.4)
114 | Fake.Core.Trace (>= 5.20.4)
115 | FSharp.Core (>= 4.7.2)
116 | Fake.Testing.Common (5.20.4)
117 | Fake.Core.Trace (>= 5.20.4)
118 | FSharp.Core (>= 4.7.2)
119 | FParsec (1.1.1)
120 | FSharp.Core (>= 4.3.4)
121 | FSharp.Control.Reactive (5.0.2)
122 | FSharp.Core (>= 4.7.2)
123 | System.Reactive (>= 5.0)
124 | FSharp.Core (5.0.1)
125 | Microsoft.Bcl.AsyncInterfaces (6.0)
126 | System.Threading.Tasks.Extensions (>= 4.5.4)
127 | Microsoft.Build (17.0)
128 | Microsoft.Build.Framework (>= 17.0)
129 | Microsoft.NET.StringTools (>= 1.0)
130 | Microsoft.Win32.Registry (>= 4.3)
131 | System.Collections.Immutable (>= 5.0)
132 | System.Configuration.ConfigurationManager (>= 4.7)
133 | System.Reflection.Metadata (>= 1.6)
134 | System.Security.Principal.Windows (>= 4.7)
135 | System.Text.Encoding.CodePages (>= 4.0.1)
136 | System.Text.Json (>= 5.0.2)
137 | System.Threading.Tasks.Dataflow (>= 4.9)
138 | Microsoft.Build.Framework (17.0)
139 | System.Security.Permissions (>= 4.7)
140 | Microsoft.Build.Tasks.Core (17.0)
141 | Microsoft.Build.Framework (>= 17.0)
142 | Microsoft.Build.Utilities.Core (>= 17.0)
143 | Microsoft.NET.StringTools (>= 1.0)
144 | Microsoft.Win32.Registry (>= 4.3)
145 | System.CodeDom (>= 4.4)
146 | System.Collections.Immutable (>= 5.0)
147 | System.Reflection.Metadata (>= 1.6)
148 | System.Resources.Extensions (>= 4.6)
149 | System.Security.Cryptography.Pkcs (>= 4.7)
150 | System.Security.Cryptography.Xml (>= 4.7)
151 | System.Security.Permissions (>= 4.7)
152 | System.Threading.Tasks.Dataflow (>= 4.9)
153 | Microsoft.Build.Utilities.Core (17.0)
154 | Microsoft.Build.Framework (>= 17.0)
155 | Microsoft.NET.StringTools (>= 1.0)
156 | Microsoft.Win32.Registry (>= 4.3)
157 | System.Collections.Immutable (>= 5.0)
158 | System.Configuration.ConfigurationManager (>= 4.7)
159 | System.Security.Permissions (>= 4.7)
160 | System.Text.Encoding.CodePages (>= 4.0.1)
161 | Microsoft.NET.StringTools (1.0)
162 | System.Memory (>= 4.5.4)
163 | System.Runtime.CompilerServices.Unsafe (>= 5.0)
164 | Microsoft.NETCore.Platforms (6.0.1)
165 | Microsoft.NETCore.Targets (5.0)
166 | Microsoft.Win32.Registry (5.0)
167 | System.Buffers (>= 4.5.1)
168 | System.Memory (>= 4.5.4)
169 | System.Security.AccessControl (>= 5.0)
170 | System.Security.Principal.Windows (>= 5.0)
171 | Mono.Posix.NETStandard (1.0)
172 | MSBuild.StructuredLogger (2.1.545)
173 | Microsoft.Build (>= 16.10)
174 | Microsoft.Build.Framework (>= 16.10)
175 | Microsoft.Build.Tasks.Core (>= 16.10)
176 | Microsoft.Build.Utilities.Core (>= 16.10)
177 | Newtonsoft.Json (13.0.1)
178 | NuGet.CommandLine (6.0)
179 | NuGet.Common (6.0)
180 | NuGet.Frameworks (>= 6.0)
181 | NuGet.Configuration (6.0)
182 | NuGet.Common (>= 6.0)
183 | System.Security.Cryptography.ProtectedData (>= 4.4)
184 | NuGet.Frameworks (6.0)
185 | NuGet.Packaging (6.0)
186 | Newtonsoft.Json (>= 13.0.1)
187 | NuGet.Configuration (>= 6.0)
188 | NuGet.Versioning (>= 6.0)
189 | System.Security.Cryptography.Cng (>= 5.0)
190 | System.Security.Cryptography.Pkcs (>= 5.0)
191 | NuGet.Protocol (6.0)
192 | NuGet.Packaging (>= 6.0)
193 | NuGet.Versioning (6.0)
194 | Octokit (0.50)
195 | System.Buffers (4.5.1)
196 | System.CodeDom (6.0)
197 | System.Collections.Immutable (6.0)
198 | System.Memory (>= 4.5.4)
199 | System.Runtime.CompilerServices.Unsafe (>= 6.0)
200 | System.Configuration.ConfigurationManager (6.0)
201 | System.Security.Cryptography.ProtectedData (>= 6.0)
202 | System.Security.Permissions (>= 6.0)
203 | System.Formats.Asn1 (6.0)
204 | System.Buffers (>= 4.5.1)
205 | System.Memory (>= 4.5.4)
206 | System.Memory (4.5.4)
207 | System.Buffers (>= 4.5.1)
208 | System.Numerics.Vectors (>= 4.4)
209 | System.Runtime.CompilerServices.Unsafe (>= 4.5.3)
210 | System.Numerics.Vectors (4.5)
211 | System.Reactive (5.0)
212 | System.Runtime.InteropServices.WindowsRuntime (>= 4.3)
213 | System.Threading.Tasks.Extensions (>= 4.5.4)
214 | System.Reflection.Metadata (6.0)
215 | System.Collections.Immutable (>= 6.0)
216 | System.Resources.Extensions (6.0)
217 | System.Memory (>= 4.5.4)
218 | System.Runtime (4.3.1)
219 | Microsoft.NETCore.Platforms (>= 1.1.1)
220 | Microsoft.NETCore.Targets (>= 1.1.3)
221 | System.Runtime.CompilerServices.Unsafe (6.0)
222 | System.Runtime.InteropServices.WindowsRuntime (4.3)
223 | System.Runtime (>= 4.3)
224 | System.Security.AccessControl (6.0)
225 | System.Security.Principal.Windows (>= 5.0)
226 | System.Security.Cryptography.Cng (5.0)
227 | System.Security.Cryptography.Pkcs (6.0)
228 | System.Buffers (>= 4.5.1)
229 | System.Formats.Asn1 (>= 6.0)
230 | System.Memory (>= 4.5.4)
231 | System.Security.Cryptography.Cng (>= 5.0)
232 | System.Security.Cryptography.ProtectedData (6.0)
233 | System.Memory (>= 4.5.4)
234 | System.Security.Cryptography.Xml (6.0)
235 | System.Memory (>= 4.5.4)
236 | System.Security.AccessControl (>= 6.0)
237 | System.Security.Cryptography.Pkcs (>= 6.0)
238 | System.Security.Permissions (6.0)
239 | System.Security.AccessControl (>= 6.0)
240 | System.Security.Principal.Windows (5.0)
241 | System.Text.Encoding.CodePages (6.0)
242 | System.Memory (>= 4.5.4)
243 | System.Runtime.CompilerServices.Unsafe (>= 6.0)
244 | System.Text.Encodings.Web (6.0)
245 | System.Buffers (>= 4.5.1)
246 | System.Memory (>= 4.5.4)
247 | System.Runtime.CompilerServices.Unsafe (>= 6.0)
248 | System.Text.Json (6.0.1)
249 | Microsoft.Bcl.AsyncInterfaces (>= 6.0)
250 | System.Buffers (>= 4.5.1)
251 | System.Memory (>= 4.5.4)
252 | System.Numerics.Vectors (>= 4.5)
253 | System.Runtime.CompilerServices.Unsafe (>= 6.0)
254 | System.Text.Encodings.Web (>= 6.0)
255 | System.Threading.Tasks.Extensions (>= 4.5.4)
256 | System.Threading.Tasks.Dataflow (6.0)
257 | System.Threading.Tasks.Extensions (4.5.4)
258 | System.Runtime.CompilerServices.Unsafe (>= 4.5.3)
259 | xunit.runner.console (2.4.1)
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e -o
4 |
5 | function version_compare() {
6 | ver1=(${1//./ })
7 | ver2=(${2//./ })
8 |
9 | len1=${#ver1[@]}
10 | len2=${#ver2[@]}
11 |
12 | vlen=$(($len1 < $len2 ? $len1 : $len2))
13 |
14 | for ((i=0;i /dev/null) || EXIT_CODE=$?
28 |
29 | if (($EXIT_CODE == 0)) && version_compare "$MINIMAL_DOTNET_VERSION" "$CURRENT_DOTNET_VERSION"; then
30 | echo "dotnet command already installed"
31 | else
32 | # Install .NET Core (https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-install-script)
33 | curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --version 3.1.100
34 |
35 | PATH="~/.dotnet:$PATH"
36 | fi
37 |
38 | FSIARGS=""
39 | OS=${OS:-"unknown"}
40 | if [[ "$OS" != "Windows_NT" ]]
41 | then
42 | FSIARGS="--fsiargs -d:MONO"
43 | fi
44 |
45 | function run() {
46 | if [[ "$OS" != "Windows_NT" ]]
47 | then
48 | mono "$@"
49 | else
50 | "$@"
51 | fi
52 | }
53 |
54 | run .paket/paket.bootstrapper.exe
55 |
56 | if [[ "$OS" != "Windows_NT" ]] &&
57 | [ ! -e ~/.config/.mono/certs ]
58 | then
59 | mozroots --import --sync --quiet
60 | fi
61 |
62 | dotnet tool restore
63 | dotnet fake run $FSIARGS build.fsx $@
--------------------------------------------------------------------------------
/paket.dependencies:
--------------------------------------------------------------------------------
1 | source https://api.nuget.org/v3/index.json
2 |
3 | storage: none
4 | framework: netcoreapp3.1, netstandard2.0, netstandard2.1
--------------------------------------------------------------------------------
/paket.lock:
--------------------------------------------------------------------------------
1 | STORAGE: NONE
2 | RESTRICTION: || (== netcoreapp3.1) (== netstandard2.0) (== netstandard2.1)
3 |
--------------------------------------------------------------------------------
/src/Example/App.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/Example/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace Example {
4 | ///
5 | /// Interaction logic for App.xaml
6 | ///
7 | public partial class App : Application { }
8 | }
--------------------------------------------------------------------------------
/src/Example/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
--------------------------------------------------------------------------------
/src/Example/Example.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | WinExe
4 | netcoreapp3.1
5 | true
6 | false
7 | Example.App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/Example/ExampleScene.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Runtime.CompilerServices;
4 | using OpenTK.Graphics.OpenGL;
5 | using OpenTK.Mathematics;
6 |
7 | namespace Example {
8 | /// Example class handling the rendering for OpenGL.
9 | public class ExampleScene {
10 |
11 | private static readonly Stopwatch _stopwatch = Stopwatch.StartNew();
12 |
13 | private int Program;
14 |
15 | private int VAO;
16 | private int VBO;
17 |
18 | struct Vertex
19 | {
20 | public Vector2 Position;
21 | public Color4 Color;
22 |
23 | public Vertex(Vector2 position, Color4 color)
24 | {
25 | Position = position;
26 | Color = color;
27 | }
28 | }
29 |
30 | private static readonly Vertex[] vertices =
31 | {
32 | new Vertex((0.0f, 0.5f), Color4.Red),
33 | new Vertex((0.58f, -0.5f), Color4.Green),
34 | new Vertex((-0.58f, -0.5f), Color4.Blue),
35 | };
36 |
37 | private static readonly string VertexShaderSource =
38 | @"#version 330 core
39 |
40 | in vec2 vPosition;
41 | in vec4 vColor;
42 |
43 | out vec4 fColor;
44 |
45 | void main()
46 | {
47 | gl_Position = vec4(vPosition, 0, 1);
48 | fColor = vColor;
49 | }
50 | ";
51 |
52 | private static readonly string FragmentShaderSource =
53 | @"#version 330 core
54 |
55 | in vec4 fColor;
56 |
57 | out vec4 oColor;
58 |
59 | void main()
60 | {
61 | oColor = fColor;
62 | }
63 | ";
64 |
65 | public void Initialize()
66 | {
67 | Program = GL.CreateProgram();
68 |
69 | int vertexShader = GL.CreateShader(ShaderType.VertexShader);
70 | GL.ShaderSource(vertexShader, VertexShaderSource);
71 | GL.CompileShader(vertexShader);
72 | GL.GetShader(vertexShader, ShaderParameter.CompileStatus, out int success);
73 | if (success == 0)
74 | {
75 | string log = GL.GetShaderInfoLog(vertexShader);
76 | Debug.WriteLine($"Vertex shader compile error: {log}");
77 | }
78 |
79 | int fragmentShader = GL.CreateShader(ShaderType.FragmentShader);
80 | GL.ShaderSource(fragmentShader, FragmentShaderSource);
81 | GL.CompileShader(fragmentShader);
82 | GL.GetShader(fragmentShader, ShaderParameter.CompileStatus, out success);
83 | if (success == 0)
84 | {
85 | string log = GL.GetShaderInfoLog(fragmentShader);
86 | Debug.WriteLine($"Fragment shader compile error: {log}");
87 | }
88 |
89 | GL.AttachShader(Program, vertexShader);
90 | GL.AttachShader(Program, fragmentShader);
91 | GL.LinkProgram(Program);
92 | GL.GetProgram(Program, GetProgramParameterName.LinkStatus, out success);
93 | if (success == 0)
94 | {
95 | string log = GL.GetProgramInfoLog(Program);
96 | Debug.WriteLine($"Program link error: {log}");
97 | }
98 |
99 | GL.DetachShader(Program, vertexShader);
100 | GL.DetachShader(Program, fragmentShader);
101 |
102 | GL.DeleteShader(vertexShader);
103 | GL.DeleteShader(fragmentShader);
104 |
105 | int positionLocation = GL.GetAttribLocation(Program, "vPosition");
106 | int colorLocation = GL.GetAttribLocation(Program, "vColor");
107 |
108 | VAO = GL.GenVertexArray();
109 | GL.BindVertexArray(VAO);
110 |
111 | VBO = GL.GenBuffer();
112 | GL.BindBuffer(BufferTarget.ArrayBuffer, VBO);
113 | GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * Unsafe.SizeOf(), vertices, BufferUsageHint.StaticDraw);
114 |
115 | GL.EnableVertexAttribArray(positionLocation);
116 | GL.VertexAttribPointer(positionLocation, 2, VertexAttribPointerType.Float, false, Unsafe.SizeOf(), 0);
117 |
118 | GL.EnableVertexAttribArray(colorLocation);
119 | GL.VertexAttribPointer(colorLocation, 4, VertexAttribPointerType.Float, false, Unsafe.SizeOf(), Unsafe.SizeOf());
120 | }
121 |
122 | public void Render(float alpha = 1.0f) {
123 | var hue = (float) _stopwatch.Elapsed.TotalSeconds * 0.15f % 1;
124 | var c = Color4.FromHsv(new Vector4(alpha * hue, alpha * 0.75f, alpha * 0.75f, alpha));
125 | GL.ClearColor(c);
126 | GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
127 |
128 | GL.UseProgram(Program);
129 | GL.DrawArrays(PrimitiveType.Triangles, 0, 3);
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/src/Example/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
16 |
17 |
18 |
20 |
21 |
22 |
23 |
29 |
34 |
35 |
43 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/src/Example/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using OpenTK.Wpf;
4 |
5 | namespace Example {
6 | ///
7 | /// Interaction logic for MainWindow.xaml
8 | ///
9 | public sealed partial class MainWindow {
10 |
11 | ExampleScene mainScene = new ExampleScene();
12 | ExampleScene insetScene = new ExampleScene();
13 |
14 | public MainWindow() {
15 | InitializeComponent();
16 |
17 | // You can start and rely on the Settings property that may be set in XAML or elsewhere in the codebase.
18 | OpenTkControl.Start();
19 | mainScene.Initialize();
20 |
21 | // Or, you can suppy a settings object directly.
22 | InsetControl.Start(new GLWpfControlSettings()
23 | {
24 | MajorVersion = 2,
25 | MinorVersion = 1,
26 | RenderContinuously = false,
27 | });
28 | insetScene.Initialize();
29 | }
30 |
31 | private void OpenTkControl_OnRender(TimeSpan delta) {
32 | mainScene.Render();
33 | }
34 |
35 | private void InsetControl_OnRender(TimeSpan delta) {
36 | insetScene.Render();
37 | }
38 |
39 | private void RedrawButton_OnClick(object sender, RoutedEventArgs e) {
40 | // re-draw the inset control when the button is clicked.
41 | InsetControl.InvalidateVisual();
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Example/TabbedMainWindowTest.xaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/Example/TabbedMainWindowTest.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Runtime.CompilerServices;
4 | using System.Windows.Input;
5 | using OpenTK.Windowing.Common;
6 | using OpenTK.Wpf;
7 |
8 | namespace Example
9 | {
10 | ///
11 | /// Interaction logic for TabbedMainWindowTest.xaml
12 | ///
13 | public sealed partial class TabbedMainWindowTest
14 | {
15 | // FIXME: Make this example make use of context sharing...
16 | ExampleScene scene1 = new ExampleScene();
17 | ExampleScene scene2 = new ExampleScene();
18 | ExampleScene scene3 = new ExampleScene();
19 |
20 | public TabbedMainWindowTest()
21 | {
22 | InitializeComponent();
23 | GLWpfControlSettings mainSettings = new GLWpfControlSettings {MajorVersion = 4, MinorVersion = 1, Profile = ContextProfile.Compatability, ContextFlags = ContextFlags.Debug};
24 | // Start() makes the controls context current.
25 | Control1.Start(mainSettings);
26 | // We call Context.MakeCurrent() to make this explicitly clear.
27 | Control1.Context.MakeCurrent();
28 | scene1.Initialize();
29 |
30 | GLWpfControlSettings insetSettings = new GLWpfControlSettings {MajorVersion = 4, MinorVersion = 1, Profile = ContextProfile.Compatability, ContextFlags = ContextFlags.Debug, Samples = 8};
31 | Control2.Start(insetSettings);
32 | Control2.Context.MakeCurrent();
33 | scene2.Initialize();
34 |
35 | GLWpfControlSettings transparentSettings = new GLWpfControlSettings { MajorVersion = 4, MinorVersion = 1, Profile = ContextProfile.Compatability, ContextFlags = ContextFlags.Debug, TransparentBackground = true};
36 | Control3.Start(transparentSettings);
37 | Control3.Context.MakeCurrent();
38 | scene3.Initialize();
39 |
40 | Control1.KeyDown += Control1_KeyDown;
41 |
42 | Keyboard.AddPreviewKeyDownHandler(this, Keyboard_PreviewKeyDown);
43 | }
44 |
45 | private void Keyboard_PreviewKeyDown(object sender, KeyEventArgs e)
46 | {
47 | Debug.WriteLine($"Preview key down: {e.Key}");
48 | }
49 |
50 | private void Control1_KeyDown(object sender, KeyEventArgs e)
51 | {
52 | Debug.WriteLine(e.Key);
53 |
54 | if (e.Key == Key.A)
55 | {
56 | Control1.Dispose();
57 | }
58 | }
59 |
60 | private void Control1_OnRender(TimeSpan delta)
61 | {
62 | scene1.Render();
63 | }
64 |
65 | private void Control2_OnRender(TimeSpan delta)
66 | {
67 | scene2.Render();
68 | }
69 |
70 | private void Control3_OnRender(TimeSpan delta)
71 | {
72 | scene3.Render(0.0f);
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/GLWpfControl/DXGLContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Diagnostics;
4 | using System.Runtime.InteropServices;
5 | using System.Threading;
6 | using System.Windows;
7 | using System.Windows.Interop;
8 | using OpenTK.Graphics.OpenGL;
9 | using OpenTK.Graphics.Wgl;
10 | using OpenTK.Windowing.Common;
11 | using OpenTK.Windowing.Desktop;
12 | using OpenTK.Windowing.GraphicsLibraryFramework;
13 | using OpenTK.Wpf.Interop;
14 | using WindowState = OpenTK.Windowing.Common.WindowState;
15 |
16 | namespace OpenTK.Wpf
17 | {
18 | /// This contains the DirectX and OpenGL contexts used in this control.
19 | internal sealed class DxGlContext : IDisposable
20 | {
21 | /// The DirectX context. This is basically the root of all DirectX state.
22 | public DXInterop.IDirect3D9Ex DxContext { get; }
23 |
24 | /// The DirectX device handle. This is the graphics card we're running on.
25 | public DXInterop.IDirect3DDevice9Ex DxDevice { get; }
26 |
27 | /// The OpenGL Context. This is basically the root of all OpenGL state.
28 | public IGraphicsContext GraphicsContext { get; }
29 |
30 | /// An OpenGL handle to the DirectX device. Created and used by the WGL_dx_interop extension.
31 | public IntPtr GLDeviceHandle { get; }
32 |
33 | /// The GLFW window that provides the OpenGL context. Null if a context was provided externally.
34 | private NativeWindow? GlfwWindow { get; }
35 |
36 | #if DEBUG
37 | private readonly static DebugProc DebugProcCallback = Window_DebugProc;
38 | #endif
39 |
40 | public DxGlContext(GLWpfControlSettings settings)
41 | {
42 | // if the graphics context is null, we use the shared context.
43 | if (settings.ContextToUse != null)
44 | {
45 | GraphicsContext = settings.ContextToUse;
46 | }
47 | else
48 | {
49 | NativeWindowSettings nws = NativeWindowSettings.Default;
50 | nws.StartFocused = false;
51 | nws.StartVisible = false;
52 | nws.NumberOfSamples = 0;
53 | nws.SharedContext = settings.SharedContext;
54 | // If we ask GLFW for 1.0, we should get the highest level context available with full compat.
55 | nws.APIVersion = new Version(settings.MajorVersion, settings.MinorVersion);
56 | nws.Flags = ContextFlags.Offscreen | settings.ContextFlags;
57 | // We have to ask for any compat in this case.
58 | nws.Profile = settings.Profile;
59 | nws.WindowBorder = WindowBorder.Hidden;
60 | nws.WindowState = WindowState.Minimized;
61 | GlfwWindow = new NativeWindow(nws);
62 | GraphicsContext = GlfwWindow.Context;
63 | GraphicsContext.MakeCurrent();
64 |
65 | IBindingsContext provider = settings.BindingsContext ?? new GLFWBindingsContext();
66 | Wgl.LoadBindings(provider);
67 |
68 | bool hasNVDXInterop = false;
69 | unsafe
70 | {
71 | IntPtr hwnd = GLFW.GetWin32Window(GlfwWindow.WindowPtr);
72 | IntPtr hdc = DXInterop.GetDC(hwnd);
73 | string exts = Wgl.Arb.GetExtensionsString(hdc);
74 | DXInterop.ReleaseDC(hwnd, hdc);
75 |
76 | foreach (string ext in exts.Split(' '))
77 | {
78 | if (ext == "WGL_NV_DX_interop" || ext == "NV_DX_interop")
79 | {
80 | hasNVDXInterop = true;
81 | break;
82 | }
83 | }
84 | }
85 |
86 | if (hasNVDXInterop == false)
87 | {
88 | Dispose();
89 | throw new PlatformNotSupportedException("NV_DX_interop extension is not suppored. This extensions is currently needed for GLWpfControl to work.");
90 | }
91 |
92 | #if DEBUG
93 | GL.DebugMessageCallback(DebugProcCallback, IntPtr.Zero);
94 | GL.Enable(EnableCap.DebugOutput);
95 | GL.Enable(EnableCap.DebugOutputSynchronous);
96 | #endif
97 | }
98 |
99 | DXInterop.Direct3DCreate9Ex(DXInterop.DefaultSdkVersion, out DXInterop.IDirect3D9Ex dxContext);
100 | DxContext = dxContext;
101 |
102 | PresentationParameters deviceParameters = new PresentationParameters
103 | {
104 | Windowed = 1,
105 | SwapEffect = SwapEffect.Discard,
106 | DeviceWindowHandle = IntPtr.Zero,
107 | PresentationInterval = 0,
108 | BackBufferFormat = Format.X8R8G8B8,
109 | BackBufferWidth = 1,
110 | BackBufferHeight = 1,
111 | AutoDepthStencilFormat = Format.Unknown,
112 | BackBufferCount = 1,
113 | EnableAutoDepthStencil = 0,
114 | Flags = 0,
115 | FullScreen_RefreshRateInHz = 0,
116 | MultiSampleQuality = 0,
117 | MultiSampleType = MultisampleType.D3DMULTISAMPLE_NONE,
118 | };
119 |
120 | dxContext.CreateDeviceEx(
121 | 0,
122 | DeviceType.HAL,
123 | IntPtr.Zero,
124 | CreateFlags.HardwareVertexProcessing | CreateFlags.Multithreaded | CreateFlags.PureDevice | CreateFlags.FpuPreserve,
125 | ref deviceParameters,
126 | IntPtr.Zero,
127 | out DXInterop.IDirect3DDevice9Ex dxDevice);
128 | DxDevice = dxDevice;
129 |
130 | GLDeviceHandle = Wgl.DXOpenDeviceNV(dxDevice.Handle);
131 | if (GLDeviceHandle == IntPtr.Zero)
132 | {
133 | int error = DXInterop.GetLastError();
134 | Dispose();
135 | throw new Win32Exception(error);
136 | }
137 | }
138 |
139 | public void Dispose()
140 | {
141 | int error = 0;
142 | if (GLDeviceHandle != IntPtr.Zero && Wgl.DXCloseDeviceNV(GLDeviceHandle) == false)
143 | {
144 | error = DXInterop.GetLastError();
145 | }
146 |
147 | GlfwWindow?.Dispose();
148 | if (DxDevice.Handle != IntPtr.Zero)
149 | {
150 | DxDevice.Release();
151 | }
152 | if (DxContext.Handle != IntPtr.Zero)
153 | {
154 | DxContext.Release();
155 | }
156 |
157 | if (error != 0)
158 | {
159 | throw new Win32Exception(error);
160 | }
161 | }
162 |
163 | #if DEBUG
164 | private static void Window_DebugProc(DebugSource source, DebugType type, int id, DebugSeverity severity, int length, IntPtr messagePtr, IntPtr userParam)
165 | {
166 | string message = Marshal.PtrToStringAnsi(messagePtr, length);
167 |
168 | bool showMessage = true;
169 |
170 | switch (source)
171 | {
172 | case DebugSource.DebugSourceApplication:
173 | showMessage = false;
174 | break;
175 | case DebugSource.DontCare:
176 | case DebugSource.DebugSourceApi:
177 | case DebugSource.DebugSourceWindowSystem:
178 | case DebugSource.DebugSourceShaderCompiler:
179 | case DebugSource.DebugSourceThirdParty:
180 | case DebugSource.DebugSourceOther:
181 | default:
182 | showMessage = true;
183 | break;
184 | }
185 |
186 | if (showMessage)
187 | {
188 | switch (severity)
189 | {
190 | case DebugSeverity.DontCare:
191 | Debug.Print($"[DontCare] {message}");
192 | break;
193 | case DebugSeverity.DebugSeverityNotification:
194 | //Debug.Print($"[Notification] [{source}] {message}");
195 | break;
196 | case DebugSeverity.DebugSeverityHigh:
197 | Debug.Print($"[Error] [{source}] {message}");
198 | //Debug.Break();
199 | break;
200 | case DebugSeverity.DebugSeverityMedium:
201 | Debug.Print($"[Warning] [{source}] {message}");
202 | break;
203 | case DebugSeverity.DebugSeverityLow:
204 | Debug.Print($"[Info] [{source}] {message}");
205 | break;
206 | default:
207 | Debug.Print($"[default] {message}");
208 | break;
209 | }
210 | }
211 | }
212 | #endif
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/src/GLWpfControl/GLWpfControl.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Diagnostics;
4 | using System.Globalization;
5 | using System.Windows;
6 | using System.Windows.Controls;
7 | using System.Windows.Input;
8 | using System.Windows.Media;
9 | using OpenTK.Wpf.Interop;
10 | using System.Windows.Interop;
11 | using OpenTK.Windowing.Common;
12 |
13 | namespace OpenTK.Wpf
14 | {
15 | ///
16 | /// Provides a native WPF control for OpenTK.
17 | /// To use this component, call the method.
18 | /// Bind to the event only after is called.
19 | ///
20 | /// Please do not extend this class. It has no support for that.
21 | ///
22 | public class GLWpfControl : FrameworkElement, IDisposable
23 | {
24 | static GLWpfControl()
25 | {
26 | // Default to Focusable=true.
27 | FocusableProperty.OverrideMetadata(typeof(GLWpfControl), new FrameworkPropertyMetadata(true));
28 | }
29 |
30 | ///
31 | /// Called whenever rendering should occur.
32 | /// GLWpfControl makes sure that it's OpenGL context is current when this event happens.
33 | ///
34 | public event Action? Render;
35 |
36 | ///
37 | /// Called once per frame after render. This does not synchronize with the copy to the screen.
38 | /// This is only for extremely advanced use, where a non-display out task needs to run.
39 | /// Examples of these are an async Pixel Buffer Object transfer or Transform Feedback.
40 | /// If you do not know what these are, do not use this function.
41 | ///
42 | /// GLWpfControl makes sure that it's OpenGL context is current when this event happens.
43 | ///
44 | [Obsolete("There is no difference between Render and AsyncRender. Use Render.")]
45 | public event Action? AsyncRender;
46 |
47 | ///
48 | /// Gets called after the control has finished initializing and is ready to render
49 | ///
50 | public event Action? Ready;
51 |
52 | ///
53 | /// Represents the dependency property for .
54 | ///
55 | public static readonly DependencyProperty SettingsProperty = DependencyProperty.Register(
56 | "Settings", typeof(GLWpfControlSettings), typeof(GLWpfControl));
57 |
58 | private GLWpfControlRenderer? _renderer;
59 |
60 | ///
61 | /// Indicates whether the function has been invoked.
62 | ///
63 | private bool _isStarted;
64 |
65 | ///
66 | /// Gets or sets the settings used when initializing the control.
67 | ///
68 | ///
69 | /// The settings used when initializing the control.
70 | ///
71 | public GLWpfControlSettings Settings
72 | {
73 | get { return (GLWpfControlSettings)GetValue(SettingsProperty); }
74 | set { SetValue(SettingsProperty, value); }
75 | }
76 |
77 | /// The OpenGL Framebuffer Object used internally by this component.
78 | /// Bind to this instead of the default framebuffer when using this component along with other FrameBuffers for the final pass.
79 | /// If no framebuffer is available (because this control is not visible, etc etc, then it should be 0).
80 | ///
81 | public int Framebuffer => _renderer?.GLFramebufferHandle ?? 0;
82 |
83 | ///
84 | /// If this control is rendering continuously.
85 | /// If this is false, then redrawing will only occur when is called.
86 | ///
87 | public bool RenderContinuously {
88 | get => Settings.RenderContinuously;
89 | set => Settings.RenderContinuously = value;
90 | }
91 |
92 | ///
93 | /// Pixel width of the underlying OpenGL framebuffer.
94 | /// It could differ from UIElement.RenderSize if UseDeviceDpi setting is set.
95 | /// To be used for operations related to OpenGL viewport calls (glViewport, glScissor, ...).
96 | ///
97 | public int FrameBufferWidth => _renderer?.Width ?? 0;
98 |
99 | ///
100 | /// Pixel height of the underlying OpenGL framebuffer.
101 | /// It could differ from UIElement.RenderSize if UseDeviceDpi setting is set.
102 | /// To be used for operations related to OpenGL viewport calls (glViewport, glScissor, ...).
103 | ///
104 | public int FrameBufferHeight => _renderer?.Height ?? 0;
105 |
106 | ///
107 | /// The currently used OpenGL context, or null if no OpenGL context is created.
108 | /// It is not safe to call on this context on any other thread
109 | /// than the one the is running on.
110 | ///
111 | [CLSCompliant(false)]
112 | public IGraphicsContext? Context => _renderer?.GLContext;
113 |
114 | ///
115 | /// If MSAA backbuffers can be created for this GLWpfControl.
116 | /// If false any attempt to create an MSAA framebuffer will be ignored.
117 | ///
118 | public bool SupportsMSAA => _renderer?.SupportsMSAA ?? false;
119 |
120 | private TimeSpan? _lastRenderTime = TimeSpan.FromSeconds(-1);
121 |
122 | [Obsolete("This property has no effect. See RegisterToEventsDirectly.")]
123 | public bool CanInvokeOnHandledEvents { get; set; } = true;
124 |
125 | [Obsolete("If you want to receive keyboard events without having focus you can use EventManager.RegisterClassHandler yourself. The control is by default focusable and will get key events when focused. This property will have no effect.")]
126 | public bool RegisterToEventsDirectly { get; set; } = true;
127 |
128 | ///
129 | /// Used to create a new control. Before rendering can take place, must be called.
130 | ///
131 | public GLWpfControl() : base()
132 | {
133 | }
134 |
135 | ///
136 | /// Starts the control and rendering, using the settings provided via the property.
137 | ///
138 | public void Start()
139 | {
140 | // Start with default settings if none were provided.
141 | Settings ??= new GLWpfControlSettings();
142 |
143 | Start(Settings);
144 | }
145 |
146 | ///
147 | /// Starts the control and rendering, using the settings provided.
148 | ///
149 | ///
150 | /// The settings used to construct the underlying graphics context.
151 | ///
152 | ///
153 | /// The function must only be called once for a given .
154 | ///
155 | public void Start(GLWpfControlSettings settings)
156 | {
157 | if (_isStarted) {
158 | throw new InvalidOperationException($"{nameof(Start)} must only be called once for a given {nameof(GLWpfControl)}");
159 | }
160 |
161 | _isStarted = true;
162 |
163 | Settings = settings.Clone();
164 | _renderer = new GLWpfControlRenderer(Settings);
165 | _renderer.GLRender += timeDelta => Render?.Invoke(timeDelta);
166 | _renderer.GLAsyncRender += () => AsyncRender?.Invoke();
167 | IsVisibleChanged += (_, args) => {
168 | if ((bool) args.NewValue) {
169 | CompositionTarget.Rendering += OnCompTargetRender;
170 | }
171 | else {
172 | CompositionTarget.Rendering -= OnCompTargetRender;
173 | }
174 | };
175 |
176 | Loaded += (a, b) => InvalidateVisual();
177 | Unloaded += (a, b) => OnUnloaded();
178 |
179 | Ready?.Invoke();
180 | }
181 |
182 | private void OnUnloaded()
183 | {
184 | if (_isStarted)
185 | {
186 | _renderer?.ReleaseFramebufferResources();
187 | }
188 | }
189 |
190 | ///
191 | /// Disposes the native resources allocated by this control.
192 | /// After this function has been called this control will no longer render anything
193 | /// until has been called again.
194 | ///
195 | public void Dispose()
196 | {
197 | _renderer?.Dispose();
198 | _isStarted = false;
199 | }
200 |
201 | private void OnCompTargetRender(object? sender, EventArgs e)
202 | {
203 | TimeSpan? currentRenderTime = (e as RenderingEventArgs)?.RenderingTime;
204 | if(currentRenderTime == _lastRenderTime)
205 | {
206 | // It's possible for Rendering to call back twice in the same frame
207 | // so only render when we haven't already rendered in this frame.
208 | // Reference: https://docs.microsoft.com/en-us/dotnet/desktop/wpf/advanced/walkthrough-hosting-direct3d9-content-in-wpf?view=netframeworkdesktop-4.8#to-import-direct3d9-content
209 | return;
210 | }
211 |
212 | _lastRenderTime = currentRenderTime;
213 |
214 | if (RenderContinuously) InvalidateVisual();
215 | }
216 |
217 | protected override void OnRender(DrawingContext drawingContext)
218 | {
219 | base.OnRender(drawingContext);
220 |
221 | bool isDesignMode = DesignerProperties.GetIsInDesignMode(this);
222 | if (isDesignMode) {
223 | DrawDesignTimeHelper(this, drawingContext);
224 | }
225 | else if (_renderer != null && _isStarted == true)
226 | {
227 | if (Settings != null)
228 | {
229 | double dpiScaleX = 1.0;
230 | double dpiScaleY = 1.0;
231 |
232 | if (Settings.UseDeviceDpi)
233 | {
234 | PresentationSource presentationSource = PresentationSource.FromVisual(this);
235 | // this can be null in the case of not having any visual on screen, such as a tabbed view.
236 | if (presentationSource != null)
237 | {
238 | Debug.Assert(presentationSource.CompositionTarget != null, "presentationSource.CompositionTarget != null");
239 |
240 | Matrix transformToDevice = presentationSource.CompositionTarget.TransformToDevice;
241 | dpiScaleX = transformToDevice.M11;
242 | dpiScaleY = transformToDevice.M22;
243 | }
244 | }
245 |
246 | Format format = Settings.TransparentBackground ? Format.A8R8G8B8 : Format.X8R8G8B8;
247 |
248 | MultisampleType msaaType = MultisampleType.D3DMULTISAMPLE_NONE;
249 | // 2 to 16 are valid msaa values, clamp to 16.
250 | if (Settings.Samples >= 2 && Settings.Samples <= 16)
251 | msaaType = MultisampleType.D3DMULTISAMPLE_NONE + Settings.Samples;
252 | else if (Settings.Samples > 16)
253 | msaaType = MultisampleType.D3DMULTISAMPLE_16_SAMPLES;
254 |
255 | _renderer.ReallocateFramebufferIfNeeded(RenderSize.Width, RenderSize.Height, dpiScaleX, dpiScaleY, format, msaaType);
256 | }
257 |
258 | _renderer.Render(drawingContext);
259 | }
260 | else
261 | {
262 | DrawUnstartedControlHelper(this, drawingContext);
263 | }
264 | }
265 |
266 | protected override void OnRenderSizeChanged(SizeChangedInfo info)
267 | {
268 | base.OnRenderSizeChanged(info);
269 |
270 | bool isInDesignMode = DesignerProperties.GetIsInDesignMode(this);
271 | if (isInDesignMode)
272 | {
273 | return;
274 | }
275 |
276 | if ((info.WidthChanged || info.HeightChanged) && (info.NewSize.Width > 0 && info.NewSize.Height > 0))
277 | {
278 | InvalidateVisual();
279 | }
280 | }
281 |
282 | internal static void DrawDesignTimeHelper(GLWpfControl control, DrawingContext drawingContext)
283 | {
284 | if (control.Visibility == Visibility.Visible && control.ActualWidth > 0 && control.ActualHeight > 0)
285 | {
286 | const string LabelText = "GL WPF CONTROL";
287 | double width = control.ActualWidth;
288 | double height = control.ActualHeight;
289 | double size = 1.5 * Math.Min(width, height) / LabelText.Length;
290 | Typeface tf = new Typeface("Arial");
291 | DpiScale dpi = VisualTreeHelper.GetDpi(control);
292 | FormattedText ft = new FormattedText(LabelText, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, tf, size, Brushes.White, dpi.PixelsPerDip)
293 | {
294 | TextAlignment = TextAlignment.Center
295 | };
296 | Pen redPen = new Pen(Brushes.DarkBlue, 2.0);
297 | Rect rect = new Rect(1, 1, width - 1, height - 1);
298 | drawingContext.DrawRectangle(Brushes.Black, redPen, rect);
299 | drawingContext.DrawLine(new Pen(Brushes.DarkBlue, 2.0),
300 | new Point(0.0, 0.0),
301 | new Point(control.ActualWidth, control.ActualHeight));
302 | drawingContext.DrawLine(new Pen(Brushes.DarkBlue, 2.0),
303 | new Point(control.ActualWidth, 0.0),
304 | new Point(0.0, control.ActualHeight));
305 | drawingContext.DrawText(ft, new Point(width / 2, (height - ft.Height) / 2));
306 | }
307 | }
308 |
309 | internal static void DrawUnstartedControlHelper(GLWpfControl control, DrawingContext drawingContext)
310 | {
311 | if (control.Visibility == Visibility.Visible && control.ActualWidth > 0 && control.ActualHeight > 0)
312 | {
313 | double width = control.ActualWidth;
314 | double height = control.ActualHeight;
315 | drawingContext.DrawRectangle(Brushes.Gray, null, new Rect(0, 0, width, height));
316 |
317 | if (!Debugger.IsAttached) // Do not show the message if we're not debugging
318 | {
319 | return;
320 | }
321 |
322 | const string UnstartedLabelText = "OpenGL content. Call Start() on the control to begin rendering.";
323 | const int Size = 12;
324 | Typeface tf = new Typeface("Arial");
325 |
326 | DpiScale dpi = VisualTreeHelper.GetDpi(control);
327 | FormattedText ft = new FormattedText(UnstartedLabelText, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, tf, Size, Brushes.White, dpi.PixelsPerDip)
328 | {
329 | TextAlignment = TextAlignment.Left,
330 | MaxTextWidth = width
331 | };
332 |
333 | drawingContext.DrawText(ft, new Point(0, 0));
334 | }
335 | }
336 | }
337 | }
338 |
--------------------------------------------------------------------------------
/src/GLWpfControl/GLWpfControl.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp3.1
4 | true
5 | OpenTK.Wpf
6 | false
7 | 9.0
8 | true
9 | enable
10 | bin\$(Configuration)\$(TargetFramework)
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/GLWpfControl/GLWpfControlRenderer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 | using System.Windows.Interop;
7 | using System.Windows.Media;
8 | using OpenTK.Graphics.OpenGL;
9 | using OpenTK.Graphics.Wgl;
10 | using OpenTK.Platform.Windows;
11 | using OpenTK.Windowing.Common;
12 | using OpenTK.Wpf.Interop;
13 |
14 | #nullable enable
15 |
16 | namespace OpenTK.Wpf
17 | {
18 | /// Renderer that uses DX_Interop for a fast-path.
19 | internal sealed class GLWpfControlRenderer : IDisposable
20 | {
21 | private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
22 |
23 | private readonly DxGlContext _context;
24 |
25 | public event Action? GLRender;
26 | [Obsolete("There is no difference between GLRender and GLAsyncRender. Use GLRender.")]
27 | public event Action? GLAsyncRender;
28 |
29 | /// The width of this buffer in pixels.
30 | public int FramebufferWidth { get; private set; }
31 |
32 | /// The height of this buffer in pixels.
33 | public int FramebufferHeight { get; private set; }
34 |
35 | /// The DirectX multisample type.
36 | public MultisampleType MultisampleType { get; private set; }
37 |
38 | /// The OpenGL Framebuffer width
39 | public int Width => D3dImage != null ? FramebufferWidth : 0;
40 |
41 | /// The OpenGL Framebuffer height
42 | public int Height => D3dImage != null ? FramebufferHeight : 0;
43 |
44 | public IGraphicsContext? GLContext => _context.GraphicsContext;
45 |
46 | public D3DImage? D3dImage { get; private set; }
47 |
48 | public DXInterop.IDirect3DSurface9 DxColorRenderTarget { get; private set; }
49 | public DXInterop.IDirect3DSurface9 DxDepthStencilRenderTarget { get; private set; }
50 |
51 | public IntPtr DxInteropColorRenderTargetRegisteredHandle { get; private set; }
52 | public IntPtr DxInteropDepthStencilRenderTargetRegisteredHandle { get; private set; }
53 |
54 | /// The OpenGL framebuffer handle.
55 | public int GLFramebufferHandle { get; private set; }
56 | private int GLSharedColorRenderbufferHandle { get; set; }
57 | private int GLSharedDepthRenderRenderbufferHandle { get; set; }
58 |
59 | public TranslateTransform TranslateTransform { get; private set; }
60 | public ScaleTransform FlipYTransform { get; private set; }
61 |
62 | private TimeSpan _lastFrameStamp;
63 |
64 | public readonly bool SupportsMSAA;
65 |
66 | public GLWpfControlRenderer(GLWpfControlSettings settings)
67 | {
68 | _context = new DxGlContext(settings);
69 | // Placeholder transforms.
70 | TranslateTransform = new TranslateTransform(0, 0);
71 | FlipYTransform = new ScaleTransform(1, 1);
72 |
73 | SupportsMSAA = SupportsMSAATest();
74 | }
75 |
76 | public bool SupportsMSAATest()
77 | {
78 | // A test to see whether we can create multisample render targets without
79 | // getting an exception...
80 | try
81 | {
82 | IntPtr dxColorRenderTargetShareHandle = IntPtr.Zero;
83 | _context.DxDevice.CreateRenderTarget(
84 | 128,
85 | 128,
86 | Format.X8R8G8B8,
87 | MultisampleType.D3DMULTISAMPLE_2_SAMPLES,
88 | 0,
89 | false,
90 | out DXInterop.IDirect3DSurface9 dxColorRenderTarget,
91 | ref dxColorRenderTargetShareHandle);
92 |
93 | IntPtr dxDepthStencilRenderTargetShareHandle = IntPtr.Zero;
94 | _context.DxDevice.CreateDepthStencilSurface(
95 | FramebufferWidth,
96 | FramebufferHeight,
97 | Format.D24S8,
98 | MultisampleType.D3DMULTISAMPLE_2_SAMPLES,
99 | 0,
100 | false,
101 | out DXInterop.IDirect3DSurface9 dxDepthStencilRenderTarget,
102 | ref dxDepthStencilRenderTargetShareHandle);
103 | DxDepthStencilRenderTarget = dxDepthStencilRenderTarget;
104 |
105 | dxColorRenderTarget.Release();
106 | dxDepthStencilRenderTarget.Release();
107 |
108 | return true;
109 | }
110 | catch(COMException)
111 | {
112 | Trace.TraceWarning("GLWpfControl was unable to create an MSAA framebuffer on this computer.");
113 | return false;
114 | }
115 | }
116 |
117 | public void ReallocateFramebufferIfNeeded(double width, double height, double dpiScaleX, double dpiScaleY, Format format, MultisampleType msaaType)
118 | {
119 | int newWidth = (int)Math.Ceiling(width * dpiScaleX);
120 | int newHeight = (int)Math.Ceiling(height * dpiScaleY);
121 |
122 | // Disable MSAA if we've determined we don't support it.
123 | // It's better to create a normal backbuffer instead of crashing.
124 | if (SupportsMSAA == false)
125 | {
126 | msaaType = MultisampleType.D3DMULTISAMPLE_NONE;
127 | }
128 |
129 | // FIXME: It seems we can't use this function to detect if MSAA will work with NV_DX_interop or not...
130 | int result = _context.DxContext.CheckDeviceMultiSampleType(0, DeviceType.HAL, format, true, msaaType, out uint qualityLevels);
131 |
132 | if (D3dImage == null || FramebufferWidth != newWidth || FramebufferHeight != newHeight || MultisampleType != msaaType)
133 | {
134 | ReleaseFramebufferResources();
135 |
136 | if (width > 0 && height > 0)
137 | {
138 | FramebufferWidth = newWidth;
139 | FramebufferHeight = newHeight;
140 | MultisampleType = msaaType;
141 |
142 | IntPtr dxColorRenderTargetShareHandle = IntPtr.Zero;
143 | _context.DxDevice.CreateRenderTarget(
144 | FramebufferWidth,
145 | FramebufferHeight,
146 | format,
147 | msaaType,
148 | 0,
149 | false,
150 | out DXInterop.IDirect3DSurface9 dxColorRenderTarget,
151 | ref dxColorRenderTargetShareHandle);
152 | DxColorRenderTarget = dxColorRenderTarget;
153 |
154 | bool success;
155 | success = Wgl.DXSetResourceShareHandleNV(DxColorRenderTarget.Handle, dxColorRenderTargetShareHandle);
156 | if (success == false)
157 | {
158 | Debug.WriteLine("Failed to set resource share handle for color render target.");
159 | }
160 |
161 | IntPtr dxDepthStencilRenderTargetShareHandle = IntPtr.Zero;
162 | _context.DxDevice.CreateDepthStencilSurface(
163 | FramebufferWidth,
164 | FramebufferHeight,
165 | Format.D24S8,
166 | msaaType,
167 | 0,
168 | false,
169 | out DXInterop.IDirect3DSurface9 dxDepthStencilRenderTarget,
170 | ref dxDepthStencilRenderTargetShareHandle);
171 | DxDepthStencilRenderTarget = dxDepthStencilRenderTarget;
172 |
173 | success = Wgl.DXSetResourceShareHandleNV(dxDepthStencilRenderTarget.Handle, dxDepthStencilRenderTargetShareHandle);
174 | if (success == false)
175 | {
176 | Debug.WriteLine("Failed to set resource share handle for depth stencil render target.");
177 | }
178 |
179 | #if DEBUG
180 | {
181 | DxColorRenderTarget.GetDesc(out DXInterop.D3DSURFACE_DESC desc);
182 |
183 | Debug.WriteLine($"Render target desc: {desc.Format}, {desc.Type}, {desc.Usage}, {desc.Pool}, {desc.MultiSampleType}, {desc.MultiSampleQuality}, {desc.Width}, {desc.Height}");
184 | }
185 |
186 | {
187 | DxDepthStencilRenderTarget.GetDesc(out DXInterop.D3DSURFACE_DESC desc);
188 |
189 | Debug.WriteLine($"Render target desc: {desc.Format}, {desc.Type}, {desc.Usage}, {desc.Pool}, {desc.MultiSampleType}, {desc.MultiSampleQuality}, {desc.Width}, {desc.Height}");
190 | }
191 | #endif
192 |
193 | GLFramebufferHandle = GL.GenFramebuffer();
194 |
195 | TextureTarget colorTextureTarget = msaaType == MultisampleType.D3DMULTISAMPLE_NONE ? TextureTarget.Texture2D : TextureTarget.Texture2DMultisample;
196 |
197 | GLSharedColorRenderbufferHandle = GL.GenRenderbuffer();
198 | DxInteropColorRenderTargetRegisteredHandle = Wgl.DXRegisterObjectNV(
199 | _context.GLDeviceHandle,
200 | DxColorRenderTarget.Handle,
201 | (uint)GLSharedColorRenderbufferHandle,
202 | (uint)RenderbufferTarget.Renderbuffer,
203 | WGL_NV_DX_interop.AccessReadWrite);
204 | if (DxInteropColorRenderTargetRegisteredHandle == IntPtr.Zero)
205 | {
206 | Debug.WriteLine($"Could not register color render target. 0x{DXInterop.GetLastError():X8}");
207 | }
208 |
209 | GLSharedDepthRenderRenderbufferHandle = GL.GenRenderbuffer();
210 | DxInteropDepthStencilRenderTargetRegisteredHandle = Wgl.DXRegisterObjectNV(
211 | _context.GLDeviceHandle,
212 | DxDepthStencilRenderTarget.Handle,
213 | (uint)GLSharedDepthRenderRenderbufferHandle,
214 | (uint)RenderbufferTarget.Renderbuffer,
215 | WGL_NV_DX_interop.AccessReadWrite);
216 | if (DxInteropDepthStencilRenderTargetRegisteredHandle == IntPtr.Zero)
217 | {
218 | Debug.WriteLine($"Could not register depth stencil render target. 0x{DXInterop.GetLastError():X8}");
219 | }
220 |
221 | GL.BindFramebuffer(FramebufferTarget.Framebuffer, GLFramebufferHandle);
222 |
223 | GL.FramebufferRenderbuffer(
224 | FramebufferTarget.Framebuffer,
225 | FramebufferAttachment.ColorAttachment0,
226 | RenderbufferTarget.Renderbuffer,
227 | GLSharedColorRenderbufferHandle);
228 |
229 | // FIXME: If we have a combined format, maybe set both at the same time?
230 | GL.FramebufferRenderbuffer(
231 | FramebufferTarget.Framebuffer,
232 | FramebufferAttachment.DepthAttachment,
233 | RenderbufferTarget.Renderbuffer,
234 | GLSharedDepthRenderRenderbufferHandle);
235 |
236 | GL.FramebufferRenderbuffer(
237 | FramebufferTarget.Framebuffer,
238 | FramebufferAttachment.StencilAttachment,
239 | RenderbufferTarget.Renderbuffer,
240 | GLSharedDepthRenderRenderbufferHandle);
241 |
242 | // FIXME: This will report unsupported but it will not do that in Render()...?
243 | FramebufferErrorCode status = GL.CheckFramebufferStatus(FramebufferTarget.DrawFramebuffer);
244 | if (status != FramebufferErrorCode.FramebufferComplete)
245 | {
246 | Debug.WriteLine($"Framebuffer is not complete: {status}");
247 | }
248 |
249 | GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
250 |
251 | D3dImage = new D3DImage(96.0 * dpiScaleX, 96.0 * dpiScaleY);
252 |
253 | TranslateTransform = new TranslateTransform(0, height);
254 | FlipYTransform = new ScaleTransform(1, -1);
255 | }
256 | }
257 | }
258 |
259 | ///
260 | /// Releases all resources related to the framebuffer.
261 | ///
262 | public void ReleaseFramebufferResources()
263 | {
264 | _context.GraphicsContext.MakeCurrent();
265 |
266 | if (D3dImage != null)
267 | {
268 | Wgl.DXUnregisterObjectNV(_context.GLDeviceHandle, DxInteropColorRenderTargetRegisteredHandle);
269 | Wgl.DXUnregisterObjectNV(_context.GLDeviceHandle, DxInteropDepthStencilRenderTargetRegisteredHandle);
270 | DxColorRenderTarget.Release();
271 | DxDepthStencilRenderTarget.Release();
272 | GL.DeleteFramebuffer(GLFramebufferHandle);
273 | GL.DeleteRenderbuffer(GLSharedDepthRenderRenderbufferHandle);
274 | GL.DeleteRenderbuffer(GLSharedColorRenderbufferHandle);
275 | }
276 | D3dImage = null;
277 | }
278 |
279 | public void Render(DrawingContext drawingContext)
280 | {
281 | if (D3dImage == null)
282 | {
283 | return;
284 | }
285 |
286 | _context.GraphicsContext.MakeCurrent();
287 |
288 | TimeSpan curFrameStamp = _stopwatch.Elapsed;
289 | TimeSpan deltaT = curFrameStamp - _lastFrameStamp;
290 | _lastFrameStamp = curFrameStamp;
291 |
292 | // Lock the interop object, DX calls to the framebuffer are no longer valid
293 | D3dImage.Lock();
294 | D3dImage.SetBackBuffer(System.Windows.Interop.D3DResourceType.IDirect3DSurface9, DxColorRenderTarget.Handle, true);
295 | bool success = Wgl.DXLockObjectsNV(_context.GLDeviceHandle, 2, new[] { DxInteropColorRenderTargetRegisteredHandle, DxInteropDepthStencilRenderTargetRegisteredHandle });
296 | if (success == false)
297 | {
298 | Debug.WriteLine("Failed to lock objects!");
299 | }
300 | GL.BindFramebuffer(FramebufferTarget.Framebuffer, GLFramebufferHandle);
301 | GL.Viewport(0, 0, FramebufferWidth, FramebufferHeight);
302 |
303 | GLRender?.Invoke(deltaT);
304 | GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
305 | GLAsyncRender?.Invoke();
306 |
307 | // Unlock the interop object, this acts as a synchronization point. OpenGL draws to the framebuffer are no longer valid.
308 | success = Wgl.DXUnlockObjectsNV(_context.GLDeviceHandle, 2, new[] { DxInteropColorRenderTargetRegisteredHandle, DxInteropDepthStencilRenderTargetRegisteredHandle });
309 | if (success == false)
310 | {
311 | Debug.WriteLine("Failed to unlock objects!");
312 | }
313 |
314 | D3dImage.AddDirtyRect(new Int32Rect(0, 0, FramebufferWidth, FramebufferHeight));
315 | D3dImage.Unlock();
316 |
317 | // Transforms are applied in reverse order
318 | // Apply translation to the image on the Y axis by the height. This assures that in the next step, where we apply a negative scale the image is still inside of the window
319 | drawingContext.PushTransform(TranslateTransform);
320 | // Apply a scale where the Y axis is -1. This will flip the image vertically.
321 | drawingContext.PushTransform(FlipYTransform);
322 |
323 | // Dpi scaled rectangle from the image
324 | Rect rect = new Rect(0, 0, D3dImage.Width, D3dImage.Height);
325 | // Draw the image source
326 | drawingContext.DrawImage(D3dImage, rect);
327 |
328 | // Remove the scale transform and the translation transform
329 | drawingContext.Pop();
330 | drawingContext.Pop();
331 | }
332 |
333 | public void Dispose()
334 | {
335 | ReleaseFramebufferResources();
336 | _context.Dispose();
337 | }
338 | }
339 | }
340 |
--------------------------------------------------------------------------------
/src/GLWpfControl/GLWpfControlSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.Contracts;
3 | using OpenTK.Windowing.Common;
4 | using OpenTK.Windowing.Desktop;
5 |
6 | namespace OpenTK.Wpf {
7 | public sealed class GLWpfControlSettings
8 | {
9 | ///
10 | /// If the render event is fired continuously whenever required.
11 | /// Disable this if you want manual control over when the rendered surface is updated.
12 | ///
13 | public bool RenderContinuously { get; set; } = true;
14 |
15 | ///
16 | /// If this is set to false, the control will render without any DPI scaling.
17 | /// This will result in higher performance and a worse image quality on systems with >100% DPI settings, such as 'Retina' laptop screens with 4K UHD at small sizes.
18 | /// This setting may be useful to get extra performance on mobile platforms.
19 | ///
20 | public bool UseDeviceDpi { get; set; } = true;
21 |
22 | ///
23 | /// If this parameter is set to true, the alpha channel of the color passed to the function GL.ClearColor
24 | /// will determine the level of transparency of this control
25 | ///
26 | public bool TransparentBackground { get; set; } = false;
27 |
28 | ///
29 | /// May be null. If defined, an external context will be used, of which the caller is responsible
30 | /// for managing the lifetime and disposal of.
31 | /// The management of the context sent to the becomes the responsibility of the .
32 | /// Trying to call on this context on some other thread might lead to uninteded consequences.
33 | ///
34 | [CLSCompliant(false)]
35 | public IGraphicsContext? ContextToUse { get; set; }
36 |
37 | ///
38 | /// A optional context for context sharing.
39 | ///
40 | [CLSCompliant(false)]
41 | public IGLFWGraphicsContext? SharedContext { get; set; }
42 |
43 | ///
44 | /// May be null. If so, default bindings context will be used.
45 | ///
46 | [CLSCompliant(false)]
47 | public IBindingsContext? BindingsContext { get; set; }
48 |
49 | ///
50 | /// The OpenGL context flags to use. Same as .
51 | ///
52 | [CLSCompliant(false)]
53 | [Obsolete("Use ContextFlags instead.")]
54 | public ContextFlags GraphicsContextFlags { get => ContextFlags; set => ContextFlags = value; }
55 |
56 | ///
57 | /// The OpenGL context flags to use. will always be set for DirectX interop purposes.
58 | ///
59 | [CLSCompliant(false)]
60 | public ContextFlags ContextFlags { get; set; } = ContextFlags.Default;
61 |
62 | ///
63 | /// The OpenGL profile to use. Same as .
64 | ///
65 | [CLSCompliant(false)]
66 | [Obsolete("Use Profile instead.")]
67 | public ContextProfile GraphicsProfile { get => Profile; set => Profile = value; }
68 |
69 | ///
70 | /// The OpenGL profile to use.
71 | ///
72 | [CLSCompliant(false)]
73 | public ContextProfile Profile { get; set; } = ContextProfile.Any;
74 |
75 | /// The major OpenGL version number.
76 | public int MajorVersion { get; set; } = 3;
77 | /// The minor OpenGL version number.
78 | public int MinorVersion { get; set; } = 3;
79 |
80 | ///
81 | /// How many MSAA samples should the framebuffer have in the range [0, 16]. 0 and 1 result in no MSAA.
82 | ///
83 | public int Samples { get; set; } = 0;
84 |
85 | /// If we are using an external context for the control.
86 | public bool IsUsingExternalContext => ContextToUse != null;
87 |
88 | ///
89 | /// Makes a shallow clone of this object.
90 | ///
91 | /// The cloned object.
92 | public GLWpfControlSettings Clone()
93 | {
94 | return (GLWpfControlSettings)this.MemberwiseClone();
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/GLWpfControl/Interop/DXInterop.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace OpenTK.Wpf.Interop
5 | {
6 | internal static class DXInterop
7 | {
8 | // We disable this so we can do struct _VTable
9 | #pragma warning disable IDE1006 // Naming Styles
10 |
11 | public const uint DefaultSdkVersion = 32;
12 |
13 | [DllImport("Kernel32.dll")]
14 | public static extern int GetLastError();
15 |
16 | [DllImport("User32.dll")]
17 | public static extern IntPtr /* HDC */ GetDC(IntPtr /* HWND */ hWnd);
18 |
19 | [DllImport("User32.dll")]
20 | public static extern int ReleaseDC(IntPtr /* HWND */ hWnd, IntPtr /* HDC */ hDC);
21 |
22 | public static void Direct3DCreate9Ex(uint SdkVersion, out IDirect3D9Ex context)
23 | {
24 | int result = Direct3DCreate9Ex(SdkVersion, out context);
25 | CheckHResult(result);
26 |
27 | [DllImport("d3d9.dll")]
28 | static extern int Direct3DCreate9Ex(uint SdkVersion, out IDirect3D9Ex ctx);
29 | }
30 |
31 | private delegate uint NativeGetAdapterCount(IDirect3D9Ex contextHandle);
32 | private delegate int NativeCheckDeviceMultiSampleType(IDirect3D9Ex contextHandle, uint Adapter, DeviceType DeviceType, Format SurfaceFormat, bool Windowed, MultisampleType MultiSampleType, out uint pQualityLevels);
33 | private delegate int NativeCreateDeviceEx(IDirect3D9Ex contextHandle, int adapter, DeviceType deviceType, IntPtr focusWindowHandle, CreateFlags behaviorFlags, ref PresentationParameters presentationParameters, IntPtr fullscreenDisplayMode, out IDirect3DDevice9Ex deviceHandle);
34 | private delegate int NativeCreateRenderTarget(IDirect3DDevice9Ex deviceHandle, int width, int height, Format format, MultisampleType multisample, int multisampleQuality, bool lockable, out IDirect3DSurface9 surfaceHandle, ref IntPtr sharedHandle);
35 | private delegate int NativeCreateDepthStencilSurface(IDirect3DDevice9Ex deviceHandle, int width, int height, Format format, MultisampleType multisample, int multisampleQuality, bool discard, out IDirect3DSurface9 surfaceHandle, ref IntPtr sharedHandle);
36 | private delegate uint NativeRelease(IntPtr resourceHandle);
37 |
38 | private delegate uint NativeDirect3DSurface9_GetDesc(IDirect3DSurface9 surfaceHandle, out D3DSURFACE_DESC pDesc);
39 |
40 | public static void CheckHResult(int hresult)
41 | {
42 | Marshal.ThrowExceptionForHR(hresult);
43 | }
44 |
45 | public static readonly Guid IID_IDirect3D9Ex = new Guid(0x02177241, 0x69FC, 0x400C, 0x8F, 0xF1, 0x93, 0xA4, 0x4D, 0xF6, 0x86, 0x1D);
46 |
47 | public unsafe struct IUnknown
48 | {
49 | #pragma warning disable CS0649
50 | public struct _VTable
51 | {
52 | public IntPtr QueryInterface;
53 | public IntPtr AddRef;
54 | public IntPtr Release;
55 | }
56 | #pragma warning restore CS0649
57 |
58 | public _VTable** VTable;
59 |
60 | public readonly IntPtr Handle => (IntPtr)VTable;
61 |
62 | // FIXME: This is only temporary while we have COM objects refered to by IntPtr
63 | public static explicit operator IUnknown(IntPtr ptr) => new IUnknown() { VTable = (_VTable**)ptr };
64 |
65 | public uint Release()
66 | {
67 | NativeRelease method = Marshal.GetDelegateForFunctionPointer((*VTable)->Release);
68 | // FIXME: Figure out how we want to reference things
69 | return method((IntPtr)VTable);
70 | }
71 | }
72 |
73 | public unsafe struct IDirect3D9Ex
74 | {
75 | #pragma warning disable CS0649
76 | public struct _VTable
77 | {
78 | public IntPtr QueryInterface;
79 | public IntPtr AddRef;
80 | public IntPtr Release;
81 | public IntPtr RegisterSoftwareDevice;
82 | public IntPtr GetAdapterCount;
83 | public IntPtr GetAdapterIdentifier;
84 | public IntPtr GetAdapterModeCount;
85 | public IntPtr EnumAdapterModes;
86 | public IntPtr GetAdapterDisplayMode;
87 | public IntPtr CheckDeviceType;
88 | public IntPtr CheckDeviceFormat;
89 | public IntPtr CheckDeviceMultiSampleType;
90 | public IntPtr CheckDepthStencilMatch;
91 | public IntPtr CheckDeviceFormatConversion;
92 | public IntPtr GetDeviceCaps;
93 | public IntPtr GetAdapterMonitor;
94 | public IntPtr CreateDevice;
95 | public IntPtr GetAdapterModeCountEx;
96 | public IntPtr EnumAdapterModesEx;
97 | public IntPtr GetAdapterDisplayModeEx;
98 | public IntPtr CreateDeviceEx;
99 | public IntPtr GetAdapterLUID;
100 | }
101 |
102 | public _VTable** VTable;
103 | #pragma warning restore CS0649
104 |
105 | public readonly IntPtr Handle => (IntPtr)VTable;
106 |
107 | public static explicit operator IDirect3D9Ex(IntPtr ptr) => new IDirect3D9Ex() { VTable = (_VTable**)ptr };
108 |
109 | public uint Release()
110 | {
111 | NativeRelease method = Marshal.GetDelegateForFunctionPointer((*VTable)->Release);
112 | // FIXME: Figure out how we want to reference things
113 | return method((IntPtr)VTable);
114 | }
115 |
116 | public int CheckDeviceMultiSampleType(uint Adapter, DeviceType DeviceType, Format SurfaceFormat, bool Windowed, MultisampleType MultiSampleType, out uint pQualityLevels)
117 | {
118 | NativeCheckDeviceMultiSampleType method = Marshal.GetDelegateForFunctionPointer((*VTable)->CheckDeviceMultiSampleType);
119 |
120 | int result = method(this, Adapter, DeviceType, SurfaceFormat, Windowed, MultiSampleType, out pQualityLevels);
121 |
122 | return result;
123 | }
124 |
125 | public uint GetAdapterCount()
126 | {
127 | NativeGetAdapterCount method = Marshal.GetDelegateForFunctionPointer((*VTable)->GetAdapterCount);
128 |
129 | return method(this);
130 | }
131 |
132 | public void CreateDeviceEx(int adapter, DeviceType deviceType, IntPtr focusWindowHandle, CreateFlags behaviorFlags, ref PresentationParameters presentationParameters, IntPtr fullscreenDisplayMode, out IDirect3DDevice9Ex deviceHandle)
133 | {
134 | NativeCreateDeviceEx method = Marshal.GetDelegateForFunctionPointer((*VTable)->CreateDeviceEx);
135 |
136 | int result = method(this, adapter, deviceType, focusWindowHandle, behaviorFlags, ref presentationParameters, fullscreenDisplayMode, out deviceHandle);
137 |
138 | CheckHResult(result);
139 | }
140 | }
141 |
142 | public unsafe struct IDirect3DDevice9Ex
143 | {
144 | #pragma warning disable CS0649
145 | public struct _VTable
146 | {
147 | /*** IUnknown methods ***/
148 | public IntPtr QueryInterface;
149 | public IntPtr AddRef;
150 | public IntPtr Release;
151 |
152 | /*** IDirect3DDevice9 methods ***/
153 | public IntPtr TestCooperativeLevel;
154 | public IntPtr GetAvailableTextureMem;
155 | public IntPtr EvictManagedResources;
156 | public IntPtr GetDirect3D;
157 | public IntPtr GetDeviceCaps;
158 | public IntPtr GetDisplayMode;
159 | public IntPtr GetCreationParameters;
160 | public IntPtr SetCursorProperties;
161 | public IntPtr SetCursorPosition;
162 | public IntPtr ShowCursor;
163 | public IntPtr CreateAdditionalSwapChain;
164 | public IntPtr GetSwapChain;
165 | public IntPtr GetNumberOfSwapChains;
166 | public IntPtr Reset;
167 | public IntPtr Present;
168 | public IntPtr GetBackBuffer;
169 | public IntPtr GetRasterStatus;
170 | public IntPtr SetDialogBoxMode;
171 | public IntPtr SetGammaRamp;
172 | public IntPtr GetGammaRamp;
173 | public IntPtr CreateTexture;
174 | public IntPtr CreateVolumeTexture;
175 | public IntPtr CreateCubeTexture;
176 | public IntPtr CreateVertexBuffer;
177 | public IntPtr CreateIndexBuffer;
178 | public IntPtr CreateRenderTarget;
179 | public IntPtr CreateDepthStencilSurface;
180 | public IntPtr UpdateSurface;
181 | public IntPtr UpdateTexture;
182 | public IntPtr GetRenderTargetData;
183 | public IntPtr GetFrontBufferData;
184 | public IntPtr StretchRect;
185 | public IntPtr ColorFill;
186 | public IntPtr CreateOffscreenPlainSurface;
187 | public IntPtr SetRenderTarget;
188 | public IntPtr GetRenderTarget;
189 | public IntPtr SetDepthStencilSurface;
190 | public IntPtr GetDepthStencilSurface;
191 | public IntPtr BeginScene;
192 | public IntPtr EndScene;
193 | public IntPtr Clear;
194 | public IntPtr SetTransform;
195 | public IntPtr GetTransform;
196 | public IntPtr MultiplyTransform;
197 | public IntPtr SetViewport;
198 | public IntPtr GetViewport;
199 | public IntPtr SetMaterial;
200 | public IntPtr GetMaterial;
201 | public IntPtr SetLight;
202 | public IntPtr GetLight;
203 | public IntPtr LightEnable;
204 | public IntPtr GetLightEnable;
205 | public IntPtr SetClipPlane;
206 | public IntPtr GetClipPlane;
207 | public IntPtr SetRenderState;
208 | public IntPtr GetRenderState;
209 | public IntPtr CreateStateBlock;
210 | public IntPtr BeginStateBlock;
211 | public IntPtr EndStateBlock;
212 | public IntPtr SetClipStatus;
213 | public IntPtr GetClipStatus;
214 | public IntPtr GetTexture;
215 | public IntPtr SetTexture;
216 | public IntPtr GetTextureStageState;
217 | public IntPtr SetTextureStageState;
218 | public IntPtr GetSamplerState;
219 | public IntPtr SetSamplerState;
220 | public IntPtr ValidateDevice;
221 | public IntPtr SetPaletteEntries;
222 | public IntPtr GetPaletteEntries;
223 | public IntPtr SetCurrentTexturePalette;
224 | public IntPtr GetCurrentTexturePalette;
225 | public IntPtr SetScissorRect;
226 | public IntPtr GetScissorRect;
227 | public IntPtr SetSoftwareVertexProcessing;
228 | public IntPtr GetSoftwareVertexProcessing;
229 | public IntPtr SetNPatchMode;
230 | public IntPtr GetNPatchMode;
231 | public IntPtr DrawPrimitive;
232 | public IntPtr DrawIndexedPrimitive;
233 | public IntPtr DrawPrimitiveUP;
234 | public IntPtr DrawIndexedPrimitiveUP;
235 | public IntPtr ProcessVertices;
236 | public IntPtr CreateVertexDeclaration;
237 | public IntPtr SetVertexDeclaration;
238 | public IntPtr GetVertexDeclaration;
239 | public IntPtr SetFVF;
240 | public IntPtr GetFVF;
241 | public IntPtr CreateVertexShader;
242 | public IntPtr SetVertexShader;
243 | public IntPtr GetVertexShader;
244 | public IntPtr SetVertexShaderConstantF;
245 | public IntPtr GetVertexShaderConstantF;
246 | public IntPtr SetVertexShaderConstantI;
247 | public IntPtr GetVertexShaderConstantI;
248 | public IntPtr SetVertexShaderConstantB;
249 | public IntPtr GetVertexShaderConstantB;
250 | public IntPtr SetStreamSource;
251 | public IntPtr GetStreamSource;
252 | public IntPtr SetStreamSourceFreq;
253 | public IntPtr GetStreamSourceFreq;
254 | public IntPtr SetIndices;
255 | public IntPtr GetIndices;
256 | public IntPtr CreatePixelShader;
257 | public IntPtr SetPixelShader;
258 | public IntPtr GetPixelShader;
259 | public IntPtr SetPixelShaderConstantF;
260 | public IntPtr GetPixelShaderConstantF;
261 | public IntPtr SetPixelShaderConstantI;
262 | public IntPtr GetPixelShaderConstantI;
263 | public IntPtr SetPixelShaderConstantB;
264 | public IntPtr GetPixelShaderConstantB;
265 | public IntPtr DrawRectPatch;
266 | public IntPtr DrawTriPatch;
267 | public IntPtr DeletePatch;
268 | public IntPtr CreateQuery;
269 | public IntPtr SetConvolutionMonoKernel;
270 | public IntPtr ComposeRects;
271 | public IntPtr PresentEx;
272 | public IntPtr GetGPUThreadPriority;
273 | public IntPtr SetGPUThreadPriority;
274 | public IntPtr WaitForVBlank;
275 | public IntPtr CheckResourceResidency;
276 | public IntPtr SetMaximumFrameLatency;
277 | public IntPtr GetMaximumFrameLatency;
278 | public IntPtr CheckDeviceState;
279 | public IntPtr CreateRenderTargetEx;
280 | public IntPtr CreateOffscreenPlainSurfaceEx;
281 | public IntPtr CreateDepthStencilSurfaceEx;
282 | public IntPtr ResetEx;
283 | public IntPtr GetDisplayModeEx;
284 | }
285 |
286 | public _VTable** VTable;
287 | #pragma warning restore CS0649
288 |
289 | public readonly IntPtr Handle => (IntPtr)VTable;
290 |
291 | public uint Release()
292 | {
293 | NativeRelease method = Marshal.GetDelegateForFunctionPointer((*VTable)->Release);
294 | // FIXME: Figure out how we want to reference things
295 | return method((IntPtr)VTable);
296 | }
297 |
298 | public void CreateRenderTarget(int width, int height, Format format, MultisampleType multisample, int multisampleQuality, bool lockable, out IDirect3DSurface9 surfaceHandle, ref IntPtr sharedHandle)
299 | {
300 | NativeCreateRenderTarget method = Marshal.GetDelegateForFunctionPointer((*VTable)->CreateRenderTarget);
301 |
302 | int result = method(this, width, height, format, multisample, multisampleQuality, lockable, out surfaceHandle, ref sharedHandle);
303 |
304 | CheckHResult(result);
305 | }
306 |
307 | public void CreateDepthStencilSurface(int width, int height, Format format, MultisampleType multisample, int multisampleQuality, bool discard, out IDirect3DSurface9 surfaceHandle, ref IntPtr sharedHandle)
308 | {
309 | NativeCreateDepthStencilSurface method = Marshal.GetDelegateForFunctionPointer((*VTable)->CreateDepthStencilSurface);
310 |
311 | int result = method(this, width, height, format, multisample, multisampleQuality, discard, out surfaceHandle, ref sharedHandle);
312 |
313 | CheckHResult(result);
314 | }
315 | }
316 |
317 | #pragma warning disable CS0649
318 | public struct D3DSURFACE_DESC
319 | {
320 | public D3DFormat Format;
321 | public D3DResourceType Type;
322 | public D3DUsage Usage;
323 | public D3DPool Pool;
324 | public MultisampleType MultiSampleType;
325 | public uint MultiSampleQuality;
326 | public uint Width;
327 | public uint Height;
328 | }
329 | #pragma warning restore CS0649
330 |
331 | public unsafe struct IDirect3DSurface9
332 | {
333 | #pragma warning disable CS0649
334 | public struct _VTable
335 | {
336 | /*** IUnknown methods ***/
337 | public IntPtr QueryInterface;
338 | public IntPtr AddRef;
339 | public IntPtr Release;
340 |
341 | /*** IDirect3DResource9 methods ***/
342 | public IntPtr GetDevice;
343 | public IntPtr SetPrivateData;
344 | public IntPtr GetPrivateData;
345 | public IntPtr FreePrivateData;
346 | public IntPtr SetPriority;
347 | public IntPtr GetPriority;
348 | public IntPtr PreLoad;
349 | public new IntPtr GetType;
350 | public IntPtr GetContainer;
351 | public IntPtr GetDesc;
352 | public IntPtr LockRect;
353 | public IntPtr UnlockRect;
354 | public IntPtr GetDC;
355 | public IntPtr ReleaseDC;
356 | }
357 |
358 | public _VTable** VTable;
359 | #pragma warning restore CS0649
360 |
361 | public readonly IntPtr Handle => (IntPtr)VTable;
362 |
363 | public uint GetDesc(out D3DSURFACE_DESC pDesc)
364 | {
365 | NativeDirect3DSurface9_GetDesc method = Marshal.GetDelegateForFunctionPointer((*VTable)->GetDesc);
366 |
367 | return method(this, out pDesc);
368 | }
369 |
370 | public uint Release()
371 | {
372 | NativeRelease method = Marshal.GetDelegateForFunctionPointer((*VTable)->Release);
373 | // FIXME: Figure out how we want to reference things
374 | return method((IntPtr)VTable);
375 | }
376 | }
377 | }
378 | }
379 |
--------------------------------------------------------------------------------
/src/GLWpfControl/Interop/Enums.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OpenTK.Wpf.Interop
4 | {
5 | [Flags]
6 | internal enum CreateFlags : uint
7 | {
8 | FpuPreserve = 2,
9 | Multithreaded = 4,
10 | PureDevice = 16,
11 | HardwareVertexProcessing = 64,
12 | }
13 |
14 | internal enum DeviceType
15 | {
16 | ///
17 | /// Hardware rasterization. Shading is done with software, hardware, or mixed transform and lighting.
18 | ///
19 | HAL = 1,
20 | }
21 |
22 | internal enum D3DFormat
23 | {
24 | D3DFMT_UNKNOWN = 0,
25 |
26 | D3DFMT_R8G8B8 = 20,
27 | D3DFMT_A8R8G8B8 = 21,
28 | D3DFMT_X8R8G8B8 = 22,
29 | D3DFMT_R5G6B5 = 23,
30 | D3DFMT_X1R5G5B5 = 24,
31 | D3DFMT_A1R5G5B5 = 25,
32 | D3DFMT_A4R4G4B4 = 26,
33 | D3DFMT_R3G3B2 = 27,
34 | D3DFMT_A8 = 28,
35 | D3DFMT_A8R3G3B2 = 29,
36 | D3DFMT_X4R4G4B4 = 30,
37 | D3DFMT_A2B10G10R10 = 31,
38 | D3DFMT_A8B8G8R8 = 32,
39 | D3DFMT_X8B8G8R8 = 33,
40 | D3DFMT_G16R16 = 34,
41 | D3DFMT_A2R10G10B10 = 35,
42 | D3DFMT_A16B16G16R16 = 36,
43 |
44 | D3DFMT_A8P8 = 40,
45 | D3DFMT_P8 = 41,
46 |
47 | D3DFMT_L8 = 50,
48 | D3DFMT_A8L8 = 51,
49 | D3DFMT_A4L4 = 52,
50 |
51 | D3DFMT_V8U8 = 60,
52 | D3DFMT_L6V5U5 = 61,
53 | D3DFMT_X8L8V8U8 = 62,
54 | D3DFMT_Q8W8V8U8 = 63,
55 | D3DFMT_V16U16 = 64,
56 | D3DFMT_A2W10V10U10 = 67,
57 |
58 | D3DFMT_UYVY = 'U' | 'Y' << 8 | 'V' << 16 | 'Y' << 24,
59 | D3DFMT_R8G8_B8G8 = 'R' | 'G' << 8 | 'B' << 16 | 'G' << 24,
60 | D3DFMT_YUY2 = 'Y' | 'U' << 8 | 'Y' << 16 | '2' << 24,
61 | D3DFMT_G8R8_G8B8 = 'G' | 'R' << 8 | 'G' << 16 | 'B' << 24,
62 | D3DFMT_DXT1 = 'D' | 'X' << 8 | 'T' << 16 | '1' << 24,
63 | D3DFMT_DXT2 = 'D' | 'X' << 8 | 'T' << 16 | '2' << 24,
64 | D3DFMT_DXT3 = 'D' | 'X' << 8 | 'T' << 16 | '3' << 24,
65 | D3DFMT_DXT4 = 'D' | 'X' << 8 | 'T' << 16 | '4' << 24,
66 | D3DFMT_DXT5 = 'D' | 'X' << 8 | 'T' << 16 | '5' << 24,
67 |
68 | D3DFMT_D16_LOCKABLE = 70,
69 | D3DFMT_D32 = 71,
70 | D3DFMT_D15S1 = 73,
71 | D3DFMT_D24S8 = 75,
72 | D3DFMT_D24X8 = 77,
73 | D3DFMT_D24X4S4 = 79,
74 | D3DFMT_D16 = 80,
75 |
76 | D3DFMT_D32F_LOCKABLE = 82,
77 | D3DFMT_D24FS8 = 83,
78 |
79 | D3DFMT_D32_LOCKABLE = 84,
80 | D3DFMT_S8_LOCKABLE = 85,
81 |
82 | D3DFMT_L16 = 81,
83 |
84 | D3DFMT_VERTEXDATA = 100,
85 | D3DFMT_INDEX16 = 101,
86 | D3DFMT_INDEX32 = 102,
87 |
88 | D3DFMT_Q16W16V16U16 = 110,
89 |
90 | D3DFMT_MULTI2_ARGB8 = 'M' | 'E' << 8 | 'T' << 16 | '1' << 24,
91 |
92 | D3DFMT_R16F = 111,
93 | D3DFMT_G16R16F = 112,
94 | D3DFMT_A16B16G16R16F = 113,
95 |
96 | D3DFMT_R32F = 114,
97 | D3DFMT_G32R32F = 115,
98 | D3DFMT_A32B32G32R32F = 116,
99 |
100 | D3DFMT_CxV8U8 = 117,
101 |
102 | D3DFMT_A1 = 118,
103 | D3DFMT_A2B10G10R10_XR_BIAS = 119,
104 | D3DFMT_BINARYBUFFER = 199,
105 |
106 | D3DFMT_FORCE_DWORD = 0x7fffffff
107 | }
108 |
109 | internal enum Format
110 | {
111 | Unknown = 0,
112 | ///
113 | /// 32-bit ARGB pixel format with alpha, using 8 bits per channel.
114 | ///
115 | A8R8G8B8 = 21,
116 | ///
117 | /// 32-bit RGB pixel format, where 8 bits are reserved for each color.
118 | ///
119 | X8R8G8B8 = 22,
120 |
121 | ///
122 | /// 32-bit z-buffer bit depth using 24 bits for the depth channel and 8 bits for the stencil channel.
123 | ///
124 | D24S8 = 75,
125 | }
126 |
127 | internal enum MultisampleType : int
128 | {
129 | D3DMULTISAMPLE_NONE = 0,
130 | D3DMULTISAMPLE_NONMASKABLE = 1,
131 | D3DMULTISAMPLE_2_SAMPLES = 2,
132 | D3DMULTISAMPLE_3_SAMPLES = 3,
133 | D3DMULTISAMPLE_4_SAMPLES = 4,
134 | D3DMULTISAMPLE_5_SAMPLES = 5,
135 | D3DMULTISAMPLE_6_SAMPLES = 6,
136 | D3DMULTISAMPLE_7_SAMPLES = 7,
137 | D3DMULTISAMPLE_8_SAMPLES = 8,
138 | D3DMULTISAMPLE_9_SAMPLES = 9,
139 | D3DMULTISAMPLE_10_SAMPLES = 10,
140 | D3DMULTISAMPLE_11_SAMPLES = 11,
141 | D3DMULTISAMPLE_12_SAMPLES = 12,
142 | D3DMULTISAMPLE_13_SAMPLES = 13,
143 | D3DMULTISAMPLE_14_SAMPLES = 14,
144 | D3DMULTISAMPLE_15_SAMPLES = 15,
145 | D3DMULTISAMPLE_16_SAMPLES = 16,
146 | D3DMULTISAMPLE_FORCE_DWORD = unchecked((int)0xffffffff),
147 | }
148 |
149 | internal enum SwapEffect
150 | {
151 | Discard = 1,
152 | }
153 |
154 | internal enum D3DResourceType
155 | {
156 | D3DRTYPE_SURFACE = 1,
157 | D3DRTYPE_VOLUME = 2,
158 | D3DRTYPE_TEXTURE = 3,
159 | D3DRTYPE_VOLUMETEXTURE = 4,
160 | D3DRTYPE_CUBETEXTURE = 5,
161 | D3DRTYPE_VERTEXBUFFER = 6,
162 | D3DRTYPE_INDEXBUFFER = 7,
163 | D3DRTYPE_FORCE_DWORD = 0x7fffffff
164 | }
165 |
166 | internal enum D3DPool
167 | {
168 | D3DPOOL_DEFAULT = 0,
169 | D3DPOOL_MANAGED = 1,
170 | D3DPOOL_SYSTEMMEM = 2,
171 | D3DPOOL_SCRATCH = 3,
172 | D3DPOOL_FORCE_DWORD = 0x7fffffff
173 | }
174 |
175 | [Flags]
176 | internal enum D3DUsage : uint
177 | {
178 | ///
179 | /// The resource will be a depth stencil buffer. D3DUSAGE_DEPTHSTENCIL can only be used with D3DPOOL_DEFAULT.
180 | ///
181 | D3DUSAGE_DEPTHSTENCIL = 0x00000002,
182 |
183 | ///
184 | /// The resource will be a render target. D3DUSAGE_RENDERTARGET can only be used with D3DPOOL_DEFAULT.
185 | ///
186 | D3DUSAGE_RENDERTARGET = 0x00000001,
187 |
188 | D3DUSAGE_DYNAMIC = 0x00000200,
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/src/GLWpfControl/Interop/PresentationParameters.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace OpenTK.Wpf.Interop
5 | {
6 | [StructLayout(LayoutKind.Sequential)]
7 | internal struct PresentationParameters
8 | {
9 | public int BackBufferWidth;
10 | public int BackBufferHeight;
11 | public Format BackBufferFormat;
12 | public uint BackBufferCount;
13 | public MultisampleType MultiSampleType;
14 | public int MultiSampleQuality;
15 | public SwapEffect SwapEffect;
16 | public IntPtr DeviceWindowHandle;
17 | public int Windowed;
18 | public int EnableAutoDepthStencil;
19 | public Format AutoDepthStencilFormat;
20 | public int Flags;
21 | public int FullScreen_RefreshRateInHz;
22 | public int PresentationInterval;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/GLWpfControl/NonReloadingTabControl.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Specialized;
3 | using System.Windows;
4 | using System.Windows.Controls;
5 | using System.Windows.Controls.Primitives;
6 |
7 | namespace OpenTK.Wpf
8 | {
9 | /// Special TabControl that does not unload/re-create items when it is used.
10 | /// // Prevent TabControl unload&re-create TabItem
11 | /// https://stackoverflow.com/questions/9794151/stop-tabcontrol-from-recreating-its-children
12 | [TemplatePart(Name = "PART_ItemsHolder", Type = typeof(Panel))]
13 | public class NonReloadingTabControl : TabControl
14 | {
15 | private Panel? _itemsHolderPanel;
16 |
17 | public NonReloadingTabControl() {
18 | // This is necessary so that we get the initial databound selected item
19 | ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
20 | }
21 |
22 | ///
23 | /// If containers are done, generate the selected item
24 | ///
25 | ///
26 | ///
27 | private void ItemContainerGenerator_StatusChanged(object? sender, EventArgs e)
28 | {
29 | if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
30 | {
31 | ItemContainerGenerator.StatusChanged -= ItemContainerGenerator_StatusChanged;
32 | UpdateSelectedItem();
33 | }
34 | }
35 |
36 | ///
37 | /// Get the ItemsHolder and generate any children
38 | ///
39 | public override void OnApplyTemplate()
40 | {
41 | base.OnApplyTemplate();
42 | _itemsHolderPanel = GetTemplateChild("PART_ItemsHolder") as Panel;
43 | UpdateSelectedItem();
44 | }
45 |
46 | ///
47 | /// When the items change we remove any generated panel children and add any new ones as necessary
48 | ///
49 | ///
50 | protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
51 | {
52 | base.OnItemsChanged(e);
53 |
54 | if (_itemsHolderPanel == null)
55 | return;
56 |
57 | switch (e.Action)
58 | {
59 | case NotifyCollectionChangedAction.Reset:
60 | _itemsHolderPanel.Children.Clear();
61 | break;
62 |
63 | case NotifyCollectionChangedAction.Add:
64 | case NotifyCollectionChangedAction.Remove:
65 | if (e.OldItems != null)
66 | {
67 | foreach (object? item in e.OldItems)
68 | {
69 | ContentPresenter? cp = FindChildContentPresenter(item);
70 | if (cp != null)
71 | _itemsHolderPanel.Children.Remove(cp);
72 | }
73 | }
74 |
75 | // Don't do anything with new items because we don't want to
76 | // create visuals that aren't being shown
77 |
78 | UpdateSelectedItem();
79 | break;
80 |
81 | case NotifyCollectionChangedAction.Replace:
82 | throw new NotImplementedException("Replace not implemented yet");
83 | }
84 | }
85 |
86 | protected override void OnSelectionChanged(SelectionChangedEventArgs e)
87 | {
88 | base.OnSelectionChanged(e);
89 | UpdateSelectedItem();
90 | }
91 |
92 | private void UpdateSelectedItem()
93 | {
94 | if (_itemsHolderPanel == null)
95 | return;
96 |
97 | // Generate a ContentPresenter if necessary
98 | TabItem? item = GetSelectedTabItem();
99 | if (item != null)
100 | CreateChildContentPresenter(item);
101 |
102 | // show the right child
103 | foreach (ContentPresenter? child in _itemsHolderPanel.Children)
104 | {
105 | if (child != null)
106 | {
107 | child.Visibility = ((child.Tag as TabItem)?.IsSelected ?? false) ? Visibility.Visible : Visibility.Collapsed;
108 | }
109 | }
110 | }
111 |
112 | private ContentPresenter? CreateChildContentPresenter(object item)
113 | {
114 | if (item == null)
115 | return null;
116 |
117 | ContentPresenter? cp = FindChildContentPresenter(item);
118 |
119 | if (cp != null)
120 | return cp;
121 |
122 | // the actual child to be added. cp.Tag is a reference to the TabItem
123 | cp = new ContentPresenter();
124 | cp.Content = (item is TabItem tabItem) ? tabItem.Content : item;
125 | cp.ContentTemplate = SelectedContentTemplate;
126 | cp.ContentTemplateSelector = SelectedContentTemplateSelector;
127 | cp.ContentStringFormat = SelectedContentStringFormat;
128 | cp.Visibility = Visibility.Collapsed;
129 | cp.Tag = (item is TabItem) ? item : (ItemContainerGenerator.ContainerFromItem(item));
130 | _itemsHolderPanel?.Children.Add(cp);
131 | return cp;
132 | }
133 |
134 | private ContentPresenter? FindChildContentPresenter(object? data)
135 | {
136 | if (data is TabItem tabItem)
137 | data = tabItem.Content;
138 |
139 | if (data == null)
140 | return null;
141 |
142 | if (_itemsHolderPanel == null)
143 | return null;
144 |
145 | foreach (ContentPresenter? cp in _itemsHolderPanel.Children)
146 | {
147 | if (cp?.Content == data)
148 | return cp;
149 | }
150 |
151 | return null;
152 | }
153 |
154 | protected TabItem? GetSelectedTabItem()
155 | {
156 | object selectedItem = SelectedItem;
157 | if (selectedItem == null)
158 | return null;
159 |
160 | TabItem? item = selectedItem as TabItem;
161 | if (item == null)
162 | {
163 | item = ItemContainerGenerator.ContainerFromIndex(SelectedIndex) as TabItem;
164 | }
165 |
166 | return item;
167 | }
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/src/GLWpfControl/paket:
--------------------------------------------------------------------------------
1 | type project
2 | title
3 | OpenTK.GLWpfControl
4 | id
5 | OpenTK.GLWpfControl
6 | owners
7 | opentk varon
8 | authors
9 | Team OpenTK
10 | summary
11 | A native WPF control for OpenTK 4.8.0+
12 | projectUrl
13 | https://www.opentk.net
14 | iconUrl
15 | https://raw.githubusercontent.com/opentk/opentk.net/docfx/assets/opentk.png
16 | licenseUrl
17 | https://github.com/varon/GLWpfControl/blob/master/LICENSE.md
18 | requireLicenseAcceptance
19 | false
20 | copyright
21 | Copyright (c) 2022 Team OpenTK.
22 |
23 | include-pdbs true
24 |
25 | dependencies
26 | OpenTK ~> 4.0 >= 4.8.2
27 |
28 | files
29 | bin\Release\netcoreapp3.1\netcoreapp3.1\GLWpfControl.dll ==> lib\netcoreapp3.1
30 | bin\Release\netcoreapp3.1\netcoreapp3.1\GLWpfControl.pdb ==> lib\netcoreapp3.1
31 |
--------------------------------------------------------------------------------