├── .clang-format
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── workflows
│ └── ci.yml
├── .gitignore
├── .gitmodules
├── .idea
├── .gitignore
├── LuisaShaderToy.iml
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── misc.xml
├── modules.xml
└── vcs.xml
├── CMakeLists.txt
├── LICENSE
├── README.md
├── gallery
└── protean_clouds.mp4
├── src
├── CMakeLists.txt
├── apps
│ ├── CMakeLists.txt
│ ├── energy_plant.cpp
│ ├── flame.cpp
│ ├── fractal_pyramid.cpp
│ ├── heartwing_angel.cpp
│ ├── protean_clouds.cpp
│ ├── rainbow_spaghetti.cpp
│ ├── sdf_renderer.cpp
│ ├── seascape.cpp
│ ├── sphere_in_cable.cpp
│ └── star_nest.cpp
├── ext
│ ├── CMakeLists.txt
│ ├── glad
│ │ ├── CMakeLists.txt
│ │ └── glad
│ │ │ ├── glad.c
│ │ │ ├── glad.h
│ │ │ └── khrplatform.h
│ ├── imgui
│ │ └── CMakeLists.txt
│ └── stb
│ │ ├── CMakeLists.txt
│ │ └── stb.cpp
└── gui
│ ├── CMakeLists.txt
│ ├── framerate.cpp
│ ├── framerate.h
│ ├── gl_texture.cpp
│ ├── gl_texture.h
│ ├── hid.h
│ ├── imgui_impl_glfw.cpp
│ ├── imgui_impl_glfw.h
│ ├── shader_toy.cpp
│ ├── shader_toy.h
│ ├── window.cpp
│ └── window.h
└── tools
└── record.py
/.clang-format:
--------------------------------------------------------------------------------
1 | # Generated from CLion C/C++ Code Style settings
2 | BasedOnStyle: LLVM
3 | AccessModifierOffset: -4
4 | AlignAfterOpenBracket: Align
5 | AlignConsecutiveAssignments: None
6 | AlignOperands: Align
7 | AllowAllArgumentsOnNextLine: false
8 | AllowAllConstructorInitializersOnNextLine: false
9 | AllowAllParametersOfDeclarationOnNextLine: false
10 | AllowShortBlocksOnASingleLine: Always
11 | AllowShortCaseLabelsOnASingleLine: false
12 | AllowShortFunctionsOnASingleLine: All
13 | AllowShortIfStatementsOnASingleLine: Always
14 | AllowShortLambdasOnASingleLine: All
15 | AllowShortLoopsOnASingleLine: true
16 | AlwaysBreakAfterReturnType: None
17 | AlwaysBreakTemplateDeclarations: Yes
18 | BreakBeforeBraces: Custom
19 | BraceWrapping:
20 | AfterCaseLabel: false
21 | AfterClass: false
22 | AfterControlStatement: Never
23 | AfterEnum: false
24 | AfterFunction: false
25 | AfterNamespace: false
26 | AfterUnion: false
27 | BeforeCatch: false
28 | BeforeElse: false
29 | IndentBraces: false
30 | SplitEmptyFunction: false
31 | SplitEmptyRecord: true
32 | BreakBeforeBinaryOperators: NonAssignment
33 | BreakBeforeTernaryOperators: true
34 | BreakConstructorInitializers: BeforeColon
35 | BreakInheritanceList: BeforeColon
36 | ColumnLimit: 0
37 | CompactNamespaces: true
38 | ContinuationIndentWidth: 4
39 | IndentCaseLabels: true
40 | IndentPPDirectives: None
41 | IndentWidth: 4
42 | KeepEmptyLinesAtTheStartOfBlocks: true
43 | MaxEmptyLinesToKeep: 1
44 | NamespaceIndentation: None
45 | ObjCSpaceAfterProperty: false
46 | ObjCSpaceBeforeProtocolList: false
47 | PointerAlignment: Right
48 | ReflowComments: false
49 | SpaceAfterCStyleCast: false
50 | SpaceAfterLogicalNot: false
51 | SpaceAfterTemplateKeyword: false
52 | SpaceBeforeAssignmentOperators: true
53 | SpaceBeforeCpp11BracedList: false
54 | SpaceBeforeCtorInitializerColon: true
55 | SpaceBeforeInheritanceColon: true
56 | SpaceBeforeParens: ControlStatements
57 | SpaceBeforeRangeBasedForLoopColon: true
58 | SpaceInEmptyParentheses: false
59 | SpacesBeforeTrailingComments: 0
60 | SpacesInAngles: false
61 | SpacesInCStyleCastParentheses: false
62 | SpacesInContainerLiterals: false
63 | SpacesInParentheses: false
64 | SpacesInSquareBrackets: false
65 | TabWidth: 4
66 | UseTab: Never
67 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: build
2 |
3 | on: [ push, pull_request ]
4 |
5 | jobs:
6 | build-linux:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v2
10 | with:
11 | submodules: recursive
12 | - name: "Install Dependencies"
13 | run: |
14 | sudo apt-get purge --auto-remove cmake
15 | wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null
16 | sudo apt-add-repository 'deb https://apt.kitware.com/ubuntu/ focal main'
17 | sudo add-apt-repository ppa:ubuntu-toolchain-r/test
18 | sudo apt-get update
19 | sudo apt-get -y install cmake
20 | sudo apt-get -y install gcc-11 g++-11 build-essential ninja-build git file libopencv-dev uuid-dev libglfw3-dev libxinerama-dev libxcursor-dev libxi-dev
21 | wget https://apt.llvm.org/llvm.sh
22 | chmod +x llvm.sh
23 | sudo ./llvm.sh 14
24 | # - name: "Setup CUDA"
25 | # uses: Jimver/cuda-toolkit@v0.2.4
26 | # with:
27 | # cuda: "11.4.0"
28 | # linux-local-args: '["--toolkit"]'
29 | - name: "Configure and Build"
30 | run: |
31 | cmake -S . -B build -G Ninja -D CMAKE_BUILD_TYPE=Release -D CMAKE_C_COMPILER=gcc-11 -D CMAKE_CXX_COMPILER=g++-11 -D LLVM_ROOT=/usr/lib/llvm-14
32 | cmake --build build
33 |
34 | build-macos:
35 | runs-on: macos-latest
36 | steps:
37 | - uses: actions/checkout@v2
38 | with:
39 | submodules: recursive
40 | - name: "Install Dependencies"
41 | run: |
42 | brew install cmake ninja opencv llvm sccache glfw
43 | - name: "Configure and Build"
44 | run: |
45 | export PATH=$PATH:/usr/local/opt/llvm/bin
46 | cmake -S . -B build -G Ninja -D CMAKE_BUILD_TYPE=Release -D LUISA_COMPUTE_ENABLE_METAL=OFF -D CMAKE_C_COMPILER=/usr/local/opt/llvm/bin/clang -D CMAKE_CXX_COMPILER=/usr/local/opt/llvm/bin/clang++
47 | cmake --build build
48 |
49 | build-windows:
50 | runs-on: windows-latest
51 | steps:
52 | - uses: actions/checkout@v2
53 | with:
54 | submodules: recursive
55 | # - name: "Setup CUDA"
56 | # uses: Jimver/cuda-toolkit@v0.2.4
57 | # with:
58 | # cuda: "11.4.0"
59 | - name: "Setup Ninja"
60 | uses: ashutoshvarma/setup-ninja@master
61 | with:
62 | version: 1.10.2
63 | - name: "Configure and Build"
64 | shell: cmd
65 | run: |
66 | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
67 | cmake -S . -G Ninja -B build -D CMAKE_BUILD_TYPE=Release -D CMAKE_C_COMPILER:FILEPATH=cl.exe -D CMAKE_CXX_COMPILER:FILEPATH=cl.exe
68 | cmake --build build
69 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### VisualStudioCode template
2 | .vscode/*
3 | !.vscode/settings.json
4 | !.vscode/tasks.json
5 | !.vscode/launch.json
6 | !.vscode/extensions.json
7 | *.code-workspace
8 |
9 | # Local History for Visual Studio Code
10 | .history/
11 |
12 | ### Linux template
13 | *~
14 |
15 | # temporary files which can be created if a process still has a handle open of a deleted file
16 | .fuse_hidden*
17 |
18 | # KDE directory preferences
19 | .directory
20 |
21 | # Linux trash folder which might appear on any partition or disk
22 | .Trash-*
23 |
24 | # .nfs files are created when an open file is removed but is still being accessed
25 | .nfs*
26 |
27 | ### macOS template
28 | # General
29 | .DS_Store
30 | .AppleDouble
31 | .LSOverride
32 |
33 | # Icon must end with two \r
34 | Icon
35 |
36 | # Thumbnails
37 | ._*
38 |
39 | # Files that might appear in the root of a volume
40 | .DocumentRevisions-V100
41 | .fseventsd
42 | .Spotlight-V100
43 | .TemporaryItems
44 | .Trashes
45 | .VolumeIcon.icns
46 | .com.apple.timemachine.donotpresent
47 |
48 | # Directories potentially created on remote AFP share
49 | .AppleDB
50 | .AppleDesktop
51 | Network Trash Folder
52 | Temporary Items
53 | .apdisk
54 |
55 | ### VisualStudio template
56 | ## Ignore Visual Studio temporary files, build results, and
57 | ## files generated by popular Visual Studio add-ons.
58 | ##
59 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
60 |
61 | # User-specific files
62 | *.rsuser
63 | *.suo
64 | *.user
65 | *.userosscache
66 | *.sln.docstates
67 |
68 | # User-specific files (MonoDevelop/Xamarin Studio)
69 | *.userprefs
70 |
71 | # Mono auto generated files
72 | mono_crash.*
73 |
74 | # Build results
75 | [Dd]ebug/
76 | [Dd]ebugPublic/
77 | [Rr]elease/
78 | [Rr]eleases/
79 | x64/
80 | x86/
81 | [Ww][Ii][Nn]32/
82 | [Aa][Rr][Mm]/
83 | [Aa][Rr][Mm]64/
84 | bld/
85 | [Bb]in/
86 | [Oo]bj/
87 | [Ll]og/
88 | [Ll]ogs/
89 |
90 | # Visual Studio 2015/2017 cache/options directory
91 | .vs/
92 | # Uncomment if you have tasks that create the project's static files in wwwroot
93 | #wwwroot/
94 |
95 | # Visual Studio 2017 auto generated files
96 | Generated\ Files/
97 |
98 | # MSTest test Results
99 | [Tt]est[Rr]esult*/
100 | [Bb]uild[Ll]og.*
101 |
102 | # NUnit
103 | *.VisualState.xml
104 | TestResult.xml
105 | nunit-*.xml
106 |
107 | # Build Results of an ATL Project
108 | [Dd]ebugPS/
109 | [Rr]eleasePS/
110 | dlldata.c
111 |
112 | # Benchmark Results
113 | BenchmarkDotNet.Artifacts/
114 |
115 | # .NET Core
116 | project.lock.json
117 | project.fragment.lock.json
118 | artifacts/
119 |
120 | # ASP.NET Scaffolding
121 | ScaffoldingReadMe.txt
122 |
123 | # StyleCop
124 | StyleCopReport.xml
125 |
126 | # Files built by Visual Studio
127 | *_i.c
128 | *_p.c
129 | *_h.h
130 | *.ilk
131 | *.meta
132 | *.obj
133 | *.iobj
134 | *.pch
135 | *.pdb
136 | *.ipdb
137 | *.pgc
138 | *.pgd
139 | *.rsp
140 | *.sbr
141 | *.tlb
142 | *.tli
143 | *.tlh
144 | *.tmp
145 | *.tmp_proj
146 | *_wpftmp.csproj
147 | *.log
148 | *.vspscc
149 | *.vssscc
150 | .builds
151 | *.pidb
152 | *.svclog
153 | *.scc
154 |
155 | # Chutzpah Test files
156 | _Chutzpah*
157 |
158 | # Visual C++ cache files
159 | ipch/
160 | *.aps
161 | *.ncb
162 | *.opendb
163 | *.opensdf
164 | *.sdf
165 | *.cachefile
166 | *.VC.db
167 | *.VC.VC.opendb
168 |
169 | # Visual Studio profiler
170 | *.psess
171 | *.vsp
172 | *.vspx
173 | *.sap
174 |
175 | # Visual Studio Trace Files
176 | *.e2e
177 |
178 | # TFS 2012 Local Workspace
179 | $tf/
180 |
181 | # Guidance Automation Toolkit
182 | *.gpState
183 |
184 | # ReSharper is a .NET coding add-in
185 | _ReSharper*/
186 | *.[Rr]e[Ss]harper
187 | *.DotSettings.user
188 |
189 | # TeamCity is a build add-in
190 | _TeamCity*
191 |
192 | # DotCover is a Code Coverage Tool
193 | *.dotCover
194 |
195 | # AxoCover is a Code Coverage Tool
196 | .axoCover/*
197 | !.axoCover/settings.json
198 |
199 | # Coverlet is a free, cross platform Code Coverage Tool
200 | coverage*.json
201 | coverage*.xml
202 | coverage*.info
203 |
204 | # Visual Studio code coverage results
205 | *.coverage
206 | *.coveragexml
207 |
208 | # NCrunch
209 | _NCrunch_*
210 | .*crunch*.local.xml
211 | nCrunchTemp_*
212 |
213 | # MightyMoose
214 | *.mm.*
215 | AutoTest.Net/
216 |
217 | # Web workbench (sass)
218 | .sass-cache/
219 |
220 | # Installshield output folder
221 | [Ee]xpress/
222 |
223 | # DocProject is a documentation generator add-in
224 | DocProject/buildhelp/
225 | DocProject/Help/*.HxT
226 | DocProject/Help/*.HxC
227 | DocProject/Help/*.hhc
228 | DocProject/Help/*.hhk
229 | DocProject/Help/*.hhp
230 | DocProject/Help/Html2
231 | DocProject/Help/html
232 |
233 | # Click-Once directory
234 | publish/
235 |
236 | # Publish Web Output
237 | *.[Pp]ublish.xml
238 | *.azurePubxml
239 | # Note: Comment the next line if you want to checkin your web deploy settings,
240 | # but database connection strings (with potential passwords) will be unencrypted
241 | *.pubxml
242 | *.publishproj
243 |
244 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
245 | # checkin your Azure Web App publish settings, but sensitive information contained
246 | # in these scripts will be unencrypted
247 | PublishScripts/
248 |
249 | # NuGet Packages
250 | *.nupkg
251 | # NuGet Symbol Packages
252 | *.snupkg
253 | # The packages folder can be ignored because of Package Restore
254 | **/[Pp]ackages/*
255 | # except build/, which is used as an MSBuild target.
256 | !**/[Pp]ackages/build/
257 | # Uncomment if necessary however generally it will be regenerated when needed
258 | #!**/[Pp]ackages/repositories.config
259 | # NuGet v3's project.json files produces more ignorable files
260 | *.nuget.props
261 | *.nuget.targets
262 |
263 | # Microsoft Azure Build Output
264 | csx/
265 | *.build.csdef
266 |
267 | # Microsoft Azure Emulator
268 | ecf/
269 | rcf/
270 |
271 | # Windows Store app package directories and files
272 | AppPackages/
273 | BundleArtifacts/
274 | Package.StoreAssociation.xml
275 | _pkginfo.txt
276 | *.appx
277 | *.appxbundle
278 | *.appxupload
279 |
280 | # Visual Studio cache files
281 | # files ending in .cache can be ignored
282 | *.[Cc]ache
283 | # but keep track of directories ending in .cache
284 | !?*.[Cc]ache/
285 |
286 | # Others
287 | ClientBin/
288 | ~$*
289 | *.dbmdl
290 | *.dbproj.schemaview
291 | *.jfm
292 | *.pfx
293 | *.publishsettings
294 | orleans.codegen.cs
295 |
296 | # Including strong name files can present a security risk
297 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
298 | #*.snk
299 |
300 | # Since there are multiple workflows, uncomment next line to ignore bower_components
301 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
302 | #bower_components/
303 |
304 | # RIA/Silverlight projects
305 | Generated_Code/
306 |
307 | # Backup & report files from converting an old project file
308 | # to a newer Visual Studio version. Backup files are not needed,
309 | # because we have git ;-)
310 | _UpgradeReport_Files/
311 | Backup*/
312 | UpgradeLog*.XML
313 | UpgradeLog*.htm
314 | ServiceFabricBackup/
315 | *.rptproj.bak
316 |
317 | # SQL Server files
318 | *.mdf
319 | *.ldf
320 | *.ndf
321 |
322 | # Business Intelligence projects
323 | *.rdl.data
324 | *.bim.layout
325 | *.bim_*.settings
326 | *.rptproj.rsuser
327 | *- [Bb]ackup.rdl
328 | *- [Bb]ackup ([0-9]).rdl
329 | *- [Bb]ackup ([0-9][0-9]).rdl
330 |
331 | # Microsoft Fakes
332 | FakesAssemblies/
333 |
334 | # GhostDoc plugin setting file
335 | *.GhostDoc.xml
336 |
337 | # Node.js Tools for Visual Studio
338 | .ntvs_analysis.dat
339 | node_modules/
340 |
341 | # Visual Studio 6 build log
342 | *.plg
343 |
344 | # Visual Studio 6 workspace options file
345 | *.opt
346 |
347 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
348 | *.vbw
349 |
350 | # Visual Studio LightSwitch build output
351 | **/*.HTMLClient/GeneratedArtifacts
352 | **/*.DesktopClient/GeneratedArtifacts
353 | **/*.DesktopClient/ModelManifest.xml
354 | **/*.Server/GeneratedArtifacts
355 | **/*.Server/ModelManifest.xml
356 | _Pvt_Extensions
357 |
358 | # Paket dependency manager
359 | .paket/paket.exe
360 | paket-files/
361 |
362 | # FAKE - F# Make
363 | .fake/
364 |
365 | # CodeRush personal settings
366 | .cr/personal
367 |
368 | # Python Tools for Visual Studio (PTVS)
369 | __pycache__/
370 | *.pyc
371 |
372 | # Cake - Uncomment if you are using it
373 | # tools/**
374 | # !tools/packages.config
375 |
376 | # Tabs Studio
377 | *.tss
378 |
379 | # Telerik's JustMock configuration file
380 | *.jmconfig
381 |
382 | # BizTalk build output
383 | *.btp.cs
384 | *.btm.cs
385 | *.odx.cs
386 | *.xsd.cs
387 |
388 | # OpenCover UI analysis results
389 | OpenCover/
390 |
391 | # Azure Stream Analytics local run output
392 | ASALocalRun/
393 |
394 | # MSBuild Binary and Structured Log
395 | *.binlog
396 |
397 | # NVidia Nsight GPU debugger configuration file
398 | *.nvuser
399 |
400 | # MFractors (Xamarin productivity tool) working folder
401 | .mfractor/
402 |
403 | # Local History for Visual Studio
404 | .localhistory/
405 |
406 | # BeatPulse healthcheck temp database
407 | healthchecksdb
408 |
409 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
410 | MigrationBackup/
411 |
412 | # Ionide (cross platform F# VS Code tools) working folder
413 | .ionide/
414 |
415 | # Fody - auto-generated XML schema
416 | FodyWeavers.xsd
417 |
418 | ### CMake template
419 | CMakeLists.txt.user
420 | CMakeCache.txt
421 | CMakeFiles
422 | CMakeScripts
423 | Testing
424 | Makefile
425 | cmake_install.cmake
426 | install_manifest.txt
427 | compile_commands.json
428 | CTestTestfile.cmake
429 | _deps
430 |
431 | ### Vim template
432 | # Swap
433 | [._]*.s[a-v][a-z]
434 | !*.svg # comment out if you don't need vector files
435 | [._]*.sw[a-p]
436 | [._]s[a-rt-v][a-z]
437 | [._]ss[a-gi-z]
438 | [._]sw[a-p]
439 |
440 | # Session
441 | Session.vim
442 | Sessionx.vim
443 |
444 | # Temporary
445 | .netrwhist
446 | # Auto-generated tag files
447 | tags
448 | # Persistent undo
449 | [._]*.un~
450 |
451 | ### JetBrains template
452 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
453 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
454 |
455 | # User-specific stuff
456 | .idea/**/workspace.xml
457 | .idea/**/tasks.xml
458 | .idea/**/usage.statistics.xml
459 | .idea/**/dictionaries
460 | .idea/**/shelf
461 |
462 | # Generated files
463 | .idea/**/contentModel.xml
464 |
465 | # Sensitive or high-churn files
466 | .idea/**/dataSources/
467 | .idea/**/dataSources.ids
468 | .idea/**/dataSources.local.xml
469 | .idea/**/sqlDataSources.xml
470 | .idea/**/dynamic.xml
471 | .idea/**/uiDesigner.xml
472 | .idea/**/dbnavigator.xml
473 |
474 | # Gradle
475 | .idea/**/gradle.xml
476 | .idea/**/libraries
477 |
478 | # Gradle and Maven with auto-import
479 | # When using Gradle or Maven with auto-import, you should exclude module files,
480 | # since they will be recreated, and may cause churn. Uncomment if using
481 | # auto-import.
482 | # .idea/artifacts
483 | # .idea/compiler.xml
484 | # .idea/jarRepositories.xml
485 | # .idea/modules.xml
486 | # .idea/*.iml
487 | # .idea/modules
488 | # *.iml
489 | # *.ipr
490 |
491 | # CMake
492 | cmake-build-*/
493 |
494 | # Mongo Explorer plugin
495 | .idea/**/mongoSettings.xml
496 |
497 | # File-based project format
498 | *.iws
499 |
500 | # IntelliJ
501 | out/
502 |
503 | # mpeltonen/sbt-idea plugin
504 | .idea_modules/
505 |
506 | # JIRA plugin
507 | atlassian-ide-plugin.xml
508 |
509 | # Cursive Clojure plugin
510 | .idea/replstate.xml
511 |
512 | # Crashlytics plugin (for Android Studio and IntelliJ)
513 | com_crashlytics_export_strings.xml
514 | crashlytics.properties
515 | crashlytics-build.properties
516 | fabric.properties
517 |
518 | # Editor-based Rest Client
519 | .idea/httpRequests
520 |
521 | # Android studio 3.1+ serialized cache file
522 | .idea/caches/build_file_checksums.ser
523 |
524 | ### Windows template
525 | # Windows thumbnail cache files
526 | Thumbs.db
527 | Thumbs.db:encryptable
528 | ehthumbs.db
529 | ehthumbs_vista.db
530 |
531 | # Dump file
532 | *.stackdump
533 |
534 | # Folder config file
535 | [Dd]esktop.ini
536 |
537 | # Recycle Bin used on file shares
538 | $RECYCLE.BIN/
539 |
540 | # Windows Installer files
541 | *.cab
542 | *.msi
543 | *.msix
544 | *.msm
545 | *.msp
546 |
547 | # Windows shortcuts
548 | *.lnk
549 |
550 | ### Emacs template
551 | # -*- mode: gitignore; -*-
552 | \#*\#
553 | /.emacs.desktop
554 | /.emacs.desktop.lock
555 | *.elc
556 | auto-save-list
557 | tramp
558 | .\#*
559 |
560 | # Org-mode
561 | .org-id-locations
562 | *_archive
563 |
564 | # flymake-mode
565 | *_flymake.*
566 |
567 | # eshell files
568 | /eshell/history
569 | /eshell/lastdir
570 |
571 | # elpa packages
572 | /elpa/
573 |
574 | # reftex files
575 | *.rel
576 |
577 | # AUCTeX auto folder
578 | /auto/
579 |
580 | # cask packages
581 | .cask/
582 | dist/
583 |
584 | # Flycheck
585 | flycheck_*.el
586 |
587 | # server auth directory
588 | /server/
589 |
590 | # projectiles files
591 | .projectile
592 |
593 | # directory configuration
594 | .dir-locals.el
595 |
596 | # network security
597 | /network-security.data
598 |
599 |
600 | build/src/compute/src/ext/spdlog/spdlog_pch.h
601 | build/src/ext/glfw/src/glfw3.pc
602 | build/src/ext/glfw/src/glfw3Config.cmake
603 | build/src/ext/glfw/src/glfw3ConfigVersion.cmake
604 | build/src/ext/glfw/src/glfw_config.h
605 | *.json
606 | *.a
607 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "src/ext/glfw"]
2 | path = src/ext/glfw
3 | url = https://github.com/glfw/glfw.git
4 | [submodule "src/ext/imgui/imgui"]
5 | path = src/ext/imgui/imgui
6 | url = https://github.com/ocornut/imgui.git
7 | [submodule "src/compute"]
8 | path = src/compute
9 | url = https://github.com/LuisaGroup/LuisaCompute.git
10 | [submodule "src/ext/stb/stb"]
11 | path = src/ext/stb/stb
12 | url = https://github.com/nothings/stb.git
13 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Datasource local storage ignored files
5 | /dataSources/
6 | /dataSources.local.xml
7 | # Editor-based HTTP Client requests
8 | /httpRequests/
9 |
--------------------------------------------------------------------------------
/.idea/LuisaShaderToy.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.18...3.20)
2 | cmake_policy(VERSION 3.18)
3 |
4 | project(LuisaShaderToy LANGUAGES C CXX VERSION 0.1)
5 |
6 | set(CMAKE_C_STANDARD 11)
7 | set(CMAKE_CXX_STANDARD 20)
8 | set(CMAKE_C_STANDARD_REQUIRED ON)
9 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
10 | set(CMAKE_C_EXTENSIONS OFF)
11 | set(CMAKE_CXX_EXTENSIONS OFF)
12 | set(CMAKE_OSX_DEPLOYMENT_TARGET 12)
13 |
14 | set(BUILD_SHARED_LIBS ON)
15 |
16 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
17 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
18 | foreach (CONFIG ${CMAKE_CONFIGURATION_TYPES})
19 | string(TOUPPER ${CONFIG} CONFIG_UPPER)
20 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG_UPPER} "${CMAKE_BINARY_DIR}/${CONFIG}/bin")
21 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONFIG_UPPER} "${CMAKE_BINARY_DIR}/${CONFIG}/bin")
22 | endforeach ()
23 |
24 | set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
25 | set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
26 |
27 | if (MSVC)
28 | string(REGEX REPLACE "/EH[a-z]+" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
29 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
30 | endif ()
31 |
32 | add_subdirectory(src)
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2021, LuisaGroup
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LuisaShaderToy
2 |
3 | LuisaShaderToy is a playground for testing shaders with [LuisaCompute](https://github.com/LuisaGroup/LuisaCompute).
4 |
5 | See `src/apps` for some demo toys we port from the original [ShaderToy](https://www.shadertoy.com) website.
6 |
7 | # Demos
8 |
9 | https://user-images.githubusercontent.com/7614925/191537869-baf78cde-dbf7-46b4-860f-f87470e800ea.mp4
10 |
11 |
12 |
13 | https://user-images.githubusercontent.com/7614925/191538018-1a50b50d-bf8f-49d3-a4b9-c6a4ae30c1d9.mp4
14 |
15 |
16 |
17 | https://user-images.githubusercontent.com/7614925/191538042-c589829f-9273-4506-a45d-c0e474b9a226.mp4
18 |
19 |
--------------------------------------------------------------------------------
/gallery/protean_clouds.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LuisaGroup/LuisaShaderToy/01c968a379fcd7d810851311607a5dcdba46be3c/gallery/protean_clouds.mp4
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | include_directories("${CMAKE_CURRENT_SOURCE_DIR}")
2 |
3 | set(LUISA_COMPUTE_ENABLE_GUI OFF CACHE BOOL "" FORCE)
4 | add_subdirectory(compute)
5 |
6 | add_subdirectory(ext)
7 | add_subdirectory(gui)
8 |
9 | add_library(luisa::shader-toy ALIAS luisa-shader-toy-gui)
10 |
11 | add_subdirectory(apps)
12 |
--------------------------------------------------------------------------------
/src/apps/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | function(luisa_shader_toy_add_executable name)
2 | add_executable(${name} ${name}.cpp)
3 | target_link_libraries(${name} PRIVATE luisa::shader-toy)
4 | endfunction()
5 |
6 | luisa_shader_toy_add_executable(fractal_pyramid)
7 | luisa_shader_toy_add_executable(energy_plant)
8 | luisa_shader_toy_add_executable(star_nest)
9 | luisa_shader_toy_add_executable(protean_clouds)
10 | luisa_shader_toy_add_executable(heartwing_angel)
11 | luisa_shader_toy_add_executable(flame)
12 | luisa_shader_toy_add_executable(rainbow_spaghetti)
13 | luisa_shader_toy_add_executable(sphere_in_cable)
14 | luisa_shader_toy_add_executable(sdf_renderer)
15 | luisa_shader_toy_add_executable(seascape)
16 |
--------------------------------------------------------------------------------
/src/apps/energy_plant.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/25.
3 | //
4 |
5 | #include
6 |
7 | using namespace luisa;
8 | using namespace luisa::compute;
9 |
10 | // Credit: https://www.shadertoy.com/view/WdjBWc
11 | int main(int argc, char *argv[]) {// FIXME...
12 |
13 | gui::ShaderToy toy{argc, argv};
14 |
15 | Callable rot = [](Float a) noexcept {
16 | Var s = sin(a);
17 | Var c = cos(a);
18 | return make_float2x2(c, -s, s, c);
19 | };
20 |
21 | Callable lpNorm = [](Float3 p, Float n) noexcept {
22 | p = pow(abs(p), make_float3(n));
23 | return pow(p.x + p.y + p.z, 1.0f / n);
24 | };
25 |
26 | Callable pSFold = [](Float2 p, Float n) noexcept {
27 | Var h = floor(log2(n));
28 | Var a = 6.2831f * exp2(h) / n;
29 | for (auto i : range(cast(h) + 2u)) {
30 | Var v = make_float2(-cos(a), sin(a));
31 | Var g = dot(p, v);
32 | p -= (g - sqrt(g * g + 5e-3f)) * v;
33 | a *= 0.5f;
34 | }
35 | return p;
36 | };
37 |
38 | Callable sFold45 = [](Float2 p, Float k) noexcept {
39 | Var v = float2(-1.0f, 1.0f) * 0.7071f;
40 | Var g = dot(p, v);
41 | return p - (g - sqrt(g * g + k)) * v;
42 | };
43 |
44 | Callable frameBox = [&](Float3 p, Float3 s, Float r) noexcept {
45 | p = abs(p) - s;
46 | p = make_float3(p.x, sFold45(p.yz(), 1e-3f));
47 | p = make_float3(sFold45(p.xy(), 1e-3f), p.z);
48 | p.x = max(0.0f, p.x);
49 | return lpNorm(p, 5.0f) - r;
50 | };
51 |
52 | Callable sdRoundBox = [](Float3 p, Float3 b, Float r) noexcept {
53 | Var q = abs(p) - b;
54 | return length(max(q, 0.0f)) + min(max(q.x, max(q.y, q.z)), 0.0f) - r;
55 | };
56 |
57 | Callable deObj = [&](Float3 p) noexcept {
58 | return min(min(sdRoundBox(p, float3(0.3f), 0.1f),
59 | frameBox(p, float3(0.7f), 0.05f)),
60 | frameBox(p, float3(0.5f), 0.01f));
61 | };
62 |
63 | Callable map = [&](Float3 p, Float &g, Float time) noexcept {
64 | Var de = 1e9f;
65 | p.z -= time * 1.5f;
66 | p.z = mod(p.z, 12.0f) - 6.0f;
67 | Var q = p;
68 | p = make_float3(pSFold(p.xy(), 6.0f), p.z);
69 | p.y -= 5.0f;
70 | Var s = 1.0f;
71 | for (auto i = 0; i < 6; i++) {
72 | p = make_float3(abs(p.xy()) - 0.5f, p.z);
73 | p.z = abs(p.z) - 0.3f;
74 | p = make_float3(rot(-0.05f) * p.xy(), p.z);
75 | p = make_float3(p.x, rot(0.1f) * p.zy()).xzy();
76 | s *= 0.7f;
77 | p *= s;
78 | p = make_float3(rot(0.05f) * p.xy(), p.z);
79 | p.y -= 0.3f;
80 | Var sp = p / s;
81 | de = min(de, min(sdRoundBox(sp, float3(0.3f), 0.1f),
82 | frameBox(sp, float3(0.7f), 0.05f)));
83 | }
84 | q.z -= clamp(q.z, -1.f, 1.f);
85 | Var d = length(q) - 0.5f;
86 | g += 0.1f / (0.2f + d * d * 5.0f);// Distance glow by balkhan
87 | de = min(de, d + 0.2f);
88 | return de;
89 | };
90 |
91 | Callable calcNormal = [&](Float3 pos, Float &g, Float time) noexcept {
92 | auto e = float2(1.0f, -1.0f) * 0.002f;
93 | auto m1 = map(pos + e.xyy(), g, time);
94 | auto m2 = map(pos + e.yyx(), g, time);
95 | auto m3 = map(pos + e.yxy(), g, time);
96 | auto m4 = map(pos + e.xxx(), g, time);
97 | return normalize(e.xyy() * m1 + e.yyx() * m2 + e.yxy() * m3 + e.xxx() * m4);
98 | };
99 |
100 | Callable march = [&](Float3 ro, Float3 rd, Float t_near, Float t_far, Float &g, Float time) noexcept {
101 | Var t = t_near;
102 | Var ret = t_far;
103 | for (auto i : range(100)) {
104 | auto d = map(ro + rd * t, g, time);
105 | t += d;
106 | if_(d < 0.001f, [&] {
107 | ret = t;
108 | break_();
109 | });
110 | if_(t >= t_far, break_);
111 | }
112 | return ret;
113 | };
114 |
115 | Callable calcShadow = [&](Float3 light, Float3 ld, Float len, Float &g, Float time) noexcept {
116 | auto depth = march(light, ld, 0.0f, len, g, time);
117 | return step(len - depth, 0.01f);
118 | };
119 |
120 | Callable doColor = [](Float3 p) noexcept {
121 | return float3(0.3, 0.5, 0.8) + cos(p * 0.2f) * .5f + .5f;
122 | };
123 |
124 | Callable reflect = [](Float3 I, Float3 N) noexcept {
125 | return I - 2.0f * dot(N, I) * N;
126 | };
127 |
128 | toy.run([&](Float2 fragCoord, Float2 iResolution, Float time, Float4 cursor) noexcept {
129 | Var uv = (fragCoord * 2.0f - iResolution.xy()) / iResolution.y;
130 | auto ro = float3(2.5, 3.5, 8);
131 | auto ta = float3(-1, 0, 0);
132 | auto w = normalize(ta - ro);
133 | auto u = normalize(cross(w, float3(0.0f, 1.0f, 0.0f)));
134 | Var rd = float3x3(u, cross(u, w), w) * normalize(make_float3(uv, 2.0f));
135 | Var col = make_float3(0.05f, 0.05f, 0.1f);
136 | static constexpr auto maxd = 80.0f;
137 | auto g = def(0.0f);
138 | auto t = march(ro, rd, 0.0f, maxd, g, time);
139 | if_(t < maxd, [&] {
140 | Var p = ro + rd * t;
141 | col = doColor(p);
142 | auto n = calcNormal(p, g, time);
143 | auto lightPos = float3(5.0f, 5.0f, 1.0f);
144 | Var li = lightPos - p;
145 | Var len = length(li);
146 | li /= len;
147 | Var dif = clamp(dot(n, li), 0.0f, 1.0f);
148 | auto sha = calcShadow(lightPos, -li, len, g, time);
149 | col *= max(sha * dif, 0.2f);
150 | Var rimd = pow(clamp(1.0f - dot(reflect(-li, n), -rd), 0.0f, 1.0f), 2.5f);
151 | Var frn = rimd + 2.2f * (1.0f - rimd);
152 | col *= frn * 0.8f;
153 | col *= max(0.5f + 0.5f * n.y, 0.0f);
154 | auto m = map(p + n * 0.3f, g, time);
155 | col *= exp2(-2.f * pow(max(0.0f, 1.0f - m / 0.3f), 2.0f));
156 | col += float3(0.8f, 0.6f, 0.2f) * pow(clamp(dot(reflect(rd, n), li), 0.0f, 1.0f), 20.0f);
157 | col = lerp(float3(0.1f, 0.1f, 0.2f), col, exp(-0.001f * t * t));
158 | col += float3(0.7f, 0.3f, 0.1f) * g * (1.5f + 0.8f * sin(time * 3.5f));
159 | col = clamp(col, 0.0f, 1.0f);
160 | });
161 | return pow(col, float3(1.5f));
162 | });
163 | }
164 |
--------------------------------------------------------------------------------
/src/apps/flame.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/25.
3 | //
4 |
5 | #include
6 |
7 | using namespace luisa;
8 | using namespace luisa::compute;
9 |
10 | // Credit: https://www.shadertoy.com/view/MdX3zr
11 | int main(int argc, char *argv[]) {
12 |
13 | gui::ShaderToy toy{argc, argv};
14 |
15 | Callable noise = [](Float3 p) noexcept {
16 | Var i = floor(p);
17 | Var a = dot(i, float3(1.f, 57.f, 21.f)) + float4(0.f, 57.f, 21.f, 78.f);
18 | Var f = cos((p - i) * acos(-1.f)) * (-.5f) + .5f;
19 | a = lerp(sin(cos(a) * a), sin(cos(1.f + a) * (1.f + a)), f.x);
20 | Var axy = lerp(a.xz(), a.yw(), f.y);
21 | return lerp(axy.x, axy.y, f.z);
22 | };
23 |
24 | Callable sphere = [](Float3 p, Float4 spr) noexcept {
25 | return length(spr.xyz() - p) - spr.w;
26 | };
27 |
28 | Callable flame = [&](Float3 p, Float iTime) noexcept {
29 | Var d = sphere(p * float3(1.f, .5f, 1.f), float4(.0f, -1.f, .0f, 1.f));
30 | return d + (noise(p + make_float3(.0f, iTime * 2.f, .0f)) + noise(p * 3.f) * .5f) * .25f * p.y;
31 | };
32 |
33 | Callable scene = [&](Float3 p, Float iTime) noexcept {
34 | return min(100.f - length(p), abs(flame(p, iTime)));
35 | };
36 |
37 | Callable raymarch = [&](Float3 org, Float3 dir, Float iTime) noexcept {
38 | static constexpr auto eps = 0.02f;
39 | Var d = 0.0f;
40 | Var glow = 0.0f;
41 | Var p = org;
42 | Var glowed = false;
43 |
44 | for (int i = 0; i < 64; i++) {
45 | d = scene(p, iTime) + eps;
46 | p += d * dir;
47 | if_(d > eps, [&] {
48 | glowed = glowed | flame(p, iTime) < .0f;
49 | glow = ite(glowed, static_cast(i) / 64.0f, glow);
50 | });
51 | }
52 | return make_float4(p, glow);
53 | };
54 |
55 | toy.run([&](Float2 fragCoord, Float2 iResolution, Float iTime, Float4 iMouse) noexcept {
56 | Var v = 2.0f * fragCoord / iResolution - 1.0f;
57 | v.x *= iResolution.x / iResolution.y;
58 |
59 | static constexpr auto org = float3(0.f, -2.f, 4.f);
60 | Var dir = normalize(make_float3(v.x * 1.6f, -v.y, -1.5f));
61 |
62 | Var p = raymarch(org, dir, iTime);
63 | Var glow = p.w;
64 | Var col = lerp(float3(1.f, .5f, .1f), float3(0.1f, .5f, 1.f), p.y * .02f + .4f);
65 | return lerp(float3(0.f), col, pow(glow * 2.f, 4.f));
66 | });
67 | }
68 |
--------------------------------------------------------------------------------
/src/apps/fractal_pyramid.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/25.
3 | //
4 |
5 | #include
6 |
7 | using namespace luisa;
8 | using namespace luisa::compute;
9 |
10 | // Credit: https://www.shadertoy.com/view/tsXBzS
11 | int main(int argc, char *argv[]) {
12 |
13 | gui::ShaderToy toy{argc, argv};
14 |
15 | Callable palette = [](Float d) noexcept {
16 | return lerp(float3(0.2f, 0.7f, 0.9f), float3(1.0f, 0.0f, 1.0f), d);
17 | };
18 |
19 | Callable rotate = [](Float2 p, Float a) noexcept {
20 | Var c = cos(a);
21 | Var s = sin(a);
22 | return make_float2x2(c, -s, s, c) * p;
23 | };
24 |
25 | Callable map = [&rotate](Float3 p, Float time) noexcept {
26 | for (auto i = 0u; i < 8u; i++) {
27 | Var t = time * 0.2f;
28 | p = make_float3(rotate(p.xz(), t), p.y).xzy();
29 | p = make_float3(rotate(p.xy(), t * 1.89f), p.z);
30 | p = make_float3(abs(p.x) - 0.5f, p.y, abs(p.z) - 0.5f);
31 | }
32 | return dot(sign(p), p) * 0.2f;
33 | };
34 |
35 | Callable rm = [&map, &palette](Float3 ro, Float3 rd, Float time) noexcept {
36 | Var t = 0.0f;
37 | Var col = make_float3(0.0f);
38 | Var d = 0.0f;
39 | for (auto i : range(64)) {
40 | Var p = ro + rd * t;
41 | d = map(p, time) * 0.5f;
42 | if_(d < 0.02f | d > 100.0f, [] { break_(); });
43 | col += palette(length(p) * 0.1f) / (400.0f * d);
44 | t += d;
45 | }
46 | return make_float4(col, 1.0f / (d * 100.0f));
47 | };
48 |
49 | toy.run([&](Float2 xy, Float2 resolution, Float time, Float4) noexcept {
50 | Var uv = (xy - resolution * 0.5f) / min(resolution.x, resolution.y);
51 | Var ro = make_float3(rotate(make_float2(0.0f, -50.0f), time), 0.0f).xzy();
52 | Var cf = normalize(-ro);
53 | Var cs = normalize(cross(cf, make_float3(0.0f, 1.0f, 0.0f)));
54 | Var cu = normalize(cross(cf, cs));
55 | Var uuv = ro + cf * 3.0f + uv.x * cs + uv.y * cu;
56 | Var rd = normalize(uuv - ro);
57 | return rm(ro, rd, time).xyz();
58 | });
59 | }
60 |
--------------------------------------------------------------------------------
/src/apps/heartwing_angel.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/25.
3 | //
4 |
5 | #include
6 |
7 | using namespace luisa;
8 | using namespace luisa::compute;
9 |
10 | // Credit: https://www.shadertoy.com/view/4l23zc
11 | int main(int argc, char *argv[]) {
12 |
13 | gui::ShaderToy toy{argc, argv};
14 |
15 | Callable JuliaFractal = [](Float2 c, Float2 c2, Float animparam, Float anim2) noexcept {
16 | Var z = c;
17 | Var mean = 0.0f;
18 | for (int i = 0; i < 64; i++) {
19 | Var a = make_float2(z.x, abs(z.y));
20 | Var b = atan2(a.y * (0.99f + animparam * 9.0f), a.x + .110765432f + animparam);
21 | b = ite(b > 0.0f, b - 6.303431307f + animparam * 3.1513f, b);
22 | z = make_float2(log(length(a * (0.98899f - (animparam * 2.70f * anim2)))), b) + c2;
23 | if (i > 0) { mean += length(z / a * b); }
24 | mean += a.x - (b * 77.0f / length(a * b));
25 | mean = clamp(mean, 111.0f, 99999.0f);
26 | }
27 | mean /= 131.21f;
28 | Var ci = 1.0f - fract(log2(.5f * log2(mean / (0.57891895f - abs(animparam * 141.0f)))));
29 | return make_float3(.5f + .5f * cos(6.f * ci + 0.0f),
30 | .5f + .75f * cos(6.f * ci + 0.14f),
31 | .5f + .5f * cos(6.f * ci + 0.7f));
32 | };
33 |
34 | toy.run([&](Float2 fragCoord, Float2 iResolution, Float iTime, Float4 iMouse) noexcept {
35 | static constexpr auto timeVal = 56.48f - 20.1601f;
36 | static constexpr auto rot = 3.141592654f * 0.5f;
37 | Var animWings = 0.004f * cos(iTime * 0.5f);
38 | Var animFlap = 0.011f * sin(iTime * 1.0f);
39 | Var uv = fragCoord - iResolution * .5f;
40 | uv /= iResolution.x * 1.5113f * abs(sin(timeVal));
41 | uv.y -= animWings * 5.0f;
42 | Var tuv = uv * 125.0f;
43 | uv.x = tuv.x * cos(rot) - tuv.y * sin(rot);
44 | uv.y = 1.05f * tuv.x * sin(rot) + tuv.y * cos(rot);
45 | Var juliax = tan(timeVal) * 0.011f + 0.02f / (fragCoord.y * 0.19531f * (1.0f - animFlap));
46 | Var juliay = cos(timeVal * 0.213f) * (0.022f + animFlap) + 5.66752f - (juliax * 1.5101f);
47 | Var tapU = 25.5f / iResolution.x;
48 | Var tapV = 25.5f / iResolution.y;
49 | Var color = JuliaFractal(uv + float2(0.0f), make_float2(juliax, juliay), animWings, animFlap);
50 | color += JuliaFractal(uv + make_float2(tapU, tapV), make_float2(juliax, juliay), animWings, animFlap);
51 | color += JuliaFractal(uv + make_float2(-tapU, -tapV), make_float2(juliax, juliay), animWings, animFlap);
52 | color *= 0.3333f;
53 | color = float3(1.0f) - color.zyx();
54 | return color;
55 | });
56 | }
57 |
--------------------------------------------------------------------------------
/src/apps/protean_clouds.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/25.
3 | //
4 |
5 | #include
6 |
7 | using namespace luisa;
8 | using namespace luisa::compute;
9 |
10 | // Credit: https://www.shadertoy.com/view/3l23Rh
11 | int main(int argc, char *argv[]) {
12 |
13 | gui::ShaderToy toy{argc, argv};
14 |
15 | Callable rot = [](Float a) noexcept {
16 | Var c = cos(a);
17 | Var s = sin(a);
18 | return make_float2x2(c, -s, s, c);
19 | };
20 |
21 | static constexpr auto m3 = transpose(make_float3x3(
22 | 0.33338f, 0.56034f, -0.71817f,
23 | -0.87887f, 0.32651f, -0.15323f,
24 | 0.15162f, 0.69596f, 0.61339f))
25 | * 1.93f;
26 |
27 | Callable mag2 = [](Float2 p) noexcept { return dot(p, p); };
28 | Callable linstep = [](Float mn, Float mx, Float x) noexcept { return clamp((x - mn) / (mx - mn), 0.f, 1.f); };
29 |
30 | Callable disp = [](Float t) noexcept {
31 | return make_float2(sin(t * 0.22f) * 1.f, cos(t * 0.175f) * 1.f) * 2.f;
32 | };
33 |
34 | Callable map = [&](Float3 p, Float iTime, Float prm1, Float2 bsMo) noexcept {
35 | Var p2 = p;
36 | p2 = make_float3(p2.xy() - disp(p.z).xy(), p2.z);
37 | p = make_float3(rot(sin(p.z + iTime) * (0.1f + prm1 * 0.05f) + iTime * 0.09f) * p.xy(), p.z);
38 | Var cl = mag2(p2.xy());
39 | Var d = 0.0f;
40 | p *= .61f;
41 | Var z = 1.f;
42 | Var trk = 1.f;
43 | Var dspAmp = 0.1f + prm1 * 0.2f;
44 | for (int i = 0; i < 5; i++) {
45 | p += sin(p.zxy() * 0.75f * trk + iTime * trk * .8f) * dspAmp;
46 | d -= abs(dot(cos(p), sin(p.yzx())) * z);
47 | z *= 0.57f;
48 | trk *= 1.4f;
49 | p = m3 * p;
50 | }
51 | d = abs(d + prm1 * 3.f) + prm1 * .3f - 2.5f + bsMo.y;
52 | return make_float2(d + cl * .2f + 0.25f, cl);
53 | };
54 |
55 | Callable render = [&](Float3 ro, Float3 rd, Float time, Float iTime, Float prm1, Float2 bsMo) noexcept {
56 | static constexpr auto ldst = 8.f;
57 | Var rez = make_float4(0.0f);
58 | Var lpos = make_float3(disp(time + ldst) * 0.5f, time + ldst);
59 | Var t = 1.5f;
60 | Var fogT = 0.f;
61 | for (auto i : range(130)) {
62 |
63 | if_(rez.w > 0.99f, [] { break_(); });
64 |
65 | Var pos = ro + t * rd;
66 | Var mpv = map(pos, iTime, prm1, bsMo);
67 | Var den = clamp(mpv.x - 0.3f, 0.f, 1.f) * 1.12f;
68 | Var dn = clamp((mpv.x + 2.f), 0.f, 3.f);
69 |
70 | Var col = make_float4(0.0f);
71 | if_(mpv.x > 0.6f, [&] {
72 | col = make_float4(sin(float3(5.f, 0.4f, 0.2f) + mpv.y * 0.1f + sin(pos.z * 0.4f) * 0.5f + 1.8f) * 0.5f + 0.5f, 0.08f);
73 | col *= den * den * den;
74 | col = make_float4(col.xyz() * linstep(4.f, -2.5f, mpv.x) * 2.3f, col.w);
75 | Var dif = clamp((den - map(pos + .8f, iTime, prm1, bsMo).x) / 9.f, 0.001f, 1.f);
76 | dif += clamp((den - map(pos + .35f, iTime, prm1, bsMo).x) / 2.5f, 0.001f, 1.f);
77 | col = make_float4(col.xyz() * den * (float3(0.005f, .045f, .075f) + 1.5f * float3(0.033f, 0.07f, 0.03f) * dif), col.w);
78 | });
79 |
80 | Var fogC = exp(t * 0.2f - 2.2f);
81 | col += float4(0.06f, 0.11f, 0.11f, 0.1) * clamp(fogC - fogT, 0.f, 1.f);
82 | fogT = fogC;
83 | rez = rez + col * (1.f - rez.w);
84 | t += clamp(0.5f - dn * dn * .05f, 0.09f, 0.3f);
85 | }
86 | return clamp(rez, 0.0f, 1.0f);
87 | };
88 |
89 | Callable getsat = [](Float3 c) noexcept {
90 | Var mi = min(min(c.x, c.y), c.z);
91 | Var ma = max(max(c.x, c.y), c.z);
92 | return (ma - mi) / (ma + 1e-7f);
93 | };
94 |
95 | //from my "Will it blend" shader (https://www.shadertoy.com/view/lsdGzN)
96 | Callable iLerp = [&](Float3 a, Float3 b, Float x) noexcept {
97 | Var ic = lerp(a, b, x) + float3(1e-6f, 0.f, 0.f);
98 | Var sd = abs(getsat(ic) - lerp(getsat(a), getsat(b), x));
99 | Var dir = normalize(make_float3(2.f * ic.x - ic.y - ic.z, 2.f * ic.y - ic.x - ic.z, 2.f * ic.z - ic.y - ic.x));
100 | Var lgt = dot(float3(1.0f), ic);
101 | Var ff = dot(dir, normalize(ic));
102 | ic += 1.5f * dir * sd * ff * lgt;
103 | return clamp(ic, 0.f, 1.f);
104 | };
105 |
106 | toy.run([&](Float2 fragCoord, Float2 iResolution, Float iTime, Float4 iMouse) noexcept {
107 | Var q = fragCoord.xy() / iResolution.xy();
108 | Var p = (fragCoord.xy() - 0.5f * iResolution.xy()) / iResolution.y;
109 | Var bsMo = (iMouse.xy() - 0.5f * iResolution.xy()) / iResolution.y;
110 |
111 | static constexpr auto dspAmp = .85f;
112 | static constexpr auto tgtDst = 3.5f;
113 |
114 | Var time = iTime * 3.f;
115 | Var ro = make_float3(0.0f, 0.0f, time);
116 |
117 | ro += make_float3(sin(iTime) * 0.5f, sin(iTime * 1.f) * 0.f, 0.0f);
118 | ro = make_float3(ro.xy() + disp(ro.z) * dspAmp, ro.z);
119 |
120 | Var target = normalize(ro - make_float3(disp(time + tgtDst) * dspAmp, time + tgtDst));
121 | ro.x -= bsMo.x * 2.f;
122 | Var rightdir = normalize(cross(target, float3(0.0f, 1.0f, 0.0f)));
123 | Var updir = normalize(cross(rightdir, target));
124 | rightdir = normalize(cross(updir, target));
125 | Var rd = normalize((p.x * rightdir + p.y * updir) * 1.f - target);
126 | rd = make_float3(rot(-disp(time + 3.5f).x * 0.2f + bsMo.x) * rd.xy(), rd.z);
127 | Var prm1 = smoothstep(-0.4f, 0.4f, sin(iTime * 0.3f));
128 | Var scn = render(ro, rd, time, iTime, prm1, bsMo);
129 | Var col = scn.xyz();
130 | col = iLerp(col.zyx(), col.xyz(), clamp(1.f - prm1, 0.05f, 1.f));
131 | col = pow(col, float3(.55f, 0.65f, 0.6)) * float3(1.f, .97f, .9f);
132 | return col * pow(16.0f * q.x * q.y * (1.0f - q.x) * (1.0f - q.y), 0.12f) * 0.7f + 0.3f;//Vign
133 | });
134 | }
135 |
--------------------------------------------------------------------------------
/src/apps/rainbow_spaghetti.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Yawanari.fst on 2021/6/28.
3 | // Credit: https://www.shadertoy.com/view/lsjGRV
4 |
5 | #include
6 |
7 | using namespace luisa;
8 | using namespace luisa::compute;
9 |
10 | int main(int argc, char *argv[]) {
11 |
12 | static constexpr auto i3 = 0.5773502691896258f;
13 | static constexpr auto r = 0.40824829046386302f;
14 |
15 | static constexpr auto i = 0.3333333333333333f;
16 | static constexpr auto j = 0.6666666666666666f;
17 |
18 | static constexpr auto lrad = 0.015f;
19 | static constexpr auto trad = 0.06f;
20 | static constexpr auto fogv = 0.025f;
21 |
22 | static constexpr auto dmax = 20.0f;
23 | static constexpr auto rayiter = 60;
24 |
25 | static constexpr auto wrap = 64.0f;
26 |
27 | auto L = normalize(float3(0.1f, 1.0f, 0.5f));
28 |
29 | static constexpr auto axis = float3(1.0f, 1.0f, 0.0f);
30 | static constexpr auto tgt = float3(1.0f, 1.7f, 1.1f);
31 | static constexpr auto cpos = tgt + axis;
32 | static constexpr auto vel = 0.2f * axis;
33 | static constexpr auto key_G = 71.5f / 256.0f;
34 |
35 | Callable hash = [](Float3 x) {
36 | return fract(87.3f * dot(x, float3(0.1f, 0.9f, 0.7f)));
37 | };
38 |
39 | Callable line = [](Float3 p0, Float3 p1, Float3 p) {
40 | Var dp0 = p - p0;
41 | Var dp10 = p1 - p0;
42 | Var u = clamp(dot(dp0, dp10) / dot(dp10, dp10), -5.0f, 5.0f);
43 | return distance(lerp(p0, p1, u), p) - 0.5f * lrad;
44 | };
45 |
46 | Callable opU = [](Float2 a, Float2 b) {
47 | return ite(a.x < b.x, a, b);
48 | };
49 |
50 | Callable hueOf = [](Float3 pos) {
51 | return cos(2.0f * dot(2.0f * pos, make_float3(0.3f, 0.7f, 0.4f))) * 0.49f + 0.5f;
52 | };
53 |
54 | Callable round2 = [](Float3 x, Float3 a) {
55 | return 2.0f * floor(0.5f * (x + 1.0f - a)) + a;
56 | };
57 |
58 | Callable pdist = [](Float3 p, Float3 q) {
59 | Var pq = p - q;
60 | return make_float4(q, dot(pq, pq));
61 | };
62 |
63 | Callable pselect = [](Float4 a, Float4 b) {
64 | return ite(a.w < b.w, a, b);
65 | };
66 |
67 | Callable torus = [](Float3 a, Float3 b, Float3 pos) {
68 | pos -= 0.5f * (a + b);
69 | Var n = normalize(b - a);
70 | return distance(pos, r * normalize(pos - n * dot(n, pos))) - trad;
71 | };
72 |
73 | Callable permute = [](Float3 e, Float3 f, Float3 g, Float3 h, Float p) {
74 | return ite(p < i,
75 | make_float4x4(make_float4(e, 1.0f), make_float4(f, 1.0f), make_float4(g, 1.0f), make_float4(h, 1.0f)),
76 | ite(p < j, make_float4x4(make_float4(e, 1.0f), make_float4(g, 1.0f), make_float4(f, 1.0f), make_float4(h, 1.0f)),
77 | make_float4x4(make_float4(e, 1.0f), make_float4(h, 1.0f), make_float4(f, 1.0f), make_float4(g, 1.0f))));
78 | };
79 |
80 | Callable randomBasis = [](Float p) {
81 | return ite(p < i, make_float3(1.0f, 0.0f, 0.0f),
82 | ite(p < j, make_float3(0.0f, 1.0f, 0.0f), make_float3(0.0f, 0.0f, 1.0f)));
83 | };
84 |
85 | Callable randomPerp = [](Float3 v, Float p) {
86 | return ite(v.x > 0.0f, ite(p < 0.5f, make_float3(0.0f, 1.0f, 0.0f), make_float3(0.0f, 0.0f, 1.0f)),
87 | ite(v.y > 0.0f, ite(p < 0.5f, make_float3(1.0f, 0.0f, 0.0f), make_float3(0.0f, 0.0f, 1.0f)),
88 | ite(p < 0.5f, make_float3(1.0f, 0.0f, 0.0f), make_float3(0.0f, 1.0f, 0.0f))));
89 | };
90 |
91 | Callable map = [&](Float3 pos, Float iTime) {
92 | Var orig = pos;
93 | pos = mod(pos + mod(iTime * vel, wrap), wrap);
94 | Var a = round2(pos, float3(1.0f));
95 | Var h = round2(pos, float3(0.0f));
96 |
97 | Var b = make_float3(a.x, h.y, h.z);
98 | Var c = make_float3(h.x, a.y, h.z);
99 | Var d = make_float3(h.x, h.y, a.z);
100 | Var e = make_float3(h.x, a.y, a.z);
101 | Var f = make_float3(a.x, h.y, a.z);
102 | Var g = make_float3(a.x, a.y, h.z);
103 |
104 | // o is the closest octahedron center
105 | Var o = pselect(pselect(pdist(pos, a), pdist(pos, b)),
106 | pselect(pdist(pos, c), pdist(pos, d)))
107 | .xyz();
108 |
109 | // t is the closest tetrahedron center
110 | Var t = floor(pos) + 0.5f;
111 |
112 | // normal points towards o
113 | // so bd is positive inside octahedron, negative inside tetrahedron
114 | Var omt = o.xyz() - t.xyz();
115 | Var bd = dot(pos - o.xyz(), omt * 2.0f * i3) + i3;
116 |
117 | Var m = permute(e, f, g, h, hash(mod(t, wrap)));
118 |
119 | Var t1 = torus(m[0].xyz(), m[1].xyz(), pos);
120 | Var t2 = torus(m[2].xyz(), m[3].xyz(), pos);
121 |
122 | Var p = hash(mod(o, wrap));
123 | Var b1 = randomBasis(fract(85.17f * p));
124 | Var b2 = randomPerp(b1, fract(63.61f * p + 4.2f));
125 | Var b3 = randomPerp(b1, fract(43.79f * p + 8.3f));
126 |
127 | Var po = pos - o;
128 |
129 | Var o1 = torus(b1, b2, po);
130 | Var o2 = torus(b1, -b2, po);
131 | Var o3 = torus(-b1, b3, po);
132 | Var o4 = torus(-b1, -b3, po);
133 |
134 | Var noodle = make_float2(min(max(bd, min(t1, t2)),
135 | max(-bd, min(min(o1, o2), min(o3, o4)))),
136 | hueOf(orig + 0.5f * vel * iTime));
137 |
138 | #define SHOW_GRIDS 1
139 | #if SHOW_GRIDS
140 | Var dline = line(e, f, pos);
141 | dline = min(dline, line(e, g, pos));
142 | dline = min(dline, line(e, h, pos));
143 | dline = min(dline, line(f, g, pos));
144 | dline = min(dline, line(f, h, pos));
145 | dline = min(dline, line(g, h, pos));
146 | Var grid = make_float2(dline, 2.0f);
147 | noodle.x += 0.1f * trad;
148 | noodle.y = hash(mod(ite(bd < 0.0f, t, o), wrap));
149 | noodle = opU(grid, noodle);
150 | #endif
151 | return noodle;
152 | };
153 |
154 | Callable hue = [](Float h) {
155 | Var c = mod(h * 6.0f + float3(2.0f, 0.0f, 4.0f), 6.0f);
156 | return ite(h > 1.0f, float3(0.5f), clamp(min(c, -c + 4.0f), 0.0f, 1.0f));
157 | };
158 |
159 | Callable castRay = [&map](Float3 ro, Float3 rd, Float maxd, Float iTime) {
160 | static constexpr auto precis = 0.0001f;
161 | Var h = precis * 2.0f;
162 | Var t = 0.0f;
163 | Var m = -1.0f;
164 | for (auto i = 0; i < rayiter; i++) {
165 | if_(!(abs(h) < precis | t > maxd), [&] {
166 | t += h;
167 | Var res = map(ro + rd * t, iTime);
168 | h = res.x;
169 | m = res.y;
170 | });
171 | }
172 | return make_float2(t, m);
173 | };
174 |
175 | Callable calcNormal = [&map](Float3 pos, Float iTime) {
176 | static constexpr auto eps = float3(0.0001f, 0.0f, 0.0f);
177 | Var nor = make_float3(
178 | map(pos + eps.xyy(), iTime).x - map(pos - eps.xyy(), iTime).x,
179 | map(pos + eps.yxy(), iTime).x - map(pos - eps.yxy(), iTime).x,
180 | map(pos + eps.yyx(), iTime).x - map(pos - eps.yyx(), iTime).x);
181 | return normalize(nor);
182 | };
183 |
184 | Callable shade = [&hue, &calcNormal, &castRay, &L](Float3 ro, Float3 rd, Float iTime) {
185 | Var tm = castRay(ro, rd, dmax, iTime);
186 | Var ret = float3(1.0f);
187 | if_(tm.y >= 0.0f, [&] {
188 | Var n = calcNormal(ro + tm.x * rd, iTime);
189 | Var fog = exp(-tm.x * tm.x * fogv);
190 | Var color = hue(tm.y) * 0.55f + 0.45f;
191 | Var diffamb = (0.5f * dot(n, L) + 0.5f) * color;
192 | Var R = 2.0f * n * dot(n, L) - L;
193 | Var spec = 0.2f * pow(clamp(-dot(R, rd), 0.0f, 1.0f), 6.0f);
194 | ret = fog * (diffamb + spec);
195 | });
196 | return ret;
197 | };
198 |
199 | gui::ShaderToy toy{argc, argv};
200 | toy.run([&](Float2 fragCoord, Float2 iResolution, Float iTime, Float4 iMouse) {
201 | static constexpr auto yscl = 720.0f;
202 | static constexpr auto f = 900.0f;
203 | static constexpr auto up = float3(0.0f, 1.0f, 0.0f);
204 |
205 | Var uv = (fragCoord - 0.5f * iResolution) * yscl / iResolution.y;
206 |
207 | Var rz = normalize(tgt - cpos);
208 | Var rx = normalize(cross(rz, up));
209 | Var ry = cross(rx, rz);
210 |
211 | Var thetax = 0.0f;
212 | Var thetay = 0.0f;
213 |
214 | if_(max(iMouse.x, iMouse.y) > 20.0f, [&] {
215 | thetax = (iMouse.y - 0.5f * iResolution.y) * 3.14f / iResolution.y;
216 | thetay = (iMouse.x - 0.5f * iResolution.x) * -6.28f / iResolution.x;
217 | });
218 |
219 | Var cx = cos(thetax);
220 | Var sx = sin(thetax);
221 | Var cy = cos(thetay);
222 | Var sy = sin(thetay);
223 |
224 | Var Rx = make_float3x3(1.0f, 0.0f, 0.0f,
225 | 0.0f, cx, sx,
226 | 0.0f, -sx, cx);
227 | Var Ry = make_float3x3(cy, 0.0f, -sy,
228 | 0.0f, 1.0f, 0.0f,
229 | sy, 0.0f, cy);
230 | Var R = make_float3x3(rx, ry, rz);
231 | Var Rt = make_float3x3(rx.x, ry.x, rz.x,
232 | rx.y, ry.y, rz.y,
233 | rx.z, ry.z, rz.z);
234 |
235 | Var rd = R * Rx * Ry * normalize(make_float3(uv, f));
236 | Var ro = tgt + R * Rx * Ry * Rt * (cpos - tgt);
237 |
238 | return shade(ro, rd, iTime);
239 | });
240 | }
241 |
--------------------------------------------------------------------------------
/src/apps/sdf_renderer.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/25.
3 | //
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | using namespace luisa;
10 | using namespace luisa::compute;
11 |
12 | // Credit: https://github.com/taichi-dev/taichi/blob/master/examples/rendering/sdf_renderer.py
13 | int main(int argc, char *argv[]) {
14 |
15 | static constexpr auto max_ray_depth = 6;
16 | static constexpr auto eps = 1e-4f;
17 | static constexpr auto inf = 1e10f;
18 | static constexpr auto fov = 0.23f;
19 | static constexpr auto dist_limit = 100.0f;
20 | static constexpr auto camera_pos = make_float3(0.0f, 0.32f, 3.7f);
21 | static constexpr auto light_pos = make_float3(-1.5f, 0.6f, 0.3f);
22 | static constexpr auto light_normal = make_float3(1.0f, 0.0f, 0.0f);
23 | static constexpr auto light_radius = 2.0f;
24 |
25 | Callable intersect_light = [](Float3 pos, Float3 d) noexcept {
26 | auto cos_w = dot(-d, light_normal);
27 | auto dist = dot(d, light_pos - pos);
28 | auto dist_to_light = def(inf);
29 | $if(cos_w > 0.0f & dist > 0.0f) {
30 | auto D = dist / cos_w;
31 | auto dist_to_center = distance_squared(light_pos, pos + D * d);
32 | $if(dist_to_center < light_radius * light_radius) {
33 | dist_to_light = D;
34 | };
35 | };
36 | return dist_to_light;
37 | };
38 |
39 | Callable tea = [](UInt v0, UInt v1) noexcept {
40 | Var s0 = 0u;
41 | for (auto n = 0u; n < 4u; n++) {
42 | s0 += 0x9e3779b9u;
43 | v0 += ((v1 << 4) + 0xa341316cu) ^ (v1 + s0) ^ ((v1 >> 5u) + 0xc8013ea4u);
44 | v1 += ((v0 << 4) + 0xad90777du) ^ (v0 + s0) ^ ((v0 >> 5u) + 0x7e95761eu);
45 | }
46 | return v0;
47 | };
48 |
49 | Callable rand = [](UInt &state) noexcept {
50 | constexpr auto lcg_a = 1664525u;
51 | constexpr auto lcg_c = 1013904223u;
52 | state = lcg_a * state + lcg_c;
53 | return cast(state & 0x00ffffffu) * (1.0f / static_cast(0x01000000u));
54 | };
55 |
56 | Callable out_dir = [&rand](Float3 n, UInt &seed) noexcept {
57 | auto u = def(1.0f, 0.0f, 0.0f);
58 | $if(abs(n.y) < 1.0f - eps) {
59 | u = normalize(cross(n, make_float3(0.0f, 1.0f, 0.0f)));
60 | };
61 | auto v = cross(n, u);
62 | auto phi = 2.0f * std::numbers::pi_v * rand(seed);
63 | auto ay = sqrt(rand(seed));
64 | auto ax = sqrt(1.0f - ay * ay);
65 | return ax * (cos(phi) * u + sin(phi) * v) + ay * n;
66 | };
67 |
68 | Callable make_nested = [](Float f) noexcept {
69 | f *= 40.0f;
70 | auto i = f.cast();
71 | $if(f < 0.0f) {
72 | f = ite(i % 2 == 0, floor(f) + 1.0f - f, f - floor(f));
73 | };
74 | return (f - 0.2f) * (1.0f / 40.0f);
75 | };
76 |
77 | Callable sdf = [&make_nested](Float3 o) noexcept {
78 | auto wall = min(o.y + 0.1f, o.z + 0.4f);
79 | auto sphere = distance(o, make_float3(0.0f, 0.35f, 0.0f)) - 0.36f;
80 | auto q = abs(o - make_float3(0.8f, 0.3f, 0.0f)) - 0.3f;
81 | auto box = length(max(q, 0.0f)) + min(max(max(q.x, q.y), q.z), 0.0f);
82 | auto O = o - make_float3(-0.8f, 0.3f, 0.0f);
83 | auto d = make_float2(length(make_float2(O.x, O.z)) - 0.3f, abs(O.y) - 0.3f);
84 | auto cylinder = min(max(d.x, d.y), 0.0f) + length(max(d, 0.0f));
85 | auto geometry = make_nested(min(min(sphere, box), cylinder));
86 | auto g = max(geometry, -0.32f + o.y * 0.6f + o.z * 0.8f);
87 | return min(wall, g);
88 | };
89 |
90 | Callable ray_march = [&sdf](Float3 p, Float3 d) noexcept {
91 | auto dist = def(0.0f);
92 | $for(j, 100) {
93 | auto s = sdf(p + dist * d);
94 | $if(s <= 1e-6f | dist >= inf) { $break; };
95 | dist += s;
96 | };
97 | return min(dist, inf);
98 | };
99 |
100 | Callable sdf_normal = [&sdf](Float3 p) noexcept {
101 | auto d = 1e-3f;
102 | auto n = def();
103 | auto sdf_center = sdf(p);
104 | for (auto i = 0; i < 3; i++) {
105 | auto inc = p;
106 | inc[i] += d;
107 | n[i] = (1.0f / d) * (sdf(inc) - sdf_center);
108 | }
109 | return normalize(n);
110 | };
111 |
112 | Callable next_hit = [&ray_march, &sdf_normal](Float &closest, Float3 &normal, Float3 &c, Float3 pos, Float3 d) noexcept {
113 | closest = inf;
114 | normal = make_float3();
115 | c = make_float3();
116 | auto ray_march_dist = ray_march(pos, d);
117 | $if(ray_march_dist < min(dist_limit, closest)) {
118 | closest = ray_march_dist;
119 | auto hit_pos = pos + d * closest;
120 | normal = sdf_normal(hit_pos);
121 | auto t = cast((hit_pos.x + 10.0f) * 1.1f + 0.5f) % 3;
122 | c = make_float3(0.4f) + make_float3(0.3f, 0.2f, 0.3f) * ite(t == make_int3(0, 1, 2), 1.0f, 0.0f);
123 | };
124 | };
125 |
126 | gui::ShaderToy toy{argc, argv};
127 | auto accum = toy.device().create_image(PixelStorage::FLOAT4, toy.size());
128 | auto clear = toy.device().compile<2>([&] {
129 | accum.write(dispatch_id().xy(), make_float4());
130 | });
131 | toy.stream() << clear().dispatch(toy.size());
132 |
133 | toy.run([&](Float2 fragCoord, Float2 iResolution, Float iTime, Float4 iMouse) noexcept {
134 | auto aspect_ratio = iResolution.x / iResolution.y;
135 | auto pos = def(camera_pos);
136 | auto seed = tea(fragCoord.x.cast(), fragCoord.y.cast()) + cast(iTime * 1e4f);
137 | auto ux = rand(seed);
138 | auto uy = rand(seed);
139 | auto d = make_float3(
140 | 2.0f * fov * (fragCoord + make_float2(ux, uy)) / iResolution.y.cast() - fov * make_float2(aspect_ratio, 1.0f) - 1e-5f,
141 | -1.0f);
142 | d = normalize(d);
143 | auto throughput = def(1.0f, 1.0f, 1.0f);
144 | auto hit_light = def(0.0f);
145 | $for(depth, max_ray_depth) {
146 | auto closest = def(0.0f);
147 | auto normal = def();
148 | auto c = def();
149 | next_hit(closest, normal, c, pos, d);
150 | auto dist_to_light = intersect_light(pos, d);
151 | $if(dist_to_light < closest) {
152 | hit_light = 1.0f;
153 | $break;
154 | };
155 | $if(length_squared(normal) == 0.0f) { $break; };
156 | auto hit_pos = pos + closest * d;
157 | d = out_dir(normal, seed);
158 | pos = hit_pos + 1e-4f * d;
159 | throughput *= c;
160 | };
161 | auto old = accum.read(make_uint2(fragCoord));
162 | auto new_col = lerp(old.xyz(), throughput * hit_light, 1.f / (old.w + 1.f));
163 | accum.write(make_uint2(fragCoord), make_float4(new_col, old.w + 1.f));
164 | return sqrt(new_col * 2.5f);
165 | });
166 | }
167 |
--------------------------------------------------------------------------------
/src/apps/seascape.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by AirGuanZ on 2021/11/13.
3 | //
4 |
5 | #include
6 | #include
7 |
8 | using namespace luisa;
9 | using namespace compute;
10 |
11 | // Credit: https://www.shadertoy.com/view/Ms2SD1
12 | int main(int argc, char *argv[]) {
13 |
14 | constexpr int NUM_STEPS = 8;
15 | constexpr float PI = 3.14159265f;
16 |
17 | constexpr int ITER_GEOMETRY = 3;
18 | constexpr int ITER_FRAGMENT = 5;
19 |
20 | constexpr float SEA_HEIGHT = 0.6f;
21 | constexpr float SEA_CHOPPY = 4.0f;
22 | constexpr float SEA_SPEED = 0.8f;
23 | constexpr float SEA_FREQ = 0.16f;
24 | constexpr float3 SEA_BASE = float3(0.0f, 0.09f, 0.18f);
25 | constexpr float3 SEA_WATER_COLOR = float3(0.8f, 0.9f, 0.6f) * 0.6f;
26 |
27 | Callable fromEuler = [](Float3 ang) {
28 | Float2 a1 = make_float2(sin(ang.x), cos(ang.x));
29 | Float2 a2 = make_float2(sin(ang.y), cos(ang.y));
30 | Float2 a3 = make_float2(sin(ang.z), cos(ang.z));
31 | Float3x3 m;
32 | m[0] = make_float3(a1.y * a3.y + a1.x * a2.x * a3.x, a1.y * a2.x * a3.x + a3.y * a1.x, -a2.y * a3.x);
33 | m[1] = make_float3(-a2.y * a1.x, a1.y * a2.y, a2.x);
34 | m[2] = make_float3(a3.y * a1.x * a2.x + a1.y * a3.x, a1.x * a3.x - a1.y * a3.y * a2.x, a2.y * a3.y);
35 | return m;
36 | };
37 |
38 | Callable hash = [](Float2 p) {
39 | Float h = dot(p, make_float2(127.1f, 311.7f));
40 | Float f = fract(sin(h) * 43758.5453123f);
41 | return f - floor(f);
42 | };
43 |
44 | Callable noise = [&](Float2 p) {
45 | Float2 i = floor(p);
46 | Float2 f = p - i;
47 | Float2 u = f * f * (3.0f - 2.0f * f);
48 | return -1.0f + 2.0f * lerp(
49 | lerp(hash(i + make_float2(0.0f, 0.0f)), hash(i + make_float2(1.0, 0.0)), u.x),
50 | lerp(hash(i + make_float2(0.0f, 1.0f)), hash(i + make_float2(1.0f, 1.0f)), u.x),
51 | u.y);
52 | };
53 |
54 | Callable reflect = [](Float3 I, Float3 N) noexcept {
55 | return I - 2.0f * dot(N, I) * N;
56 | };
57 |
58 | Callable diffuse = [](Float3 n, Float3 l, Float p) {
59 | return pow(dot(n, l) * 0.4f + 0.6f, p);
60 | };
61 |
62 | Callable specular = [&](Float3 n, Float3 l, Float3 e, Float s) {
63 | Float nrm = (s + 8.0f) / (PI * 8.0f);
64 | return pow(max(dot(reflect(e, n), l), 0.0f), s) * nrm;
65 | };
66 |
67 | Callable getSkyColor = [](Float3 e) {
68 | e.y = (max(e.y, 0.0f) * 0.8f + 0.2f) * 0.8f;
69 | return make_float3(pow(1.0f - e.y, 2.0f), 1.0f - e.y, 0.6f + (1.0f - e.y) * 0.4f) * 1.1f;
70 | };
71 |
72 | Callable seaOctave = [&](Float2 uv, Float choppy) {
73 | uv = uv + noise(uv);
74 | Float2 wv = 1.0f - abs(sin(uv));
75 | Float2 swv = abs(cos(uv));
76 | wv = lerp(wv, swv, wv);
77 | return pow(1.0f - pow(wv.x * wv.y, 0.65f), choppy);
78 | };
79 |
80 | Callable map = [&](Float3 p, Float time) {
81 | Float2x2 octave_m = make_float2x2(1.6f, -1.2f, 1.2f, 1.6f);
82 | Float freq = SEA_FREQ;
83 | Float amp = SEA_HEIGHT;
84 | Float choppy = SEA_CHOPPY;
85 | Float2 uv = p.xz();
86 | uv.x *= 0.75f;
87 | Float h = 0.0f;
88 | for (auto i = 0; i < ITER_GEOMETRY; i++) {
89 | Float d = seaOctave((uv + (1 + time * SEA_SPEED)) * freq, choppy);
90 | d += seaOctave((uv - (1 + time * SEA_SPEED)) * freq, choppy);
91 | h += d * amp;
92 | uv = octave_m * uv;
93 | freq *= 1.9f;
94 | amp *= 0.22f;
95 | choppy = lerp(choppy, 1.0f, 0.2f);
96 | }
97 | return p.y - h;
98 | };
99 |
100 | Callable mapDetailed = [&](Float3 p, Float time) {
101 | Float2x2 octave_m = make_float2x2(1.6f, -1.2f, 1.2f, 1.6f);
102 | Float freq = SEA_FREQ;
103 | Float amp = SEA_HEIGHT;
104 | Float choppy = SEA_CHOPPY;
105 | Float2 uv = p.xz();
106 | uv.x *= 0.75f;
107 | Float h = 0.0f;
108 | for (auto i = 0; i < ITER_FRAGMENT; i++) {
109 | Float d = seaOctave((uv + (1 + time * SEA_SPEED)) * freq, choppy);
110 | d += seaOctave((uv - (1 + time * SEA_SPEED)) * freq, choppy);
111 | h += d * amp;
112 | uv = octave_m * uv;
113 | freq *= 1.9f;
114 | amp *= 0.22f;
115 | choppy = lerp(choppy, 1.0f, 0.2f);
116 | }
117 | return p.y - h;
118 | };
119 |
120 | Callable getSeaColor = [&](Float3 p, Float3 n, Float3 l, Float3 eye, Float3 dist) {
121 | Float fresnel = clamp(1.0f - dot(n, -eye), 0.0f, 1.0f);
122 | fresnel = pow(fresnel, 3.0f) * 0.5f;
123 | Float3 reflected = getSkyColor(reflect(eye, n));
124 | Float3 refracted = make_float3(SEA_BASE.x, SEA_BASE.y, SEA_BASE.z)
125 | + diffuse(n, l, 80.0f) * 0.12f * make_float3(SEA_WATER_COLOR.x, SEA_WATER_COLOR.y, SEA_WATER_COLOR.z);
126 | Float3 color = lerp(refracted, reflected, fresnel);
127 | Float atten = max(1.0f - dot(dist, dist) * 0.001f, 0.0f);
128 | color += make_float3(SEA_WATER_COLOR.x, SEA_WATER_COLOR.y, SEA_WATER_COLOR.z)
129 | * (p.y - SEA_HEIGHT) * 0.18f * atten;
130 | color += make_float3(0.2f * specular(n, l, eye, 60.0f));
131 | return color;
132 | };
133 |
134 | Callable getNormal = [&](Float3 p, Float eps, Float time) {
135 | Float3 n;
136 | n.y = mapDetailed(p, time);
137 | n.x = mapDetailed(make_float3(p.x + eps, p.y, p.z), time) - n.y;
138 | n.z = mapDetailed(make_float3(p.x, p.y, p.z + eps), time) - n.y;
139 | n.y = eps;
140 | return normalize(n);
141 | };
142 |
143 | Callable heightMapTracing = [&](Float3 ori, Float3 dir, Float3 &p, Float time) {
144 | Float tm = 0.0f;
145 | Float tx = 1000.0f;
146 | Float hx = map(ori + dir * tx, time);
147 | $if(hx > 0.0f) {
148 | p = ori + dir * tx;
149 | return tx;
150 | };
151 | Float hm = map(ori + dir * tm, time);
152 | Float tmid = 0.0f;
153 | for (auto i = 0; i < NUM_STEPS; i++) {
154 | tmid = lerp(tm, tx, hm / (hm - hx));
155 | p = ori + dir * tmid;
156 | Float hmid = map(p, time);
157 | $if(hmid < 0.0f) {
158 | tx = tmid;
159 | hx = hmid;
160 | }
161 | $else {
162 | tm = tmid;
163 | hm = hmid;
164 | };
165 | }
166 | };
167 |
168 | Callable getPixel = [&](Float2 coord, Float time, Float2 iResolution) {
169 | Float2 uv = coord / iResolution.xy();
170 | uv = uv * 2.0f - 1.0f;
171 | uv.x *= iResolution.x / iResolution.y;
172 | // ray
173 | Float3 ang = make_float3(sin(time * 3.0f) * 0.1f, sin(time) * 0.2f + 0.3f, time);
174 | Float3 ori = make_float3(0.0f, 3.5f, time * 5.0f);
175 | Float3 dir = normalize(make_float3(uv.xy(), -2.0f));
176 | dir.z += length(uv) * 0.14f;
177 | dir = transpose(fromEuler(ang)) * normalize(dir);
178 | // tracing
179 | Float3 p;
180 | heightMapTracing(ori, dir, p, time);
181 | Float3 dist = p - ori;
182 | Float3 n = getNormal(p, dot(dist, dist) * (0.1f / iResolution.x), time);
183 | Float3 light = normalize(make_float3(0.0f, 1.0f, 0.8f));
184 | // color
185 | return lerp(
186 | getSkyColor(dir),
187 | getSeaColor(p, n, light, dir, dist),
188 | pow(smoothstep(0.0f, -0.02f, dir.y), 0.2f));
189 | };
190 |
191 | gui::ShaderToy toy{argc, argv};
192 | toy.run([&](Float2 fragCoord, Float2 iResolution, Float iTime, Float4 iMouse) {
193 | Float time = iTime * 0.3f + iMouse.x * 0.01f;
194 | std::array offsets = {
195 | make_float2(-0.25f, -0.25f),
196 | make_float2(-0.25f, 0.25f),
197 | make_float2(0.25f, -0.25f),
198 | make_float2(0.25f, 0.25f),
199 | };
200 | auto color = def(make_float3());
201 | for (auto o : offsets) {
202 | color += 0.25f * getPixel(fragCoord + o, time, iResolution);
203 | }
204 | return pow(color, 0.65f);
205 | });
206 | }
207 |
--------------------------------------------------------------------------------
/src/apps/sphere_in_cable.cpp:
--------------------------------------------------------------------------------
1 |
2 | //
3 | // Created by Yawanari.fst on 2021/6/28.
4 | // Credit: https://www.shadertoy.com/view/wlKXWc
5 |
6 | #include
7 |
8 | using namespace luisa;
9 | using namespace luisa::compute;
10 |
11 | struct Ray {
12 | float3 pos;
13 | float3 dir;
14 | };
15 |
16 | LUISA_STRUCT(Ray, pos, dir) {};
17 |
18 | int main(int argc, char *argv[]) {
19 |
20 | static constexpr auto PI = 3.1415926f;
21 | static constexpr auto TAU = PI * 2.0f;
22 | static constexpr auto E = 0.01f;
23 |
24 | Callable rotate2D = [](Float rad) {
25 | Var c = cos(rad);
26 | Var s = sin(rad);
27 | return make_float2x2(c, -s, s, c);
28 | };
29 |
30 | Callable de = [&rotate2D](Float3 p, Float iTime) {
31 | Var d = 100.0f;
32 | Var a = 0.0f;
33 | p = make_float3(p.x, rotate2D(PI / 5.0f) * p.yz());
34 | p.y -= 0.5f;
35 |
36 | //reaction
37 | Var reaction = make_float3(cos(iTime), 0.0f, sin(iTime)) * 3.0f;
38 | p += exp(-length(reaction - p) * 1.0f) * normalize(reaction - p);
39 |
40 | //cables
41 | Var r = atan2(p.z, p.x) * 3.0f;
42 | static constexpr auto iter_count = 50;
43 | for (auto i = 0; i < iter_count; i++) {
44 | r += 0.5f / static_cast(iter_count) * TAU;
45 | Var s = 0.5f + sin(static_cast(i) * 1.618f * TAU) * 0.25f;
46 | s += sin(iTime + static_cast(i)) * 0.1f;
47 | Var q = make_float2(length(p.xz()) + cos(r) * s - 3.0f, p.y + sin(r) * s);
48 | Var dd = length(q) - 0.035f;
49 | a = ite(dd < d, static_cast(i), a);
50 | d = min(d, dd);
51 | }
52 |
53 | // sphere
54 | Var dd = length(p - reaction) - 0.1f;
55 | a = ite(dd < d, 0.0f, a);
56 | d = min(d, dd);
57 |
58 | return make_float2(d, a);
59 | };
60 |
61 | Callable trace = [&](Var ray, Float3 color, Float md, Float iTime) {
62 | Var ad = 0.0f;
63 | Var early_return = false;
64 | for (auto i : range(128)) {
65 | Var o = de(ray.pos, iTime);
66 | if_(o.x < E, [&] {
67 | color = lerp(make_float3(0.1f, 0.1f, 0.5f), make_float3(0.0f, 0.0f, 1.0f), fract(o.y * 1.618f));
68 | color = lerp(make_float3(1.0f, 1.0f, 1.0f), color, step(0.05f, fract(o.y * 1.618f)));
69 | color = lerp(make_float3(0.175f, 0.1f, 0.1f), color, step(0.35f, fract(o.y * 1.618f + 0.9f)));
70 | color *= exp(-i / 128.0f * 15.0f);
71 | early_return = true;
72 | break_();
73 | });
74 | o.x *= 0.6f;
75 | ray.pos += ray.dir * o.x;
76 | ad += o.x;
77 | if_(ad > md, [&] { break_(); });
78 | }
79 | return ite(early_return, color, lerp(float3(0.0f), float3(1.0f), ray.dir.y * ray.dir.y));
80 | };
81 |
82 | gui::ShaderToy toy{argc, argv};
83 | toy.run([&](Float2 fragCoord, Float2 iResolution, Float iTime, Float4 iMouse) {
84 | Var p = (fragCoord * 2.0f - iResolution) / min(iResolution.x, iResolution.y);
85 | Var color = float3(0.0f);
86 |
87 | Var view = float3(0.0f, 0.0f, 10.0f);
88 | Var at = normalize(float3(0.0f, 0.0f, 0.0f) - view);
89 | Var right = normalize(cross(at, float3(0.0f, 1.0f, 0.0f)));
90 | Var up = cross(right, at);
91 | Var focallength = 3.0f;
92 |
93 | Var ray;
94 | ray.pos = view;
95 | ray.dir = normalize(right * p.x + up * p.y + at * focallength);
96 |
97 | color = trace(ray, color, 20.0f, iTime);
98 | return pow(color, float3(0.454545f));
99 | });
100 | }
101 |
--------------------------------------------------------------------------------
/src/apps/star_nest.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/25.
3 | //
4 |
5 | #include
6 |
7 | using namespace luisa;
8 | using namespace luisa::compute;
9 |
10 | // Credit: https://www.shadertoy.com/view/XlfGRj
11 | int main(int argc, char *argv[]) {
12 |
13 | static constexpr auto iterations = 17u;
14 | static constexpr auto formuparam = 0.53f;
15 | static constexpr auto volsteps = 20u;
16 | static constexpr auto stepsize = 0.1f;
17 | static constexpr auto zoom = 0.800f;
18 | static constexpr auto tile = 0.850f;
19 | static constexpr auto speed = 0.010f;
20 | static constexpr auto brightness = 0.0015f;
21 | static constexpr auto darkmatter = 0.300f;
22 | static constexpr auto distfading = 0.730f;
23 | static constexpr auto saturation = 0.850f;
24 |
25 | gui::ShaderToy toy{argc, argv};
26 | toy.run([&](Float2 fragCoord, Float2 iResolution, Float iTime, Float4 iMouse) noexcept {
27 | //get coords and direction
28 | Var uv = fragCoord.xy() / iResolution.xy() - .5f;
29 | uv.y *= iResolution.y / iResolution.x;
30 | Var dir = make_float3(uv * zoom, 1.0f);
31 | Var time = iTime * speed + .25f;
32 |
33 | //mouse rotation
34 | Var a1 = .5f + iMouse.x / iResolution.x * 2.f;
35 | Var a2 = .8f + iMouse.y / iResolution.y * 2.f;
36 | Var rot1 = make_float2x2(cos(a1), -sin(a1), sin(a1), cos(a1));
37 | Var rot2 = make_float2x2(cos(a2), -sin(a2), sin(a2), cos(a2));
38 | dir = make_float3(rot1 * dir.xz(), dir.y).xzy();
39 | dir = make_float3(rot2 * dir.xy(), dir.z);
40 | Var from = make_float3(1.0f, 0.5f, 0.5f);
41 | from += make_float3(time * 2.f, time, -2.f);
42 | from = make_float3(rot1 * from.xz(), from.y).xzy();
43 | from = make_float3(rot2 * from.xy(), from.z);
44 |
45 | //volumetric rendering
46 | Var s = 0.1f;
47 | Var fade = 1.f;
48 | Var v = make_float3(0.f);
49 | for (auto r = 0u; r < volsteps; r++) {
50 | Var p = from + s * dir * .5f;
51 | p = abs(float3(tile) - mod(p, float3(tile * 2.f)));// tiling fold
52 | Var pa = 0.0f;
53 | Var a = 0.0f;
54 | for (auto i = 0u; i < iterations; i++) {
55 | p = abs(p) / dot(p, p) - formuparam;// the magic formula
56 | a += abs(length(p) - pa); // absolute sum of average change
57 | pa = length(p);
58 | }
59 | Var dm = max(0.f, darkmatter - a * a * .001f);//dark matter
60 | a *= a * a; // add contrast
61 | if (r > 6) fade *= 1.f - dm; // dark matter, don't render near
62 | v += fade;
63 | v += make_float3(s, s * s, s * s * s * s) * a * brightness * fade;// coloring based on distance
64 | fade *= distfading; // distance fading
65 | s += stepsize;
66 | }
67 | v = lerp(make_float3(length(v)), v, saturation);//color adjust
68 | return v * .01f;
69 | });
70 | }
71 |
--------------------------------------------------------------------------------
/src/ext/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | if (APPLE)
2 | enable_language(OBJC OBJCXX)
3 | endif ()
4 |
5 | add_library(luisa-shader-toy-ext INTERFACE)
6 |
7 | # OpenGL
8 | find_package(OpenGL REQUIRED)
9 | target_link_libraries(luisa-shader-toy-ext INTERFACE OpenGL::GL)
10 |
11 | # glfw
12 | if (NOT APPLE)
13 | set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
14 | set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
15 | set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
16 | set(GLFW_INSTALL OFF CACHE BOOL "" FORCE)
17 | set(GLFW_LIBRARY_TYPE SHARED CACHE STRING "" FORCE)
18 | add_subdirectory(glfw)
19 | else ()
20 | find_package(GLFW3 REQUIRED)
21 | endif ()
22 | target_link_libraries(luisa-shader-toy-ext INTERFACE glfw)
23 |
24 | # glad
25 | add_subdirectory(glad)
26 | target_link_libraries(luisa-shader-toy-ext INTERFACE glad)
27 |
28 | # ImGui
29 | add_subdirectory(imgui)
30 | target_link_libraries(luisa-shader-toy-ext INTERFACE imgui)
31 |
--------------------------------------------------------------------------------
/src/ext/glad/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(glad SHARED glad/glad.c glad/glad.h glad/khrplatform.h)
2 | target_link_libraries(glad PUBLIC OpenGL::GL)
3 | target_include_directories(glad PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
4 | target_compile_definitions(glad PRIVATE GLAD_GLAPI_EXPORT_BUILD PUBLIC GLAD_GLAPI_EXPORT)
5 |
--------------------------------------------------------------------------------
/src/ext/glad/glad/khrplatform.h:
--------------------------------------------------------------------------------
1 | #ifndef __khrplatform_h_
2 | #define __khrplatform_h_
3 |
4 | /*
5 | ** Copyright (c) 2008-2018 The Khronos Group Inc.
6 | **
7 | ** Permission is hereby granted, free of charge, to any person obtaining a
8 | ** copy of this software and/or associated documentation files (the
9 | ** "Materials"), to deal in the Materials without restriction, including
10 | ** without limitation the rights to use, copy, modify, merge, publish,
11 | ** distribute, sublicense, and/or sell copies of the Materials, and to
12 | ** permit persons to whom the Materials are furnished to do so, subject to
13 | ** the following conditions:
14 | **
15 | ** The above copyright notice and this permission notice shall be included
16 | ** in all copies or substantial portions of the Materials.
17 | **
18 | ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 | ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 | ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
25 | */
26 |
27 | /* Khronos platform-specific types and definitions.
28 | *
29 | * The master copy of khrplatform.h is maintained in the Khronos EGL
30 | * Registry repository at https://github.com/KhronosGroup/EGL-Registry
31 | * The last semantic modification to khrplatform.h was at commit ID:
32 | * 67a3e0864c2d75ea5287b9f3d2eb74a745936692
33 | *
34 | * Adopters may modify this file to suit their platform. Adopters are
35 | * encouraged to submit platform specific modifications to the Khronos
36 | * group so that they can be included in future versions of this file.
37 | * Please submit changes by filing pull requests or issues on
38 | * the EGL Registry repository linked above.
39 | *
40 | *
41 | * See the Implementer's Guidelines for information about where this file
42 | * should be located on your system and for more details of its use:
43 | * http://www.khronos.org/registry/implementers_guide.pdf
44 | *
45 | * This file should be included as
46 | * #include
47 | * by Khronos client API header files that use its types and defines.
48 | *
49 | * The types in khrplatform.h should only be used to define API-specific types.
50 | *
51 | * Types defined in khrplatform.h:
52 | * khronos_int8_t signed 8 bit
53 | * khronos_uint8_t unsigned 8 bit
54 | * khronos_int16_t signed 16 bit
55 | * khronos_uint16_t unsigned 16 bit
56 | * khronos_int32_t signed 32 bit
57 | * khronos_uint32_t unsigned 32 bit
58 | * khronos_int64_t signed 64 bit
59 | * khronos_uint64_t unsigned 64 bit
60 | * khronos_intptr_t signed same number of bits as a pointer
61 | * khronos_uintptr_t unsigned same number of bits as a pointer
62 | * khronos_ssize_t signed size
63 | * khronos_usize_t unsigned size
64 | * khronos_float_t signed 32 bit floating point
65 | * khronos_time_ns_t unsigned 64 bit time in nanoseconds
66 | * khronos_utime_nanoseconds_t unsigned time interval or absolute time in
67 | * nanoseconds
68 | * khronos_stime_nanoseconds_t signed time interval in nanoseconds
69 | * khronos_boolean_enum_t enumerated boolean type. This should
70 | * only be used as a base type when a client API's boolean type is
71 | * an enum. Client APIs which use an integer or other type for
72 | * booleans cannot use this as the base type for their boolean.
73 | *
74 | * Tokens defined in khrplatform.h:
75 | *
76 | * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
77 | *
78 | * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
79 | * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
80 | *
81 | * Calling convention macros defined in this file:
82 | * KHRONOS_APICALL
83 | * KHRONOS_APIENTRY
84 | * KHRONOS_APIATTRIBUTES
85 | *
86 | * These may be used in function prototypes as:
87 | *
88 | * KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
89 | * int arg1,
90 | * int arg2) KHRONOS_APIATTRIBUTES;
91 | */
92 |
93 | #if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
94 | # define KHRONOS_STATIC 1
95 | #endif
96 |
97 | /*-------------------------------------------------------------------------
98 | * Definition of KHRONOS_APICALL
99 | *-------------------------------------------------------------------------
100 | * This precedes the return type of the function in the function prototype.
101 | */
102 | #if defined(KHRONOS_STATIC)
103 | /* If the preprocessor constant KHRONOS_STATIC is defined, make the
104 | * header compatible with static linking. */
105 | # define KHRONOS_APICALL
106 | #elif defined(_WIN32)
107 | # define KHRONOS_APICALL __declspec(dllimport)
108 | #elif defined (__SYMBIAN32__)
109 | # define KHRONOS_APICALL IMPORT_C
110 | #elif defined(__ANDROID__)
111 | # define KHRONOS_APICALL __attribute__((visibility("default")))
112 | #else
113 | # define KHRONOS_APICALL
114 | #endif
115 |
116 | /*-------------------------------------------------------------------------
117 | * Definition of KHRONOS_APIENTRY
118 | *-------------------------------------------------------------------------
119 | * This follows the return type of the function and precedes the function
120 | * name in the function prototype.
121 | */
122 | #if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
123 | /* Win32 but not WinCE */
124 | # define KHRONOS_APIENTRY __stdcall
125 | #else
126 | # define KHRONOS_APIENTRY
127 | #endif
128 |
129 | /*-------------------------------------------------------------------------
130 | * Definition of KHRONOS_APIATTRIBUTES
131 | *-------------------------------------------------------------------------
132 | * This follows the closing parenthesis of the function prototype arguments.
133 | */
134 | #if defined (__ARMCC_2__)
135 | #define KHRONOS_APIATTRIBUTES __softfp
136 | #else
137 | #define KHRONOS_APIATTRIBUTES
138 | #endif
139 |
140 | /*-------------------------------------------------------------------------
141 | * basic type definitions
142 | *-----------------------------------------------------------------------*/
143 | #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
144 |
145 |
146 | /*
147 | * Using
148 | */
149 | #include
150 | typedef int32_t khronos_int32_t;
151 | typedef uint32_t khronos_uint32_t;
152 | typedef int64_t khronos_int64_t;
153 | typedef uint64_t khronos_uint64_t;
154 | #define KHRONOS_SUPPORT_INT64 1
155 | #define KHRONOS_SUPPORT_FLOAT 1
156 |
157 | #elif defined(__VMS ) || defined(__sgi)
158 |
159 | /*
160 | * Using
161 | */
162 | #include
163 | typedef int32_t khronos_int32_t;
164 | typedef uint32_t khronos_uint32_t;
165 | typedef int64_t khronos_int64_t;
166 | typedef uint64_t khronos_uint64_t;
167 | #define KHRONOS_SUPPORT_INT64 1
168 | #define KHRONOS_SUPPORT_FLOAT 1
169 |
170 | #elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
171 |
172 | /*
173 | * Win32
174 | */
175 | typedef __int32 khronos_int32_t;
176 | typedef unsigned __int32 khronos_uint32_t;
177 | typedef __int64 khronos_int64_t;
178 | typedef unsigned __int64 khronos_uint64_t;
179 | #define KHRONOS_SUPPORT_INT64 1
180 | #define KHRONOS_SUPPORT_FLOAT 1
181 |
182 | #elif defined(__sun__) || defined(__digital__)
183 |
184 | /*
185 | * Sun or Digital
186 | */
187 | typedef int khronos_int32_t;
188 | typedef unsigned int khronos_uint32_t;
189 | #if defined(__arch64__) || defined(_LP64)
190 | typedef long int khronos_int64_t;
191 | typedef unsigned long int khronos_uint64_t;
192 | #else
193 | typedef long long int khronos_int64_t;
194 | typedef unsigned long long int khronos_uint64_t;
195 | #endif /* __arch64__ */
196 | #define KHRONOS_SUPPORT_INT64 1
197 | #define KHRONOS_SUPPORT_FLOAT 1
198 |
199 | #elif 0
200 |
201 | /*
202 | * Hypothetical platform with no float or int64 support
203 | */
204 | typedef int khronos_int32_t;
205 | typedef unsigned int khronos_uint32_t;
206 | #define KHRONOS_SUPPORT_INT64 0
207 | #define KHRONOS_SUPPORT_FLOAT 0
208 |
209 | #else
210 |
211 | /*
212 | * Generic fallback
213 | */
214 | #include
215 | typedef int32_t khronos_int32_t;
216 | typedef uint32_t khronos_uint32_t;
217 | typedef int64_t khronos_int64_t;
218 | typedef uint64_t khronos_uint64_t;
219 | #define KHRONOS_SUPPORT_INT64 1
220 | #define KHRONOS_SUPPORT_FLOAT 1
221 |
222 | #endif
223 |
224 |
225 | /*
226 | * Types that are (so far) the same on all platforms
227 | */
228 | typedef signed char khronos_int8_t;
229 | typedef unsigned char khronos_uint8_t;
230 | typedef signed short int khronos_int16_t;
231 | typedef unsigned short int khronos_uint16_t;
232 |
233 | /*
234 | * Types that differ between LLP64 and LP64 architectures - in LLP64,
235 | * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
236 | * to be the only LLP64 architecture in current use.
237 | */
238 | #ifdef _WIN64
239 | typedef signed long long int khronos_intptr_t;
240 | typedef unsigned long long int khronos_uintptr_t;
241 | typedef signed long long int khronos_ssize_t;
242 | typedef unsigned long long int khronos_usize_t;
243 | #else
244 | typedef signed long int khronos_intptr_t;
245 | typedef unsigned long int khronos_uintptr_t;
246 | typedef signed long int khronos_ssize_t;
247 | typedef unsigned long int khronos_usize_t;
248 | #endif
249 |
250 | #if KHRONOS_SUPPORT_FLOAT
251 | /*
252 | * Float type
253 | */
254 | typedef float khronos_float_t;
255 | #endif
256 |
257 | #if KHRONOS_SUPPORT_INT64
258 | /* Time types
259 | *
260 | * These types can be used to represent a time interval in nanoseconds or
261 | * an absolute Unadjusted System Time. Unadjusted System Time is the number
262 | * of nanoseconds since some arbitrary system event (e.g. since the last
263 | * time the system booted). The Unadjusted System Time is an unsigned
264 | * 64 bit value that wraps back to 0 every 584 years. Time intervals
265 | * may be either signed or unsigned.
266 | */
267 | typedef khronos_uint64_t khronos_utime_nanoseconds_t;
268 | typedef khronos_int64_t khronos_stime_nanoseconds_t;
269 | #endif
270 |
271 | /*
272 | * Dummy value used to pad enum types to 32 bits.
273 | */
274 | #ifndef KHRONOS_MAX_ENUM
275 | #define KHRONOS_MAX_ENUM 0x7FFFFFFF
276 | #endif
277 |
278 | /*
279 | * Enumerated boolean type
280 | *
281 | * Values other than zero should be considered to be true. Therefore
282 | * comparisons should not be made against KHRONOS_TRUE.
283 | */
284 | typedef enum {
285 | KHRONOS_FALSE = 0,
286 | KHRONOS_TRUE = 1,
287 | KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
288 | } khronos_boolean_enum_t;
289 |
290 | #endif /* __khrplatform_h_ */
291 |
--------------------------------------------------------------------------------
/src/ext/imgui/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(imgui SHARED
2 | imgui/imgui.cpp imgui/imgui.h
3 | imgui/imgui_demo.cpp
4 | imgui/imgui_draw.cpp
5 | imgui/imgui_tables.cpp
6 | imgui/imgui_widgets.cpp
7 | # imgui/backends/imgui_impl_glfw.cpp imgui/backends/imgui_impl_glfw.h
8 | imgui/backends/imgui_impl_opengl3.cpp imgui/backends/imgui_impl_opengl3.h)
9 | target_include_directories(imgui PUBLIC imgui "${CMAKE_CURRENT_SOURCE_DIR}")
10 | target_link_libraries(imgui PUBLIC glad glfw)
11 | target_compile_definitions(imgui PUBLIC IMGUI_IMPL_OPENGL_LOADER_GLAD)
12 | set_target_properties(imgui PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
13 |
--------------------------------------------------------------------------------
/src/ext/stb/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(stb STATIC stb.cpp)
2 | target_include_directories(stb PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
3 |
--------------------------------------------------------------------------------
/src/ext/stb/stb.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/13.
3 | //
4 |
5 | #define STB_IMAGE_IMPLEMENTATION
6 | #include
7 |
8 | #define STB_IMAGE_WRITE_IMPLEMENTATION
9 | #include
10 |
--------------------------------------------------------------------------------
/src/gui/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | set(LUISA_SHADER_TOY_GUI_SOURCES
2 | framerate.cpp framerate.h
3 | window.cpp window.h
4 | hid.h
5 | imgui_impl_glfw.cpp imgui_impl_glfw.h
6 | gl_texture.cpp gl_texture.h
7 | shader_toy.cpp shader_toy.h)
8 |
9 | add_library(luisa-shader-toy-gui SHARED ${LUISA_SHADER_TOY_GUI_SOURCES})
10 | target_link_libraries(luisa-shader-toy-gui PUBLIC luisa-shader-toy-ext luisa::compute)
11 | target_compile_definitions(luisa-shader-toy-gui PUBLIC GLFW_INCLUDE_NONE)
12 | set_target_properties(luisa-shader-toy-gui PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
13 |
14 | find_package(OpenCV CONFIG)
15 | if (OpenCV_FOUND)
16 | target_link_libraries(luisa-shader-toy-gui PUBLIC ${OpenCV_LIBS})
17 | target_compile_definitions(luisa-shader-toy-gui PUBLIC LUISA_SHADERTOY_HAS_OPENCV=1)
18 | endif ()
19 |
--------------------------------------------------------------------------------
/src/gui/framerate.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/13.
3 | //
4 |
5 | #include
6 |
7 | namespace luisa::gui {
8 |
9 | Framerate::Framerate(double smoothness) noexcept
10 | : _last{Clock::now()},
11 | _alpha{smoothness},
12 | _dt{0.0f},
13 | _count{0u} {}
14 |
15 | double Framerate::tick() noexcept {
16 | using namespace std::chrono_literals;
17 | auto last = _last;
18 | _last = Clock::now();
19 | _count++;
20 | auto dt = static_cast((_last - last) / 1ns) * 1e-6;
21 | _dt = _count == 0u ? dt : (_alpha * _dt + (1.0f - _alpha) * dt);
22 | return dt;
23 | }
24 |
25 | double Framerate::fps() const noexcept {
26 | return _count == 0u ? 0.0 : 1000.0 / _dt;
27 | }
28 |
29 | void Framerate::clear() noexcept {
30 | _last = Clock::now();
31 | _dt = 0.0;
32 | _count = 0u;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/gui/framerate.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/13.
3 | //
4 |
5 | #pragma once
6 |
7 | #include
8 |
9 | namespace luisa::gui {
10 |
11 | class Framerate {
12 |
13 | using Clock = std::chrono::high_resolution_clock;
14 | using Tick = std::chrono::high_resolution_clock::time_point;
15 |
16 | private:
17 | Tick _last;
18 | double _alpha;
19 | double _dt;
20 | uint64_t _count;
21 |
22 | public:
23 | explicit Framerate(double smoothness = 0.5) noexcept;
24 | void clear() noexcept;
25 | double tick() noexcept;
26 | [[nodiscard]] auto count() const noexcept { return _count; }
27 | [[nodiscard]] double fps() const noexcept;
28 | };
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/gui/gl_texture.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/27.
3 | //
4 |
5 | #include
6 | #include
7 |
8 | namespace luisa::gui {
9 |
10 | int GLTexture::_gl_format(PixelFormat format) noexcept {
11 | switch (format) {
12 | case PixelFormat::R8UNorm:
13 | case PixelFormat::R32F:
14 | return GL_RED;
15 | case PixelFormat::RG8UNorm:
16 | case PixelFormat::RG32F:
17 | return GL_RG;
18 | case PixelFormat::RGBA8UNorm:
19 | case PixelFormat::RGBA32F:
20 | return GL_RGBA;
21 | default:
22 | LUISA_ERROR_WITH_LOCATION("Invalid pixel format.");
23 | }
24 | }
25 |
26 | int GLTexture::_gl_type(PixelFormat format) noexcept {
27 | switch (format) {
28 | case PixelFormat::R8UNorm:
29 | case PixelFormat::RG8UNorm:
30 | case PixelFormat::RGBA8UNorm:
31 | return GL_UNSIGNED_BYTE;
32 | case PixelFormat::R32F:
33 | case PixelFormat::RG32F:
34 | case PixelFormat::RGBA32F:
35 | return GL_FLOAT;
36 | default:
37 | LUISA_ERROR_WITH_LOCATION("Invalid pixel format.");
38 | }
39 | }
40 |
41 | void GLTexture::_destroy() noexcept {
42 | if (_handle != 0u) {
43 | glDeleteTextures(1, &_handle);
44 | _handle = 0u;
45 | }
46 | }
47 |
48 | size_t GLTexture::_size_bytes() const noexcept { return _size.x * _size.y * _pixel_size; }
49 |
50 | void GLTexture::resize(uint2 size) noexcept {
51 | _size = size;
52 | glTexImage2D(GL_TEXTURE_2D, 0, _format, size.x, size.y, 0, _format, _type, nullptr);
53 | }
54 |
55 | GLTexture::GLTexture(PixelFormat format, uint2 size) noexcept
56 | : _format{_gl_format(format)},
57 | _type{_gl_type(format)},
58 | _pixel_size{static_cast(compute::pixel_format_size(format))} {
59 | glGenTextures(1, &_handle);
60 | glBindTexture(GL_TEXTURE_2D, _handle);
61 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
62 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
63 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
64 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
65 | resize(size);
66 | }
67 |
68 | GLTexture::~GLTexture() noexcept { _destroy(); }
69 |
70 | bool GLTexture::_upload() noexcept {
71 | auto valid = _front_buffer.size() == _size_bytes();
72 | if (valid) {
73 | glBindTexture(GL_TEXTURE_2D, _handle);
74 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _size.x, _size.y, _format, _type, _front_buffer.data());
75 | }
76 | std::swap(_front_buffer, _back_buffer);
77 | return valid;
78 | }
79 |
80 | uint64_t GLTexture::handle() const noexcept { return _handle; }
81 |
82 | }// namespace luisa::gui
83 |
--------------------------------------------------------------------------------
/src/gui/gl_texture.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/13.
3 | //
4 |
5 | #pragma once
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | namespace luisa::gui {
18 |
19 | using compute::PixelFormat;
20 |
21 | class GLTexture {
22 |
23 | private:
24 | uint2 _size;
25 | int _format;
26 | int _type;
27 | uint _handle{0u};
28 | uint _pixel_size;
29 | std::vector _front_buffer;
30 | std::vector _back_buffer;
31 |
32 | private:
33 | [[nodiscard]] static int _gl_format(PixelFormat format) noexcept;
34 | [[nodiscard]] static int _gl_type(PixelFormat format) noexcept;
35 | [[nodiscard]] size_t _size_bytes() const noexcept;
36 | void _destroy() noexcept;
37 | [[nodiscard]] bool _upload() noexcept;
38 |
39 | public:
40 | GLTexture(PixelFormat format, uint2 size) noexcept;
41 | GLTexture(PixelFormat format, uint width, uint height) noexcept : GLTexture{format, {width, height}} {}
42 | GLTexture(GLTexture &&) noexcept = delete;
43 | GLTexture(const GLTexture &) noexcept = delete;
44 | GLTexture &operator=(GLTexture &&) noexcept = delete;
45 | GLTexture &operator=(const GLTexture &) noexcept = delete;
46 | ~GLTexture() noexcept;
47 |
48 | [[nodiscard]] uint64_t handle() const noexcept;
49 | void resize(uint2 size) noexcept;
50 |
51 | template, int> = 0>
52 | bool present(Update &&update) {
53 | _back_buffer.resize(_size_bytes());
54 | update(_back_buffer.data());
55 | return _upload();
56 | }
57 | };
58 |
59 | }// namespace luisa::gui
60 |
--------------------------------------------------------------------------------
/src/gui/hid.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/27.
3 | //
4 |
5 | #pragma once
6 |
7 | #include
8 | #include
9 | #include
10 |
11 | namespace luisa::gui {
12 |
13 | enum Key : uint32_t {
14 | KEY_SPACE = 32u,
15 | KEY_APOSTROPHE = 39u, /* ' */
16 | KEY_COMMA = 44u, /* , */
17 | KEY_MINUS = 45u, /* - */
18 | KEY_PERIOD = 46u, /* . */
19 | KEY_SLASH = 47u, /* / */
20 | KEY_0 = 48u,
21 | KEY_1 = 49u,
22 | KEY_2 = 50u,
23 | KEY_3 = 51u,
24 | KEY_4 = 52u,
25 | KEY_5 = 53u,
26 | KEY_6 = 54u,
27 | KEY_7 = 55u,
28 | KEY_8 = 56u,
29 | KEY_9 = 57u,
30 | KEY_SEMICOLON = 59u, /* ; */
31 | KEY_EQUAL = 61u, /* = */
32 | KEY_A = 65u,
33 | KEY_B = 66u,
34 | KEY_C = 67u,
35 | KEY_D = 68u,
36 | KEY_E = 69u,
37 | KEY_F = 70u,
38 | KEY_G = 71u,
39 | KEY_H = 72u,
40 | KEY_I = 73u,
41 | KEY_J = 74u,
42 | KEY_K = 75u,
43 | KEY_L = 76u,
44 | KEY_M = 77u,
45 | KEY_N = 78u,
46 | KEY_O = 79u,
47 | KEY_P = 80u,
48 | KEY_Q = 81u,
49 | KEY_R = 82u,
50 | KEY_S = 83u,
51 | KEY_T = 84u,
52 | KEY_U = 85u,
53 | KEY_V = 86u,
54 | KEY_W = 87u,
55 | KEY_X = 88u,
56 | KEY_Y = 89u,
57 | KEY_Z = 90u,
58 | KEY_LEFT_BRACKET = 91u, /* [ */
59 | KEY_BACKSLASH = 92u, /* \ */
60 | KEY_RIGHT_BRACKET = 93u, /* ] */
61 | KEY_GRAVE_ACCENT = 96u, /* ` */
62 | KEY_WORLD_1 = 161u, /* non-US #1 */
63 | KEY_WORLD_2 = 162u, /* non-US #2 */
64 | KEY_ESCAPE = 256u,
65 | KEY_ENTER = 257u,
66 | KEY_TAB = 258u,
67 | KEY_BACKSPACE = 259u,
68 | KEY_INSERT = 260u,
69 | KEY_DELETE = 261u,
70 | KEY_RIGHT = 262u,
71 | KEY_LEFT = 263u,
72 | KEY_DOWN = 264u,
73 | KEY_UP = 265u,
74 | KEY_PAGE_UP = 266u,
75 | KEY_PAGE_DOWN = 267u,
76 | KEY_HOME = 268u,
77 | KEY_END = 269u,
78 | KEY_CAPS_LOCK = 280u,
79 | KEY_SCROLL_LOCK = 281u,
80 | KEY_NUM_LOCK = 282u,
81 | KEY_PRINT_SCREEN = 283u,
82 | KEY_PAUSE = 284u,
83 | KEY_F1 = 290u,
84 | KEY_F2 = 291u,
85 | KEY_F3 = 292u,
86 | KEY_F4 = 293u,
87 | KEY_F5 = 294u,
88 | KEY_F6 = 295u,
89 | KEY_F7 = 296u,
90 | KEY_F8 = 297u,
91 | KEY_F9 = 298u,
92 | KEY_F10 = 299u,
93 | KEY_F11 = 300u,
94 | KEY_F12 = 301u,
95 | KEY_F13 = 302u,
96 | KEY_F14 = 303u,
97 | KEY_F15 = 304u,
98 | KEY_F16 = 305u,
99 | KEY_F17 = 306u,
100 | KEY_F18 = 307u,
101 | KEY_F19 = 308u,
102 | KEY_F20 = 309u,
103 | KEY_F21 = 310u,
104 | KEY_F22 = 311u,
105 | KEY_F23 = 312u,
106 | KEY_F24 = 313u,
107 | KEY_F25 = 314u,
108 | KEY_KP_0 = 320u,
109 | KEY_KP_1 = 321u,
110 | KEY_KP_2 = 322u,
111 | KEY_KP_3 = 323u,
112 | KEY_KP_4 = 324u,
113 | KEY_KP_5 = 325u,
114 | KEY_KP_6 = 326u,
115 | KEY_KP_7 = 327u,
116 | KEY_KP_8 = 328u,
117 | KEY_KP_9 = 329u,
118 | KEY_KP_DECIMAL = 330u,
119 | KEY_KP_DIVIDE = 331u,
120 | KEY_KP_MULTIPLY = 332u,
121 | KEY_KP_SUBTRACT = 333u,
122 | KEY_KP_ADD = 334u,
123 | KEY_KP_ENTER = 335u,
124 | KEY_KP_EQUAL = 336u,
125 | KEY_LEFT_SHIFT = 340u,
126 | KEY_LEFT_CONTROL = 341u,
127 | KEY_LEFT_ALT = 342u,
128 | KEY_LEFT_SUPER = 343u,
129 | KEY_RIGHT_SHIFT = 344u,
130 | KEY_RIGHT_CONTROL = 345u,
131 | KEY_RIGHT_ALT = 346u,
132 | KEY_RIGHT_SUPER = 347u,
133 | KEY_MENU = 348u
134 | };
135 |
136 | enum Mouse : uint32_t {
137 | MOUSE_LEFT = 0u,
138 | MOUSE_RIGHT = 1u,
139 | MOUSE_MIDDLE = 2u
140 | };
141 |
142 | }// namespace luisa::gui
143 |
--------------------------------------------------------------------------------
/src/gui/imgui_impl_glfw.cpp:
--------------------------------------------------------------------------------
1 | // dear imgui: Platform Backend for GLFW
2 | // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
3 | // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
4 | // (Requires: GLFW 3.1+)
5 |
6 | // Implemented features:
7 | // [X] Platform: Clipboard support.
8 | // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
9 | // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
10 | // [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
11 |
12 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
13 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
14 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
15 | // Read online: https://github.com/ocornut/imgui/tree/master/docs
16 |
17 | // CHANGELOG
18 | // (minor and older changes stripped away, please see git history for details)
19 | // 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors.
20 | // 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor).
21 | // 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown.
22 | // 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
23 | // 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
24 | // 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
25 | // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
26 | // 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
27 | // 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
28 | // 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
29 | // 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
30 | // 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
31 | // 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
32 | // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
33 | // 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
34 | // 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
35 | // 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
36 | // 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
37 | // 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
38 | // 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
39 | // 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
40 |
41 | #include
42 |
43 | #include "imgui.h"
44 | #include "imgui_impl_glfw.h"
45 |
46 | // GLFW
47 | #include
48 | #ifdef _WIN32
49 | #undef APIENTRY
50 | #define GLFW_EXPOSE_NATIVE_WIN32
51 | #include // for glfwGetWin32Window
52 | #endif
53 | #define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING
54 | #define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED
55 | #define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity
56 | #define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300)// 3.3+ glfwGetMonitorContentScale
57 | #define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface
58 | #ifdef GLFW_RESIZE_NESW_CURSOR // let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
59 | #define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
60 | #else
61 | #define GLFW_HAS_NEW_CURSORS (0)
62 | #endif
63 |
64 | // Data
65 | struct ImGuiGlfwContext {
66 | double m_Time = 0.0;
67 | bool m_MouseJustPressed[ImGuiMouseButton_COUNT] = {};
68 | GLFWcursor *m_MouseCursors[ImGuiMouseCursor_COUNT] = {};
69 | };
70 |
71 | [[nodiscard]] static auto &get_registry() noexcept {
72 | static std::unordered_map registry;
73 | return registry;
74 | }
75 |
76 | static const char *ImGui_ImplGlfw_GetClipboardText(void *user_data) {
77 | return glfwGetClipboardString((GLFWwindow *)user_data);
78 | }
79 |
80 | static void ImGui_ImplGlfw_SetClipboardText(void *user_data, const char *text) {
81 | glfwSetClipboardString((GLFWwindow *)user_data, text);
82 | }
83 |
84 | void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) {
85 | auto &&ctx = get_registry()[window];
86 | if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(ctx.m_MouseJustPressed)) {
87 | ctx.m_MouseJustPressed[button] = true;
88 | }
89 | }
90 |
91 | void ImGui_ImplGlfw_ScrollCallback(GLFWwindow *window, double xoffset, double yoffset) {
92 | ImGuiIO &io = ImGui::GetIO();
93 | io.MouseWheelH += (float)xoffset;
94 | io.MouseWheel += (float)yoffset;
95 | }
96 |
97 | void ImGui_ImplGlfw_KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) {
98 |
99 | ImGuiIO &io = ImGui::GetIO();
100 | if (key >= 0 && key < IM_ARRAYSIZE(io.KeysDown)) {
101 | if (action == GLFW_PRESS)
102 | io.KeysDown[key] = true;
103 | if (action == GLFW_RELEASE)
104 | io.KeysDown[key] = false;
105 | }
106 |
107 | // Modifiers are not reliable across systems
108 | io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
109 | io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
110 | io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
111 | #ifdef _WIN32
112 | io.KeySuper = false;
113 | #else
114 | io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
115 | #endif
116 | }
117 |
118 | void ImGui_ImplGlfw_CharCallback(GLFWwindow *window, unsigned int c) {
119 | ImGuiIO &io = ImGui::GetIO();
120 | io.AddInputCharacter(c);
121 | }
122 |
123 | static bool ImGui_ImplGlfw_Init(GLFWwindow *window) {
124 | // Setup backend capabilities flags
125 | ImGuiIO &io = ImGui::GetIO();
126 | io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;// We can honor GetMouseCursor() values (optional)
127 | io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
128 | io.BackendPlatformName = "imgui_impl_glfw";
129 |
130 | // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
131 | io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
132 | io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
133 | io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
134 | io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
135 | io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
136 | io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
137 | io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
138 | io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
139 | io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
140 | io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
141 | io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
142 | io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
143 | io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
144 | io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
145 | io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
146 | io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER;
147 | io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
148 | io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
149 | io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
150 | io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
151 | io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
152 | io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
153 |
154 | io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
155 | io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
156 | io.ClipboardUserData = window;
157 | #if defined(_WIN32)
158 | io.ImeWindowHandle = (void *)glfwGetWin32Window(window);
159 | #endif
160 |
161 | // Create mouse cursors
162 | // (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
163 | // GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
164 | // Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
165 | ImGuiGlfwContext ctx;
166 | ctx.m_Time = 0.0;
167 | GLFWerrorfun prev_error_callback = glfwSetErrorCallback(nullptr);
168 | ctx.m_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
169 | ctx.m_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
170 | ctx.m_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
171 | ctx.m_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
172 | ctx.m_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
173 | #if GLFW_HAS_NEW_CURSORS
174 | ctx.m_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
175 | ctx.m_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
176 | ctx.m_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
177 | ctx.m_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
178 | #else
179 | ctx.m_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
180 | ctx.m_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
181 | ctx.m_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
182 | ctx.m_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
183 | #endif
184 | glfwSetErrorCallback(prev_error_callback);
185 |
186 | // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
187 | glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
188 | glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
189 | glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
190 | glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
191 |
192 | get_registry().emplace(window, ctx);
193 | return true;
194 | }
195 |
196 | bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow *window) {
197 | return ImGui_ImplGlfw_Init(window);
198 | }
199 |
200 | void ImGui_ImplGlfw_Shutdown(GLFWwindow *window) {
201 | get_registry().erase(window);
202 | }
203 |
204 | static void ImGui_ImplGlfw_UpdateMousePosAndButtons(GLFWwindow *window, ImGuiGlfwContext *ctx) {
205 | // Update buttons
206 | ImGuiIO &io = ImGui::GetIO();
207 | for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) {
208 | // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
209 | io.MouseDown[i] = ctx->m_MouseJustPressed[i] || glfwGetMouseButton(window, i) != 0;
210 | ctx->m_MouseJustPressed[i] = false;
211 | }
212 |
213 | // Update mouse position
214 | const ImVec2 mouse_pos_backup = io.MousePos;
215 | io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
216 | #ifdef __EMSCRIPTEN__
217 | const bool focused = true;// Emscripten
218 | #else
219 | const bool focused = glfwGetWindowAttrib(window, GLFW_FOCUSED) != 0;
220 | #endif
221 | if (focused) {
222 | if (io.WantSetMousePos) {
223 | glfwSetCursorPos(window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y);
224 | } else {
225 | double mouse_x, mouse_y;
226 | glfwGetCursorPos(window, &mouse_x, &mouse_y);
227 | io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
228 | }
229 | }
230 | }
231 |
232 | static void ImGui_ImplGlfw_UpdateMouseCursor(GLFWwindow *window, const ImGuiGlfwContext *ctx) {
233 | ImGuiIO &io = ImGui::GetIO();
234 | if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
235 | return;
236 |
237 | ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
238 | if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) {
239 | // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
240 | glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
241 | } else {
242 | // Show OS mouse cursor
243 | // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
244 | glfwSetCursor(window, ctx->m_MouseCursors[imgui_cursor] ? ctx->m_MouseCursors[imgui_cursor] : ctx->m_MouseCursors[ImGuiMouseCursor_Arrow]);
245 | glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
246 | }
247 | }
248 |
249 | void ImGui_ImplGlfw_NewFrame(GLFWwindow *window) {
250 | ImGuiIO &io = ImGui::GetIO();
251 | IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
252 |
253 | // Setup display size (every frame to accommodate for window resizing)
254 | int w, h;
255 | int display_w, display_h;
256 | glfwGetWindowSize(window, &w, &h);
257 | glfwGetFramebufferSize(window, &display_w, &display_h);
258 | io.DisplaySize = ImVec2((float)w, (float)h);
259 | if (w > 0 && h > 0)
260 | io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
261 |
262 | auto &&ctx = get_registry()[window];
263 | // Setup time step
264 | double current_time = glfwGetTime();
265 | io.DeltaTime = ctx.m_Time > 0.0 ? (float)(current_time - ctx.m_Time) : (float)(1.0f / 60.0f);
266 | ctx.m_Time = current_time;
267 |
268 | ImGui_ImplGlfw_UpdateMousePosAndButtons(window, &ctx);
269 | ImGui_ImplGlfw_UpdateMouseCursor(window, &ctx);
270 | }
271 |
--------------------------------------------------------------------------------
/src/gui/imgui_impl_glfw.h:
--------------------------------------------------------------------------------
1 | // dear imgui: Platform Backend for GLFW
2 | // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
3 | // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
4 |
5 | // Implemented features:
6 | // [X] Platform: Clipboard support.
7 | // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
8 | // [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
9 | // [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
10 |
11 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
12 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
13 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
14 | // Read online: https://github.com/ocornut/imgui/tree/master/docs
15 |
16 | // About GLSL version:
17 | // The 'glsl_version' initialization parameter defaults to "#version 150" if NULL.
18 | // Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure!
19 |
20 | #pragma once
21 | #include "imgui.h" // IMGUI_IMPL_API
22 |
23 | struct GLFWwindow;
24 | struct ImGuiGlfwContext;
25 |
26 | IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window);
27 | IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown(GLFWwindow *window);
28 | IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame(GLFWwindow *window);
29 |
30 | // GLFW callbacks
31 | // - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any.
32 | // - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call those function yourself from your own GLFW callbacks.
33 | IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
34 | IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
35 | IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
36 | IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
37 |
--------------------------------------------------------------------------------
/src/gui/shader_toy.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/27.
3 | //
4 |
5 | #include
6 | #include
7 |
8 | #if LUISA_SHADERTOY_HAS_OPENCV
9 | #include
10 | #endif
11 |
12 | namespace luisa::gui {
13 |
14 | using namespace compute;
15 |
16 | template
17 | static void with_panel(const char *name, F &&f) {
18 | ImGui::Begin(name, nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize);
19 | f();
20 | ImGui::End();
21 | }
22 |
23 | void ShaderToy::run(const MainShader &main_shader) noexcept {
24 | auto shader = _device->compile(Kernel2D{[&](ImageFloat image, Float time, Float4 cursor) noexcept {
25 | using namespace compute;
26 | auto xy = dispatch_id().xy();
27 | auto resolution = dispatch_size().xy();
28 | auto col = main_shader(make_float2(make_uint2(xy.x, resolution.y - 1u - xy.y)) + 0.5f,
29 | make_float2(resolution), time, cursor);
30 | image.write(xy, make_float4(col, 1.0f));
31 | }});
32 | if (_dump_file.empty()) {
33 | _run_display(shader);
34 | } else {
35 | _run_dump(shader);
36 | }
37 | }
38 |
39 | ShaderToy::ShaderToy(int argc, const char *const *argv) noexcept
40 | : _context{argv[0]} {
41 | Context context{argv[0]};
42 | luisa::string backend{"unknown"};
43 | auto device_id = 0u;
44 | for (auto i = 1u; i < argc; i++) {
45 | using namespace std::string_view_literals;
46 | auto next_arg = [&] {
47 | if (i + 1u >= argc) {
48 | LUISA_ERROR_WITH_LOCATION(
49 | "Missing argument for option: ",
50 | argv[i]);
51 | }
52 | return argv[++i];
53 | };
54 | if (argv[i] == "-b"sv || argv[i] == "--backend"sv) {
55 | backend = next_arg();
56 | } else if (argv[i] == "-s"sv || argv[i] == "--size"sv) {
57 | auto s = next_arg();
58 | auto n = std::sscanf(s, "%ux%u", &_size.x, &_size.y);
59 | LUISA_ASSERT(n != 0, "Invalid size: {}", s);
60 | if (n == 1) { _size.y = _size.x; }
61 | _size = luisa::clamp(_size, 1u, 4096u);
62 | } else if (argv[i] == "-d"sv || argv[i] == "--device"sv) {
63 | device_id = std::atoi(next_arg());
64 | } else if (argv[i] == "-t"sv || argv[i] == "--step"sv) {
65 | _step = std::clamp(std::atof(next_arg()), 0., 1000.);
66 | } else if (argv[i] == "-o"sv || argv[i] == "--dump"sv) {
67 | _dump_file = next_arg();
68 | } else if (argv[i] == "-n"sv || argv[i] == "--frames"sv) {
69 | _dump_frames = std::atoi(next_arg());
70 | } else if (argv[i] == "--fps"sv) {
71 | _dump_fps = std::clamp(std::atof(next_arg()), 1., 200.);
72 | } else {
73 | LUISA_ERROR_WITH_LOCATION("Unknown option: {}", argv[i]);
74 | }
75 | }
76 | _title = std::filesystem::canonical(argv[0]).filename().replace_extension("").string();
77 | for (auto &c : _title) { c = c == '_' ? ' ' : c; }
78 | auto is_first = true;
79 | for (auto &c : _title) {
80 | if (is_first) { c = static_cast(std::toupper(c)); }
81 | is_first = c == ' ';
82 | }
83 | _device = luisa::make_unique(context.create_device(
84 | backend, luisa::format("{{\"index\": {}}}", device_id)));
85 | _stream = _device->create_stream();
86 | }
87 |
88 | void ShaderToy::_run_display(const compute::Shader2D, float, float4> &shader) noexcept {
89 |
90 | auto device_image = _device->create_image(PixelStorage::BYTE4, _size);
91 | auto event = _device->create_event();
92 | Window window{_title, _size};
93 | GLTexture texture{PixelFormat::RGBA8UNorm, _size};
94 | _stream << event.signal();
95 |
96 | auto prev_key_up = false;
97 | auto show_console = true;
98 | auto cursor = float4(0.0f);
99 | auto dragging = false;
100 | Framerate framerate{0.8};
101 | window.run([&] {
102 | auto render_size = device_image.size();
103 | auto window_size = window.size();
104 | if (window.mouse_down(MOUSE_LEFT)) {
105 | auto curr = window.cursor();
106 | curr = float2(curr.x, static_cast(window_size.y) - curr.y);
107 | if (dragging) {
108 | cursor = make_float4(curr, cursor.zw());
109 | } else {
110 | cursor = make_float4(curr, curr * float2(1.0f, -1.0f));
111 | dragging = true;
112 | }
113 | } else if (window.mouse_up(MOUSE_LEFT)) {
114 | cursor = make_float4(cursor.xy(), -abs(cursor.zw()));
115 | dragging = false;
116 | }
117 |
118 | auto time = _step == 0. ? window.time() : static_cast(framerate.count()) * _step;
119 | if (texture.present([&](void *pixels) noexcept {
120 | event.synchronize();
121 | _stream << shader(device_image, static_cast(time), cursor).dispatch(window_size)
122 | << device_image.copy_to(pixels)
123 | << event.signal();
124 | })) {
125 | ImVec2 background_size{static_cast(render_size.x), static_cast(render_size.y)};
126 | ImGui::GetBackgroundDrawList()->AddImage(reinterpret_cast(texture.handle()), {}, background_size);
127 | }
128 |
129 | framerate.tick();
130 | auto fps = framerate.fps();
131 | auto spp = framerate.count();
132 | if (show_console) {
133 | with_panel("Console", [&] {
134 | ImGui::Text("Frame: %llu", static_cast(spp));
135 | ImGui::Text("Time: %.2lfs", time);
136 | ImGui::Text("FPS: %.1lf", fps);
137 | ImGui::Text("Size: %ux%u", window_size.x, window_size.y);
138 | });
139 | }
140 | if (window.key_down(KEY_ESCAPE)) {
141 | window.notify_close();
142 | }
143 | if (prev_key_up && (window.key_down(KEY_LEFT_CONTROL) || window.key_down(KEY_RIGHT_CONTROL))) {
144 | show_console = !show_console;
145 | }
146 | prev_key_up = window.key_up(KEY_LEFT_CONTROL) && window.key_up(KEY_RIGHT_CONTROL);
147 | });
148 | }
149 |
150 | void ShaderToy::_run_dump(const compute::Shader2D, float, float4> &shader) noexcept {
151 | #if LUISA_SHADERTOY_HAS_OPENCV
152 | auto device_image = _device->create_image(PixelStorage::BYTE4, _size);
153 | cv::Size size{static_cast(_size.x), static_cast(_size.y)};
154 | cv::Mat frame{size, CV_8UC4, cv::Scalar::all(0)};
155 | cv::Mat cvt_frame{size, CV_8UC3, cv::Scalar::all(0)};
156 | auto fourcc = cv::VideoWriter::fourcc('m', 'p', '4', 'v');
157 | auto path = std::filesystem::absolute(_dump_file);
158 | cv::VideoWriter video{path.string(), fourcc, _dump_fps, size};
159 | LUISA_ASSERT(video.isOpened(), "Failed to open video file: {}", path.string());
160 | for (auto i = 0u; i < _dump_frames; i++) {
161 | _stream << shader(device_image, static_cast(i * _step), float4(0.0f)).dispatch(_size)
162 | << device_image.copy_to(frame.data)
163 | << synchronize();
164 | LUISA_INFO("Frame {} / {}", i + 1u, _dump_frames);
165 | cv::cvtColor(frame, cvt_frame, cv::COLOR_RGBA2BGR);
166 | video << cvt_frame;
167 | }
168 | #else
169 | LUISA_WARNING("OpenCV is not available. Dumping is disabled.");
170 | #endif
171 | }
172 |
173 | }// namespace luisa::gui
174 |
--------------------------------------------------------------------------------
/src/gui/shader_toy.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/27.
3 | //
4 |
5 | #pragma once
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | namespace luisa::gui {
18 |
19 | using compute::Callable;
20 | using compute::Context;
21 | using compute::Device;
22 | using compute::Event;
23 | using compute::Float;
24 | using compute::Float2;
25 | using compute::Float4;
26 | using compute::Image;
27 | using compute::ImageFloat;
28 | using compute::ImageVar;
29 | using compute::Kernel2D;
30 | using compute::Stream;
31 | using compute::Shader;
32 |
33 | class ShaderToy {
34 |
35 | public:
36 | using MainShader = Callable;
41 |
42 | private:
43 | Context _context;
44 | luisa::unique_ptr _device;
45 | Stream _stream;
46 | std::string _title{};
47 | uint2 _size{1280u, 720u};
48 | double _step{0.};
49 | luisa::string _dump_file{};
50 | uint _dump_frames{1u};
51 | double _dump_fps{24.};
52 |
53 | private:
54 | void _run_display(const compute::Shader2D, float, float4> &shader) noexcept;
55 | void _run_dump(const compute::Shader2D, float, float4> &shader) noexcept;
56 |
57 | public:
58 | ShaderToy(int argc, const char *const *argv) noexcept;
59 | void run(const MainShader &shader) noexcept;
60 | [[nodiscard]] auto &device() noexcept { return *_device; }
61 | [[nodiscard]] auto &stream() noexcept { return _stream; }
62 | [[nodiscard]] auto size() const noexcept { return _size; }
63 | };
64 |
65 | }// namespace luisa::gui
66 |
--------------------------------------------------------------------------------
/src/gui/window.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/13.
3 | //
4 |
5 | #include
6 |
7 | #include
8 | #include
9 | #include
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | namespace luisa::gui {
16 |
17 | Window::Window(std::string_view title, uint32_t width, uint32_t height) noexcept
18 | : _time_start{glfwGetTime()} {
19 |
20 | static std::once_flag once_flag;
21 | std::call_once(once_flag, [] {
22 | glfwSetErrorCallback([](int error, const char *description) noexcept {
23 | LUISA_ERROR_WITH_LOCATION("GLFW Error {}: {}.", error, description);
24 | });
25 | if (!glfwInit()) { LUISA_ERROR_WITH_LOCATION("Failed to initialize GLFW."); }
26 | });
27 |
28 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
29 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
30 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
31 | glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
32 | glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
33 | _handle = glfwCreateWindow(static_cast(width), static_cast(height),
34 | std::string{title}.c_str(), nullptr, nullptr);
35 | if (_handle == nullptr) {
36 | LUISA_ERROR_WITH_LOCATION("Failed to create window '{}' with size {}x{}.", title, width, height);
37 | }
38 |
39 | glfwMakeContextCurrent(_handle);
40 | glfwSwapInterval(0);
41 |
42 | if (gladLoadGLLoader(reinterpret_cast(glfwGetProcAddress)) == 0) {
43 | LUISA_ERROR_WITH_LOCATION("Failed to initialize OpenGL loader.");
44 | }
45 |
46 | // Setup Dear ImGui context
47 | IMGUI_CHECKVERSION();
48 | ImGui::SetCurrentContext(nullptr);
49 | _context = ImGui::CreateContext();
50 | ImGui::StyleColorsLight();
51 | ImGui_ImplGlfw_InitForOpenGL(_handle);
52 | ImGui_ImplOpenGL3_Init("#version 150");
53 | ImGui_ImplOpenGL3_CreateDeviceObjects();
54 | ImGui::SetCurrentContext(nullptr);
55 | }
56 |
57 | void Window::_begin_frame() noexcept {
58 | glfwMakeContextCurrent(_handle);
59 | ImGui::SetCurrentContext(_context);
60 | glfwPollEvents();
61 | ImGui_ImplOpenGL3_NewFrame();
62 | ImGui_ImplGlfw_NewFrame(_handle);
63 | ImGui::NewFrame();
64 | int display_w, display_h;
65 | glfwGetFramebufferSize(_handle, &display_w, &display_h);
66 | glViewport(0, 0, display_w, display_h);
67 | glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
68 | glClear(GL_COLOR_BUFFER_BIT);
69 | }
70 |
71 | void Window::_end_frame() noexcept {
72 | ImGui::Render();
73 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
74 | glfwSwapBuffers(_handle);
75 | ImGui::SetCurrentContext(nullptr);
76 | glfwMakeContextCurrent(nullptr);
77 | }
78 |
79 | Window::~Window() noexcept { _destroy(); }
80 |
81 | bool Window::should_close() const noexcept {
82 | return _handle == nullptr || glfwWindowShouldClose(_handle);
83 | }
84 |
85 | void Window::notify_close() noexcept {
86 | if (_handle != nullptr) { glfwSetWindowShouldClose(_handle, true); }
87 | }
88 |
89 | bool Window::key_down(Key key) const noexcept {
90 | return glfwGetKey(_handle, static_cast(key)) == GLFW_PRESS;
91 | }
92 |
93 | bool Window::mouse_down(Mouse button) const noexcept {
94 | return glfwGetMouseButton(_handle, static_cast(button)) == GLFW_PRESS;
95 | }
96 |
97 | bool Window::key_up(Key key) const noexcept {
98 | return glfwGetKey(_handle, static_cast(key)) == GLFW_RELEASE;
99 | }
100 |
101 | bool Window::mouse_up(Mouse button) const noexcept {
102 | return glfwGetMouseButton(_handle, static_cast(button)) == GLFW_RELEASE;
103 | }
104 |
105 | float2 Window::cursor() const noexcept {
106 | auto x = 0.0;
107 | auto y = 0.0;
108 | glfwGetCursorPos(_handle, &x, &y);
109 | auto window_size = size();
110 | return {std::clamp(static_cast(x), 0.0f, static_cast(window_size.x)),
111 | std::clamp(static_cast(y), 0.0f, static_cast(window_size.y))};
112 | }
113 |
114 | void Window::_destroy() noexcept {
115 | if (_context != nullptr) {
116 | ImGui::SetCurrentContext(_context);
117 | ImGui_ImplOpenGL3_Shutdown();
118 | ImGui_ImplGlfw_Shutdown(_handle);
119 | ImGui::DestroyContext(_context);
120 | ImGui::SetCurrentContext(nullptr);
121 | }
122 | if (_handle != nullptr) {
123 | glfwDestroyWindow(_handle);
124 | }
125 | _context = nullptr;
126 | _handle = nullptr;
127 | }
128 |
129 | Window &Window::operator=(Window &&rhs) noexcept {
130 | if (&rhs != this) {
131 | _destroy();
132 | _time_start = rhs._time_start;
133 | _handle = rhs._handle;
134 | _context = rhs._context;
135 | rhs._handle = nullptr;
136 | rhs._context = nullptr;
137 | }
138 | return *this;
139 | }
140 |
141 | Window::Window(Window &&another) noexcept
142 | : _time_start{another._time_start},
143 | _handle{another._handle},
144 | _context{another._context} {
145 | another._handle = nullptr;
146 | another._context = nullptr;
147 | }
148 |
149 | uint2 Window::size() const noexcept {
150 | auto w = 0;
151 | auto h = 0;
152 | glfwGetWindowSize(_handle, &w, &h);
153 | return make_uint2(w, h);
154 | }
155 |
156 | uint2 Window::framebuffer_size() const noexcept {
157 | auto w = 0;
158 | auto h = 0;
159 | glfwGetFramebufferSize(_handle, &w, &h);
160 | return make_uint2(w, h);
161 | }
162 |
163 | float Window::time() const noexcept {
164 | return static_cast(glfwGetTime() - _time_start);
165 | }
166 |
167 | }// namespace luisa::gui
168 |
--------------------------------------------------------------------------------
/src/gui/window.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Mike Smith on 2021/6/13.
3 | //
4 |
5 | #pragma once
6 |
7 | #include
8 | #include
9 |
10 | #include
11 |
12 | #include
13 | #include
14 | #include
15 |
16 | namespace luisa::gui {
17 |
18 | class Window : concepts::Noncopyable {
19 |
20 | public:
21 | using Handle = struct GLFWwindow *;
22 |
23 | private:
24 | double _time_start;
25 | Handle _handle{nullptr};
26 | ImGuiContext *_context{nullptr};
27 |
28 | private:
29 | void _begin_frame() noexcept;
30 | void _end_frame() noexcept;
31 | void _destroy() noexcept;
32 |
33 | public:
34 | Window(std::string_view title, uint32_t width, uint32_t height) noexcept;
35 | Window(std::string_view title, uint2 size) noexcept : Window{title, size.x, size.y} {}
36 | ~Window() noexcept;
37 |
38 | Window(Window &&another) noexcept;
39 | Window &operator=(Window &&rhs) noexcept;
40 |
41 | [[nodiscard]] bool should_close() const noexcept;
42 | void notify_close() noexcept;
43 |
44 | template, int> = 0>
45 | void with_frame(Frame &&frame) {
46 | if (!should_close()) {
47 | _begin_frame();
48 | frame();
49 | _end_frame();
50 | } else {
51 | _destroy();
52 | }
53 | }
54 |
55 | template, int> = 0>
56 | void run(Frame &&frame) {
57 | while (!should_close()) {
58 | _begin_frame();
59 | frame();
60 | _end_frame();
61 | }
62 | _destroy();
63 | }
64 |
65 | [[nodiscard]] bool key_down(Key key) const noexcept;
66 | [[nodiscard]] bool key_up(Key key) const noexcept;
67 | [[nodiscard]] bool mouse_down(Mouse button) const noexcept;
68 | [[nodiscard]] bool mouse_up(Mouse button) const noexcept;
69 | [[nodiscard]] float2 cursor() const noexcept;
70 | [[nodiscard]] uint2 size() const noexcept;
71 | [[nodiscard]] uint2 framebuffer_size() const noexcept;
72 | [[nodiscard]] float time() const noexcept;
73 | };
74 |
75 | }// namespace luisa::gui
76 |
--------------------------------------------------------------------------------
/tools/record.py:
--------------------------------------------------------------------------------
1 | from sys import argv
2 | from os import listdir, system
3 | from os.path import dirname, abspath
4 |
5 |
6 | if __name__ == "__main__":
7 | exe_dir = argv[1]
8 | script_dir = f"{dirname(abspath(__file__))}"
9 | apps = [f[:-4] for f in listdir(f"{script_dir}/../src/apps") if f.endswith(".cpp")]
10 | print(apps)
11 | for app in apps:
12 | print(f"Recording {app}")
13 | system(f"{exe_dir}/{app} -o {script_dir}/{app}.mp4 -t 0.033333 --size 1280x720 --fps 30 -n 300 -b metal")
14 |
--------------------------------------------------------------------------------